Skip to content

JSON output schemas

mxr’s CLI JSON is the automation contract. Human table output can change; json, jsonl, csv, and ids are the surfaces to script.

The CLI does not always mirror daemon IPC structs. Some commands intentionally emit smaller records that are easier to pipe.

mxr search QUERY --format json returns an array. --format jsonl returns the same records, one per line.

[
{
"message_id": "01JFQ7K3M2X8N5R0VYZA9CTBPE",
"from": "Sarah Chen <sarah@example.com>",
"subject": "1:1 prep, Friday",
"date": "2026-04-30T15:42:11+00:00",
"read": false,
"starred": true,
"score": 12.4
}
]
FieldTypeNotes
message_idstringPass to mxr cat, mxr reply, mutations, etc.
fromstringDisplay-ready sender, usually Name <email>.
subjectstringEmpty subjects are possible.
datestringRFC 3339 timestamp.
readboolCurrent local read state.
starredboolCurrent local starred state.
scorenumberSearch relevance score. Date-sorted queries still include it.

With --explain, mxr search wraps the payload:

{
"results": [/* search result */],
"explain": { /* search-mode diagnostics */ }
}

mxr cat, mxr thread, mxr headers, and mxr export --format json return fuller daemon payloads because they are read surfaces, not compact search rows. Prefer mxr search --format ids when you only need IDs.

Terminal window
mxr search 'from:sarah after:2026-04-23' --format ids \
| mxr archive --dry-run

--format ids prints one ID per line. Mutations with omitted positional IDs read that form from stdin.

Terminal window
mxr search 'label:newsletters older_than:30d' --format ids \
| mxr archive --dry-run

This is safer and more portable than xargs -r on macOS.

Bulk mutation dry-runs return a preview object:

{
"action": "archive",
"dry_run": true,
"requested": 2,
"message_ids": ["01JFQ...", "01JFR..."],
"messages": [
{
"message_id": "01JFQ...",
"from": "Alice",
"subject": "Quarterly review"
}
]
}

--format jsonl emits one preview line per message:

{"action":"archive","dry_run":true,"message_id":"01JFQ...","from":"Alice","subject":"Quarterly review"}

Batch mutations return a summary object:

{
"action": "archive",
"dry_run": false,
"requested": 2,
"succeeded": 2,
"failed": 0,
"message_ids": ["01JFQ...", "01JFR..."],
"errors": []
}

Single-message mutation commands can return a command-specific result payload, but the stable fields are action, dry_run, and message_ids.

Terminal window
# Senders by volume from compact search rows
mxr search 'newer_than:7d' --format json \
| jq -r 'group_by(.from)
| map({sender: .[0].from, count: length})
| sort_by(-.count) | .[]
| "\(.count)\t\(.sender)"'
# Subjects from a sender
mxr search 'from:legal@' --format jsonl \
| jq -r '.subject'
# IDs from attachment-bearing matches
mxr search 'has:attachment older_than:30d' --format ids