Agent Skills › planetaryescape/mxr › mxr-development

mxr-development

GitHub

mxr项目开发技能,涵盖源码修改、架构设计、测试验证、IPC通信及多客户端(CLI/TUI/Web)功能实现。提供构建验证流程、Crate边界定义及发布规范,指导全栈开发工作。

.agents/skills/mxr-development/SKILL.md planetaryescape/mxr

Trigger Scenarios

修改 mxr 源代码或架构 编写或更新文档 运行测试或调试程序 调整 IPC 或守护进程逻辑 涉及发布流程或仓库级开发过程

Install

npx skills add planetaryescape/mxr --skill mxr-development -g -y
More Options

Non-standard path

npx skills add https://github.com/planetaryescape/mxr/tree/main/.agents/skills/mxr-development -g -y

Use without installing

npx skills use planetaryescape/mxr@mxr-development

指定 Agent (Claude Code)

npx skills add planetaryescape/mxr --skill mxr-development -a claude-code -g -y

安装 repo 全部 skill

npx skills add planetaryescape/mxr --all -g -y

预览 repo 内 skill

npx skills add planetaryescape/mxr --list

SKILL.md

Frontmatter
{
    "name": "mxr-development",
    "description": "Use 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."
}

mxr Development

This skill holds the context that used to bloat always-on agent files. Load it only for source/docs/process work.

Product shape

  • Email modes: the product model is five modes (Messages, To do, Updates, Reading, Archive) plus Now, per docs/blueprint/22-email-modes.md (D107 to D114). Build them in its phase order. A phase ships with the site pages and repo docs its Docs line names, and user docs never describe a mode behaviour before it ships.
  • 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 $EDITOR with 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:

  1. Implement in the narrowest crate surface.
  2. Run scripts/cargo-test -p <crate> --tests.
  3. Run cargo build -p mxr.
  4. Restart only the daemon owned by this worktree or isolated test profile. Verify its PID and runtime paths before stopping it; never stop all mxr daemons on a shared machine. Build in the shared queue, then launch the built binary with daemon --foreground outside the queue.
  5. Drive the feature through the CLI, preferably with --format json.
  6. Inspect daemon state with mxr events, mxr logs, mxr doctor, and mxr activity.
  7. 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

  • core depends on no internal crates.
  • protocol depends only on core.
  • Provider crates depend on core plus shared mail utility crates such as mail-parse and outbound.
  • store and search depend only on core.
  • semantic owns embeddings/dense retrieval and must not depend on daemon, TUI, or provider crates.
  • llm owns provider clients and prompt/result DTOs; higher layers pass plain data in.
  • relationship may depend on core, store, reader, and llm; not protocol/daemon/client/sync/search/semantic/provider crates.
  • safety may depend on core, reader, and relationship; not store/protocol/daemon/clients/sync/search/semantic/provider crates.
  • sync depends on core, store, and search.
  • daemon is the integration point, but talks to providers only through MailSyncProvider and MailSendProvider.
  • tui and web are 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 REPLACE can trigger ON DELETE CASCADE; prefer INSERT ... ON CONFLICT UPDATE for parent rows with dependents.
  • mxr reset --hard / mxr burn wipe runtime state only by default; preserve config and credentials unless explicitly requested.

Local gates vs CI

CI is the workspace gate. scripts/ci_change_scope.sh selects Rust, web, docs and expensive checks from the changed paths. The workflow runs the applicable workspace checks; a docs-only PR does not run the Rust and web suites. Draft PRs also skip the two workspace test jobs and Web E2E until marked ready. Inspect .github/workflows/ci.yml and the final ready-PR checks rather than treating a skipped job as validation. Do not run --workspace clippy, cargo doc --workspace, cargo nextest run --workspace or cargo build --workspace --release on the developer machine. Locally run only what is scoped to the change:

  • scripts/pre-pr-rust-gate (fmt, clippy for touched crates only, boundary script, cargo deny). --list shows the crates it will check; --full is for reproducing a CI failure you cannot narrow to one crate.
  • scripts/cargo-test -p <crate> --tests for the crates you touched.

Then push and read the PR checks. If one is red, reproduce that one failure with -p <crate>, fix, push again.

Open the PR as a draft while iterating. Test (fast / no semantic), Test (semantic-local) and Web E2E skip on draft PR pushes (they still run on every push to main and on workflow_dispatch); every other check still runs on each push, so you still get fast fmt/clippy/type feedback. Each of those three is the most expensive job in the matrix, and re-running the full set on every rebase/fixup push during iteration is most of the Blacksmith bill. Mark the PR ready for review (gh pr ready <N>) once it's genuinely final, which triggers the full suite once before merge; merge once it's green. If a fix is still needed after marking ready, push it and expect one more full run — that's expected and fine, just don't flip ready back and forth to dodge the gate.

Release shorthand

