The chronological story of a case — every activity, every event, every upload — merged into one view, sorted newest-first, grouped by recency. The reference an attorney pulls up before a deposition, before trial, and when the client asks “what’s been happening on my case?”
At the prompt:
aaicase> timeline on Doe
Or by case ID:
aaicase> timeline on case [CASE-ID]
About thirty seconds later you have a single chronological view of the case’s entire history: phone calls logged, letters sent and received, hearings held, QMEs received, subpoenas served, every upload attached to an activity. Sorted newest-first — what’s current is at the top.
The timeline is the read-only counterpart to audit. Audit reads documents and finds money; timeline reads the chronology and tells the story. You run timeline before a deposition when you need to walk through what happened; you run audit when you need to know what’s broken.
If you give it a name, the skill resolves to a case ID first via merus-search. Then two fetches:
/activities/index/[CASE-ID] → ALL activities on the case (path param, not the global slice)
/events/index/[CASE-ID] → ALL events on the case
The path-param form is critical — /activities/index alone returns only the most recent ~2,700 activities across the whole firm, which on a long-running case will miss anything older than a few months. Passing the case ID as a path segment unlocks the full per-case history.
Both responses are parsed in-memory, merged into a single stream, sorted by timestamp descending, then formatted for output. No temp directory, no second LLM pass, no string-matching.
reference/api-reference.md, not by guessing.
The relevant field map, documented and stable:
| Field | Meaning |
|---|---|
"0" | activity_type_id (number) |
"1" | activity_type_label (e.g. “Phone Call”, “Letter Received”) |
"2" | description (HTML — tags stripped before display) |
"3" | user_id (staff member who created the activity) |
"4" | activity_date (UNIX seconds — the date to sort by) |
"5" | created (UNIX seconds — row insertion time) |
"6" | upload_id (number, or 0 if no attachment) |
"7" | filename (when an upload is attached) |
Field "4" is the sort key, with created as a fallback in case a row has a missing "4" (older Merus rows). The skill never tries to “discover” the schema at runtime — that would mean asking Claude to inspect a sample row, which on a case with 800 activities is wasted budget and a slower response. The schema is fixed; the skill knows it.
Activities and events live in separate Merus tables but tell parts of the same story. A scheduled hearing is an Event (it appears on the calendar). The notes about the hearing are an Activity (they document what happened). Pulling only activities misses the “hearing is scheduled for next Tuesday” entry; pulling only events misses the notes about what was discussed.
The timeline pulls both, tags each row with its source type, and interleaves them in the single sorted view. Events get the EVENT prefix and the event type label (Hearing, QME, MSC); activities use the activity type label. The attorney sees one chronology with both sources clearly distinguishable.
Output is grouped by how recent each row is, with the boundaries adapting to case size:
| Case size | Grouping |
|---|---|
| Under 10 rows | One flat section (no headers needed) |
| 10–50 rows | Last 30 days / Last 90 days / Older |
| Over 50 rows | By year/month (2026-05 / 2026-04 / 2026-03 / …) |
The thresholds are deliberate. A long-running case with 600 activities is overwhelming as a flat list; grouping by month restores readability. A new case with 8 entries doesn’t benefit from grouping — the section headers would be most of the output.
All Merus timestamps are UNIX seconds (UTC). The timeline converts each timestamp through new Date(ts * 1000) and renders to YYYY-MM-DD using .toLocaleDateString('en-CA'). The en-CA locale gives the YYYY-MM-DD format; the locale flag also anchors to the user’s local timezone. The user sees activities on the date they happened in the user’s office, not on the UTC date Merus stored them under.
The reason this matters: an activity timestamped at 5:00 PM Pacific (2026-05-04 17:00 PT) is 2026-05-05 00:00 UTC. Naive UTC slicing (toISOString().slice(0,10)) would show this activity dated 2026-05-05 in the user’s timeline — one day AHEAD of when the attorney actually worked on it. That’s confusing when the attorney remembers “we did that yesterday afternoon.” The skill anchors to local time so a 5:00 PM Pacific activity shows as 2026-05-04, matching the attorney’s lived experience.
The same locale-anchored YYYY-MM-DD rendering is used across activity-display skills (timeline, health-check recent-activity, prep-hearing event windows). Consistent format, consistent timezone.
If field "6" (upload_id) is non-zero, the timeline shows a paperclip icon and the filename:
2026-03-15 QME Report Dr. Sample ortho — 12% WPI lumbar [📎 qme.pdf]
The filename comes from field "7". If field "7" is empty but the upload exists, the icon still renders with a generic upload label so the attorney knows there’s a document attached even if the description doesn’t name it.
The timeline does not read the attached PDFs — that’s audit’s job. Timeline is the index; audit is the content read.
TIMELINE — Doe, Jane v. Sample Container Inc (Case #[FILE-#])
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Last 30 days
2026-05-04 Phone Call CLIENT CALL — confirming hearing prep
2026-04-30 EVENT [Hearing] Status conference, Anaheim WCAB Dept 4
2026-04-28 Letter Received Defense response to TD demand [📎 def-resp.pdf]
2026-04-21 Hearing ✓ Status conference — continued to 6/15
Last 90 days
2026-03-15 QME Report Dr. Sample ortho — 12% WPI lumbar [📎 qme.pdf]
2026-03-02 Letter Sent TD demand to Sample Insurance [📎 td-dmd.pdf]
2026-02-28 Subpoena Served SDT to medical provider for records
2026-02-14 EVENT [QME] QME with Dr. Sample, Anaheim
2026-02-05 Application Filed Original ADJ filing — [ADJ-#]
Older
2025-11-12 Intake New case opened — DOI 2025-10-15
2025-10-15 EVENT [DOI] Date of injury
158 total entries on this case
| Timeline | Audit | |
|---|---|---|
| Time | ~4 minutes | ~4 minutes |
| Reads | Activity + event metadata | Pages 1–5 of every PDF on the case |
| Finds | What happened, in order | What’s wrong, what’s owed, what’s misfiled |
| Writes back | Nothing | Case summary, action tasks |
| Use case | Pre-depo prep, client call, narrative review | Pre-trial workup, case takeover, large settlement push |
The relationship: timeline tells you what to ask audit to look at more carefully. “The QME report came in on 3/15. Was there an objection?” The timeline shows you the report; the audit reads the document and tells you whether the response was timely.
The skill used /activities/index without the case-ID path param — that returns the global slice (~2,700 recent across the firm), which on an older case misses everything pre-window. Use the case ID directly (timeline on case [CASE-ID]) to force the per-case endpoint.
If you’re looking at the same activity in the Merus UI and seeing a different date, the difference is timezone — Merus UI and the timeline both show local time, but the user’s local time and the Merus server’s local time can disagree if they’re in different timezones (rare but possible at multi-office firms). For a single document where the date is dispositive (deposition exhibit prep), confirm against the underlying record.
Most common cause: it was never logged. The Merus UI sometimes accepts data entered into the wrong place (an “event” note left blank in the notes field, a phone call recorded as a contact edit rather than an activity). The timeline only shows what’s in /activities and /events — if a piece of work happened but wasn’t recorded, it doesn’t exist for the system.
Activity descriptions are HTML in the raw data. The skill strips tags before display. If you see raw <p> in the output, the stripping regex missed a malformed tag — report it and the regex will be tightened.
The upload exists in Merus but might be on a different case if it was reassigned. Use read upload [id] with the upload ID to fetch it directly, or run audit case to verify all uploads on this case are correctly attached.
Part of AAI for MerusCase — code-guarded AI case intelligence for California Workers’ Comp attorneys.