mxr Development
SkillSearchUse when changing mxr source, architecture, docs, tests, IPC, daemon handlers, store/search/sync/semantic behavior, provider adapters, TUI/web clients, release flow, or repo-level development process.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the mxr Development skill
What this skill tells your AI
The instructions your AI receives, as published by planetaryescape/mxr in .agents/skills/mxr-development/SKILL.md and read by ahel’s review.
This skill holds the context that used to bloat always-on agent files. Load it only for source/docs/process work.
Product shape
- Local-first: SQLite is canonical, search indexes are rebuildable, and core mail works offline.
- Daemon-backed: TUI, CLI, web, and scripts are clients over Unix-socket IPC.
- CLI-first: new capabilities land in CLI at the same time as daemon support, with stable JSON/JSONL.
- Client parity: a user-facing daemon capability is incomplete until CLI, TUI, web, and MCP expose it. Interaction design may differ; capability may not silently disappear in one client.
- Provider-agnostic core: Gmail/IMAP/SMTP/Outlook behavior maps into the internal model in adapters.
- Compose uses
$EDITORwith YAML frontmatter plus markdown body. - Reader mode is plain text first; no inline images in the terminal rendering path.
Build and verify loop
For feature work:
- Implement in the narrowest crate surface.
- Run
scripts/cargo-test -p <crate> --tests. - Run
cargo build -p mxr. - Restart stale daemons:
pkill -f 'mxr daemon' 2>/dev/null, thencargo run --bin mxr -- daemon --foreground. - Drive the feature through the CLI, preferably with
--format json. - Inspect daemon state with
mxr events,mxr logs,mxr doctor, andmxr activity. - Query persisted state back through the CLI, such as
mxr search ... --format json.
If the daemon will not start, check cargo build -p mxr, pgrep -af 'mxr|cargo', mxr daemon --foreground, and stale socket files.
Client and mutation contract
- TUI and CLI must use the same daemon request; avoid client-only capabilities.
- Every reusable daemon capability needs a CLI surface. TUI/web support should layer on it.
- Destructive or batch mutations need a dry-run/preview path before commit.
- Dry-run selection/query logic must match the real mutation path.
- Read/list/status/search/export surfaces must keep structured output pipeable.
Crate boundaries
coredepends on no internal crates.protocoldepends only oncore.- Provider crates depend on
coreplus shared mail utility crates such asmail-parseandoutbound. storeandsearchdepend only oncore.semanticowns embeddings/dense retrieval and must not depend on daemon, TUI, or provider crates.llmowns provider clients and prompt/result DTOs; higher layers pass plain data in.relationshipmay depend oncore,store,reader, andllm; not protocol/daemon/client/sync/search/semantic/provider crates.safetymay depend oncore,reader, andrelationship; not store/protocol/daemon/clients/sync/search/semantic/provider crates.syncdepends oncore,store, andsearch.daemonis the integration point, but talks to providers only throughMailSyncProviderandMailSendProvider.tuiandwebare clients; they must not depend on daemon, store, search, sync, semantic, or provider crates.- Use Cargo dependencies for architecture seams, never
#[path].
See docs/blueprint/01-architecture.md for longer rationale.
Domain invariants
- Semantic search is optional platform behavior layered above core mail runtime.
- Sync stores envelopes/bodies and commits lexical search before a sync batch finishes.
- Semantic chunks may be persisted during sync, but embeddings/ANN refresh only happen when semantic is enabled or explicitly reindexed.
- Hybrid search keeps BM25 exactness and adds dense recall with RRF.
- Activity log rows are local-only personal data. Never sync or transmit them, never store credentials/full bodies/attachment bytes, and write only through
state.activity.record(...). INSERT OR REPLACEcan triggerON DELETE CASCADE; preferINSERT ... ON CONFLICT UPDATEfor parent rows with dependents.mxr reset --hard/mxr burnwipe runtime state only by default; preserve config and credentials unless explicitly requested.
Release shorthand
If the user says ship it, run the full release flow:
- Commit release-ready changes.
- If the version/tag exists, bump first; never overwrite tags or GitHub releases.
- Push
main. - Create and push
v{version}. - Wait for the tag-driven release workflow.
- Verify all three install channels, in throwaway locations so they never collide with the real install:
- Homebrew:
brew update && brew upgrade mxr(the real install on this machine);mxr versionmust report the new release. - install.sh:
MXR_INSTALL_DIR="$(mktemp -d)" ./install.sh v{version}, run<tmp>/mxr version, thenrm -rfthe temp dir. - cargo:
cargo install --git https://github.com/planetaryescape/mxr --tag v{version} --locked --root "$(mktemp -d)" mxr, run<tmp>/bin/mxr version, thenrm -rfthe temp root.
- Homebrew:
- Converge this machine on Homebrew only. After verification, the sole
mxron PATH must be Homebrew's: remove any~/.cargo/bin/mxr(cargo uninstall mxr) and any~/.local/bin/mxrleft by past install.sh runs, then confirm withwhich -a mxr. Multiple mxr binaries on PATH carry different build ids, and every invocation restarts the daemon to "match the current binary" — ping-ponging the daemon between versions.
Source of truth: docs/blueprint/17-release-pipeline.md and checked-in GitHub workflows.
Useful docs
docs/blueprint/- requirements, architecture, decisions.docs/blueprint/15-decision-log.md- settled decisions.docs/activity-log.md- activity table lifecycle and privacy rules.docs/implementation-journey.md- historical context and superseded plans.
Signals
- GitHub stars
- 72
- Forks
- 8
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
mxr-development- Source
- github.com/planetaryescape/mxr