Browse your activity log
mxr keeps a local, append-only record of every action you take across the TUI, CLI, and web. Browse the last hour, last week, or any custom range. Filter by what, where, when. Tombstone anything you want gone.
Email clients don’t ship this. Gmail logs IPs for compliance admins. mxr logs intent — for you, on your machine, never anywhere else.
What gets captured
Section titled “What gets captured”State-changing or intent-expressing actions:
- Mail:
mail.read,mail.archive,mail.trash,mail.star,mail.label,mail.move,mail.snooze,mail.unsubscribe,mail.mark_spam. - Send:
mail.send,mail.reply,mail.forward,draft.create,draft.discard, scheduled sends. - Search:
search.run,search.save,search.delete,saved.open. - Threads:
thread.open,thread.summarize,thread.flag_reply_later. - Accounts:
account.add,account.remove,account.signin,account.sync. - Rules:
rule.create,rule.update,rule.delete,rule.run,rule.test. - Snippets / signatures / screener / reminders: edits and triage decisions.
Mapping is closed: every IPC verb that produces activity has an explicit entry in crates/daemon/src/activity/mapper.rs. New IPC verbs default to “no activity” until someone decides what to log.
# Show the last day of activity in a tablemxr activity list --since 24hWhat you get: reverse-chronological table with TIME / SRC / ACTION / TARGET / CONTEXT columns. Source badges (tui/cli/web/daemon) make it obvious where each action originated.
What it does NOT capture
Section titled “What it does NOT capture”- Cursor moves, scroll, pane focus, palette opens-then-cancelled.
- Heartbeats, pings, status polls, background sync, FTS rebuilds.
- Read-side getters (
mxr cat, listing envelopes) — they don’t change state. - Anything when
MXR_ACTIVITY=offis set or recording is paused.
Filter to the slice you care about
Section titled “Filter to the slice you care about”Shared filter flags apply to list, stats, top, export, and redact. AND-combined; empty means any.
# Last week of mail mutations, JSON for pipingmxr activity list --since 7d --prefix mail. --limit 100 --format json
# Searches you ran for "invoice"mxr activity list --action search.run --query 'invoice'
# Activity on a specific threadmxr activity list --target-kind thread --target-id thr_abc123What you get: each command emits the matching rows; --format json produces { entries: [...], next_cursor: { ts, id } | null } for paging.
See yesterday at a glance
Section titled “See yesterday at a glance”Aggregate over a window to see what you actually did.
# Top actions over the last weekmxr activity top --since 7d --limit 10
# Hour-of-day histogram for the last monthmxr activity stats --group-by hour --since 30d --format json | jq
# Daily rollupmxr activity stats --group-by day --since 30dWhat you get: KEY / COUNT table in human mode, { buckets: [...] } in JSON mode.
Replay a session as prose
Section titled “Replay a session as prose”replay aggregates consecutive same-action rows into readable lines.
mxr activity replay --since 1hWhat you get:
Since 1h: 09:42 Read 5 threads 09:43 Searched "invoice 2026" 09:44 Archived 12 threads 09:46 Sent 1 messageTime travel by natural-language phrase
Section titled “Time travel by natural-language phrase”recall resolves a curated set of fuzzy-time phrases.
mxr activity recall "yesterday afternoon"mxr activity recall "last hour"mxr activity recall "before lunch" --limit 20Accepted phrases: today, yesterday, this morning/afternoon/evening, lunch, breakfast, night, last <duration>, past <duration>, before|after|since|until <phrase>. Anything else returns an error pointing at the supported grammar.
Export your data
Section titled “Export your data”# CSV → stdoutmxr activity export --format csv > today.csv
# NDJSON → file (preferred for piping into jq/awk)mxr activity export --format ndjson --out my-week.ndjson
# Filter first, export only the slicemxr activity export --prefix mail. --since 7d --format ndjson --out mail-week.ndjsonWhat you get: the daemon writes the file with the matching rows in the requested format. CSV is RFC 4180. NDJSON is one ActivityEntry per line. JSON is a top-level pretty-printed array.
Scrub what you don’t want kept
Section titled “Scrub what you don’t want kept”Three layers, from most permanent to most temporary.
Hard kill (env var)
Section titled “Hard kill (env var)”MXR_ACTIVITY=off mxr daemonThe recorder is spawned but every record() call is a no-op for the lifetime of the daemon.
Soft pause (runtime)
Section titled “Soft pause (runtime)”# Stop recording for 2 hours; auto-resumesmxr activity pause --for 2h
# Indefinite — stays paused until `resume`mxr activity pause
# Bring it backmxr activity resumePause writes one activity.paused marker, then drops new writes until the window elapses or you resume. Auto-resume also writes a synthesized activity.resumed marker so you can always see when the gap began and ended.
Tombstone after the fact
Section titled “Tombstone after the fact”Always dry-run first. Tombstones are irreversible (the audit-trail columns survive but context_json is cleared).
# Preview what would be tombstonedmxr activity clear --last 1h --dry-run
# Tombstone the last hour (preserves important-tier rows by default)mxr activity clear --last 1h --yes
# Nuke everything, including important rowsmxr activity clear --last all --include-important --yes
# Surgical: tombstone two specific rowsmxr activity redact --ids 42,43 --yes
# Retention prune (hard delete, not tombstone)mxr activity prune --before 90d --dry-runmxr activity prune --before 90d --yesSave filters you use a lot
Section titled “Save filters you use a lot”Saved activity filters mirror saved searches.
# Save the current filter under a slugmxr activity saved save mail-week --name "Mail this week" --since 7d --prefix mail.
# Run a saved filtermxr activity saved open mail-week
# Managemxr activity saved listmxr activity saved delete mail-weekRecipes
Section titled “Recipes”What was I doing right before that bug?
Section titled “What was I doing right before that bug?”mxr activity replay --since 30mQuick prose narrative of the last half-hour. Catches you up after a context switch.
Which threads did I archive without reading?
Section titled “Which threads did I archive without reading?”mxr activity list --since 7d --action mail.archive --format json \ | jq -r '.entries[] | select(.context.read_then_archive != true) | .target_id'What you get: thread IDs you archived without the read_then_archive flag — candidates for unarchive if you went too fast.
Surface my most-searched terms this month
Section titled “Surface my most-searched terms this month”mxr activity list --since 30d --action search.run --format json \ | jq -r '.entries[].context.query' \ | sort | uniq -c | sort -nr | head -20What you get: top-20 queries you ran in the last 30 days, ranked.
Audit what mxr did the last time it crashed
Section titled “Audit what mxr did the last time it crashed”mxr activity list --since 24h --include-redacted --format json \ | jq -r '.entries[] | select(.action | startswith("activity.")) | "\(.ts)\t\(.action)\t\(.context)"'What you get: synthesized markers (activity.paused, .resumed, .pruned, .redacted, .exported, .cleared) — the daemon’s diary about itself.
Agent prompts that work
Section titled “Agent prompts that work”"Use `mxr activity list --since 24h --format json` to summarise what I didin the last day, then suggest one filter I should save with`mxr activity saved save`. Don't run any mutating commands. If you findsensitive context, propose a `mxr activity redact --ids ... --dry-run`without executing it.""Run `mxr activity replay --since 4h` and paste the output. Then run`mxr activity stats --group-by hour --since 7d` and tell me my peakinbox-processing hour."Surfaces
Section titled “Surfaces”- CLI:
mxr activity ...(aliasmxr act). Scripts use--format json|ndjson. - TUI: press
g afrom any screen to open the activity modal.j/kto navigate,pto toggle pause,Escto close. Also visible inside the Diagnostics page (G d) as the Activity pane. - Web: navigate to
/activityin the web app, or open the Diagnostics page and switch to the Activity tab. Filter sidebar, bulk-select with checkboxes, pause/resume from the top bar.
Storage and retention
Section titled “Storage and retention”Three tiers with separate retention windows. Configure in the file printed by mxr config path:
[activity]enabled = truetrack_link_clicks = false # opt-in; URLs reveal a lottrack_subjects = truetrack_recipient_handles = truetrack_search_queries = true
[activity.retention]ephemeral_days = 30 # views, palette opens, navigationstandard_days = 90 # searches, thread opens, attachment viewsimportant_days = 365 # mail mutations, sends, account changesA daily prune sweep hard-deletes rows older than the cutoffs. Each deletion writes one activity.pruned marker so you can audit what was removed.
Forbidden in context_json
Section titled “Forbidden in context_json”The recorder refuses to store credential material:
- OAuth/refresh tokens, password hashes, API keys, session ids.
- Attachment bytes (filenames + sizes only).
- Full mail bodies (subjects + first-80-char draft prefixes only, truncated).
A PII-audit test asserts the table never contains the forbidden keys after a full mapper run.
Limits today
Section titled “Limits today”- No encryption at rest. Relies on OS-level disk encryption (FileVault, LUKS).
- No cross-device sync. By design.
- The TUI modal is read-only in v1 (browse + pause). Redaction and export currently flow through the CLI; the web surface has bulk-redact via the data table.
See also
Section titled “See also”- Security & Privacy — the broader local-first guarantees mxr makes.
- Diagnose mxr fast — the page that hosts the Activity tab alongside Logs and Events.
mxr activityCLI reference — full flag inventory, auto-generated from--help.[activity]config keys — defaults and toggles.