The instant unprocessed-mail count. One API fetch, an orphan filter, a number. Under five seconds. No AI, no PDF reads, no downloads. The question is “did any documents land in the inbox that aren’t filed yet?” — the skill answers in one line.
At the prompt:
aaicase> any new mail
aaicase> check my mail
aaicase> mail status
aaicase> what mail came in
The skill fetches the firm’s uploads index, filters to orphans (uploads not yet attached to a case or activity), groups them by date, and prints the list. If nothing’s unprocessed, it says so and stops. If something is, the last line says: “Say process mail to download, identify, and file these.”
It’s the polling skill — quick, repeatable, ambient. Run it whenever you wonder; if the answer is “nothing,” you saved yourself a process-mail run; if it’s “7 items,” you know what’s waiting and can decide when to handle it.
One API call:
node bin/merus-fetch.mjs /uploads/index
The response is the global uploads index. The skill filters client-side for orphans, groups by date extracted from the filename, and prints. No temp directory, no PDF downloads, no second API call. Bounded by the round-trip time to api.meruscase.com — usually 2–4 seconds.
The contract: under 5 seconds, no AI. If the run ever takes longer, that’s a Merus latency issue, not an AAI logic issue — the JavaScript filter on the client side runs in milliseconds.
An upload is an “orphan” (unprocessed) when both of these are true:
case_file_id is falsy — null, 0, or the string "0"activity_id is falsy — null, 0, or the string "0"The two-condition check matters because uploads can be in interesting in-between states:
| case_file_id | activity_id | Status |
|---|---|---|
| null | null | Orphan — not filed anywhere. Counts as new mail. |
| 123 | null | Attached to case 123 but no activity record. Rare; not counted as new mail. |
| null | 456 | Linked to an activity but the activity isn’t on a case (or it’s an orphan activity). Not counted. |
| 123 | 456 | Properly filed. Not counted. |
The strict both-fields-falsy rule keeps the skill from over-reporting. An upload that’s already partially filed (case attached, no activity) shouldn’t show up as “new mail” — the attorney handled it; the activity link is a separate cleanup. Same for upload-attached-to-activity-but-no-case — that’s a different category of broken state, not new mail.
Any-new-mail tells you how many. Process-mail tells you what. The two are sequential: poll with any-new-mail; if there’s something to do, run process-mail.
The contract is the same as status and check my email — the “instant” tier of AAI’s skills. Pure deterministic counts, no inference, no LLM tokens spent.
The output groups orphans by the date extracted from their filename. The convention at most firms is YYYY-MM-DD-... or MM-DD-YYYY-...; the skill matches against the latter (since that’s the dominant historic pattern). For uploads without a date in the filename, they group under “Unknown date.”
The grouping is small but useful: if a batch of mail came in from a copy service yesterday, all the related uploads cluster under one date heading. The attorney sees the chronology without having to scan filenames individually.
Each item shows the upload ID and the filename (or description, or “Unknown” if neither is set):
11-06-2025 (3 items):
[UPLOAD-ID-1] | POS AA PANEL STRIKE - GASTRO 11-6-2025.pdf
[UPLOAD-ID-2] | QME REPORT FLEMING 11-06-2025.pdf
[UPLOAD-ID-3] | DA LETTER 11-06-2025.pdf
| any new mail? | process mail | |
|---|---|---|
| Time | Under 5 seconds | ~20 minutes for a typical batch |
| Reads PDFs | No | Yes — every PDF, natively via Claude vision |
| Writes anything | No — read-only | Yes — creates activities, binds uploads, possibly tasks/events |
| Cost | Effectively zero | ~API budget per batch, scaling with document count + sizes |
| Question answered | “Is there anything?” | “What is it and where does it go?” |
Polling pattern: run any-new-mail throughout the day; when it shows non-zero, decide whether to handle the batch now (run process-mail) or batch later (let mail accumulate, run process-mail once at end of day).
| any new mail? | check my email | |
|---|---|---|
| Source | Merus Uploads queue (scanned/uploaded PDFs) | Merus Messages inbox (emails received by the firm address) |
| What counts | Orphan uploads (no case + no activity) | Unfiled emails (no case_file_id, not deleted) |
| Followed by | process mail | process messages |
The two skills are deliberately separate because the underlying data sources are separate. A firm might have plenty of mail and no email, or vice versa. Asking “any new mail?” doesn’t poll email; asking “check my email” doesn’t poll mail.
aaicase> any new mail
7 unprocessed uploads:
11-06-2025 (3 items):
[UPLOAD-ID-1] | POS AA PANEL STRIKE - GASTRO 11-6-2025.pdf
[UPLOAD-ID-2] | QME REPORT FLEMING 11-06-2025.pdf
[UPLOAD-ID-3] | DA LETTER 11-06-2025.pdf
11-07-2025 (2 items):
[UPLOAD-ID-4] | SUBPOENA NONCOMPLIANCE 11-07-2025.pdf
[UPLOAD-ID-5] | UR DECISION SAMPLE 11-07-2025.pdf
Unknown date (2 items):
[UPLOAD-ID-6] | attachment.pdf
[UPLOAD-ID-7] | scan-2026-05-27.pdf
Say "process mail" to download, identify, and file these.
(generated in 2.8s)
And the zero case:
aaicase> any new mail
No unprocessed mail.
(generated in 2.4s)
The mail may already be partially filed (case attached but no activity), which the orphan filter doesn’t count. Or the uploads landed in a way that gave them an immediate activity_id (some Merus integrations attach activities at upload time). Run what changed today to see new uploads regardless of orphan status.
The uploads have been there all along — they’re genuinely unfiled. Run process mail to actually file them, or use the Merus UI to handle them manually. The skill only reports; it doesn’t auto-clear.
The filenames don’t match the MM-DD-YYYY pattern the skill recognizes. Common when uploads come from copy services with their own naming conventions. The list is still correct; the grouping is just less useful.
Network latency to api.meruscase.com. If api.meruscase.com is degraded, every AAI skill that touches it is similarly affected. Check the Merus status page or try again in a few minutes.
The upload record has neither a description nor a filename field populated. Rare but happens with uploads created via certain API paths. Open the upload directly in Merus UI to see what it is, or run read upload [ID] to identify by content.
Part of AAI for MerusCase — code-guarded AI case intelligence for California Workers’ Comp attorneys.