Releases go through release-please. ship it means run the whole chain below, including merging the release PR, so the manifest, Cargo.toml, CHANGELOG.md and tags never drift. Never create, push or move a v* tag by hand; never overwrite a tag or GitHub release. The flow is built so the laptop never rebuilds what CI already built.

  1. Preflight. git fetch origin --tags, then compare .release-please-manifest.json on origin/main with git tag -l 'v*' --sort=-v:refname | head -1. If they disagree, land a PR that sets the manifest to the latest tag's version first. Also check gh pr list --head release-please--branches--main: an open release PR whose version is already tagged is stale; close it and let release-please regenerate it.
  2. Commit release-ready changes on a branch with conventional commits. Run the scoped local gates above, nothing wider. Two separate gates decide whether a release PR appears. First, release-please.yml runs its job only when scripts/release_change_scope.sh finds an artifact-affecting change since the last tag (crates/, apps/web/, real Cargo dependency changes, release workflows/scripts), or when the push is a merged release PR; otherwise the job is skipped. Second, release-please itself only opens a PR for releasable commits: feat: or fix: (pre-1.0 both bump the patch) or a breaking change (feat!: or a BREAKING CHANGE: footer, a minor bump pre-1.0). chore:/docs:/ci: alone do not release.
  3. Push, open the PR, and wait on it: gh pr checks <N> --watch.
  4. Merge with gh pr merge <N> --squash --admin (self-approval is blocked, --admin bypasses only the review).
  5. Wait for the release-please.yml run on the merge commit (gh run list --workflow=release-please.yml --commit <sha>), then for release-please--branches--main to show the new version. If the job was skipped, step 1's conditions were not met. If it failed on "Require release token" or a 401, RELEASE_PLEASE_TOKEN is missing or expired: stop and ask BK to rotate the PAT. Never set that secret from gh auth token. Once the release PR is current and green, merge it with gh pr merge <N> --squash --admin. That merge makes release-please push v{version} with the PAT, which starts the tag-driven release workflow.
  6. Wait for the release workflow on the tag, not for a main run: gh run list --workflow=release.yml --json databaseId,headBranch,status,conclusion and pick the row whose headBranch is v{version}, then gh run watch <id>. If no run exists for the tag, the tag was created without the PAT; re-run on the existing tag with gh workflow run release.yml --ref v{version} rather than re-tagging. release-please has already created the GitHub release as a draft, so nothing is visible or Latest yet. The workflow builds the macOS and Linux binaries (cargo build --release --locked -p mxr from a clean checkout), uploads them to the draft, publishes it as Latest only after every asset is attached, then pushes the Homebrew formula. A run that fails before publication leaves an unpublished draft, not a broken Latest (a re-run on an already published release writes nothing and fails on purpose if its rebuilt checksums differ, so Homebrew is not updated from them): fix and re-run the failed jobs (gh run rerun <id> --failed), see "What a failed release run leaves behind" in the blueprint. gh release view v{version} --json isDraft,assets shows where it is.
  7. Verify on this machine with downloads only; no step here compiles anything:
    • Homebrew (the real install): brew update && brew upgrade mxr; mxr version must report the new release.
    • install.sh: D="$(mktemp -d)"; MXR_INSTALL_DIR="$D/bin" ./install.sh v{version}; "$D/bin/mxr" version; rm -rf "$D". It downloads the release tarball and checks the sha256.
    • cargo channel: covered by step 5. The release workflow's build-binaries job compiled -p mxr --release --locked on this exact tag from a clean checkout, which is the same compile cargo install --git would do. Do not run cargo install --git ... locally: it is a cold release build of the whole workspace and takes every core for 10+ minutes to re-prove a passed CI job.
  8. Converge this machine on Homebrew only. The sole mxr on PATH must be Homebrew's: remove any ~/.cargo/bin/mxr (cargo uninstall mxr) and any ~/.local/bin/mxr left by past install.sh runs, then confirm with which -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.
  9. Report: the version, tag, release URL, release workflow run URL, and each install check's mxr version output. Confirm the manifest on main now equals the new tag.

Source of truth: docs/blueprint/17-release-pipeline.md and the 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.

Version History

  • d1f2b49 Current 2026-10-18 18:36

    新增邮件五模式产品形态说明;优化构建验证循环中的守护进程重启与状态检查逻辑,提升安全性与稳定性。

  • a085c37 2026-09-27 12:44

    优化发布流程:集成 release-please 完整链,增加预检和 stale PR 检查;精简本地 shipping 路径,移除冗余的 CI 重复构建步骤,聚焦作用域门控。

  • 803ee56 2026-08-06 09:01
  • c4ada04 2026-07-30 20:15

Same Skill Collection

.agents/skills/email-standards/SKILL.md
.agents/skills/mxr/SKILL.md
.agents/skills/rust-async-patterns/SKILL.md
.agents/skills/rust-best-practices/SKILL.md
.agents/skills/rust-learner/SKILL.md
.agents/skills/rust-engineer/SKILL.md

Metadata

Files
0
Version
d1f2b49
Hash
5bf9ef8f
Indexed
2026-07-30 20:15

ホーム - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-10-19 20:23
浙ICP备14020137号-1