finalize-apple-mail-mcp
Skill0 starsChanged 4 months agoMITView on GitHub
Final codebase review and doc/manifest sync for apple-mail-mcp after feature work. Starts with plugin-validator to fix manifest and doc drift, then pytest, code-simplifier, CLAUDE.md/README/skills/MCPB sync, a required `dev-check.sh release` artifact rebuild, then commit and push, and — once Cayman approves the merge — merging, signing the release tag, and attaching artifacts to the GitHub Release, because a merged-but-untagged version is not a closed loop. Use when finishing a change, before release, when the user says finalize, sync docs, update manifests, ship the branch, merge to main, tag a release, or cut a release.
- Reads credentials
- Installs packages
- Commits and pushes
In this repository23 other files it gives its agents.
- AGENTS.mdAGENTS.md
- apple-mail-mcpb/CLAUDE.mdCLAUDE.md
- CLAUDE.mdCLAUDE.md
- .claude-plugin/CLAUDE.mdCLAUDE.md
- docs/CLAUDE.mdCLAUDE.md
- tasks/CLAUDE.mdCLAUDE.md
- tests/CLAUDE.mdCLAUDE.md
- tools/CLAUDE.mdCLAUDE.md
- apple-mail-archive-exportSkill
- context-guidance-auditSkill
- cowork-plugin-customizerSkill
- create-cowork-pluginSkill
- find-skillsSkill
- mail-scripting-dictionarySkill
- marketplace-release-handoffSkill
- mcp-builderSkill
- plugin-creatorSkill
- plugin-settingsSkill
- plugin-structureSkill
- python-performance-optimizationSkill
- reviewing-codeSkill
- testing-pythonSkill
- thermo-nuclear-code-quality-reviewSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
14 rules. About 0 are common, 6 are distinctive, and 8 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈6
Distinctive · estimate
This author's own choices. Worth a look.
8
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 8
Run this after implementation is done and before calling the branch finished.
- Distinctive: line 14
Before opening a PR or tagging a release
- Very specific: line 37
Verify against an account that is currently reachable.
- Distinctive: line 90
If the validator reports FAIL or cannot fix something, stop finalize and surface blockers to the user.
- Distinctive: line 121
All must pass before updating any remaining doc claims.
- Distinctive: line 140
If the simplifier returns edits, re-run pytest before continuing.
- Distinctive: line 147
Update only what the code change still affects after step 1.
- Very specific: line 170
Do not bump metadata.version in marketplace.json
- Very specific: line 175
If step 5 edited any plugin/skills/*/SKILL.md, delegate to plugin-dev:skill-reviewer and apply wording fixes.
- Very specific: line 209
Run mcpb unpack + mcpb validate as an MCPB structural smoke (skipped with a printed notice if neither mcpb nor npx is available).
- Very specific: line 214
If any step fails, fix the underlying issue.
- Very specific: line 253
If HEAD is on a protected branch (e.g.
- Very specific: line 264
Do this before writing a CHANGELOG entry, not at tag time.
- Very specific: line 331
HEAD must equal both the fetched and the live
origin/main: Run create-release-tag.sh with no flags first.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Finalize apple-mail-mcp
Run this after implementation is done and before calling the branch finished. Orchestrate with subagents; do not solo large doc/manifest sweeps.
When to use
- User finished a feature/fix and wants docs, guides, and manifests aligned
- User says: finalize, ship, sync docs, update CLAUDE.md, validate manifests, pre-release check
- Before opening a PR or tagging a release
Recommended skills for the change being finalized
Pick by what the diff actually touched; don't run all of them. Each is
either a Skill (run inline) or an Agent (delegate via Task). The dev-mode
hook in .claude/hooks/dev_mode_reminder.sh reflects the same map.
| If the diff touched… | Use |
AppleScript inside Python f-strings (tools/*/ packages, core/ package) | The .claude/hooks/check_applescript_compiles.py parse check fires automatically on edit. Live-verify before ship against the production test account named in tasks/CLAUDE.md § Production test account — see the live-verification rule below the table. |
Perf-sensitive paths (tools/smart_inbox/, tools/analytics/, large-inbox loops) | python-performance-optimization skill |
Timeout subdivision, retry/backoff, AppleScriptTimeout handling | python-resilience skill |
Silent except / on error skips, errors[] surfacing, partial-failure JSON | python-error-handling skill |
| New tests, missing test coverage, parser-vs-script gaps | testing-python or python-testing-patterns skill |
asyncio fan-out, asyncio.run()-in-loop bugs | async-python-patterns skill |
| Pre-ship review pass | reviewing-code + code-review skills; python-anti-patterns as checklist |
| Confirming a change actually works in the running app | run skill, then the live-CLI procedure in docs/AGENT_LIVE_TESTING.md |
| Plugin manifest / marketplace / MCPB drift | plugin-dev:plugin-validator agent (REQUIRED; step 1 below) |
plugin/skills/*/SKILL.md wording or triggers | plugin-dev:skill-reviewer agent |
Live-verification rule (an empty result is not a pass)
Verify against an account that is currently reachable. Set
DEFAULT_MAIL_ACCOUNT to the production test account documented in
tasks/CLAUDE.md § Production test account, confirm
it is live, then run a bounded check:
.venv/bin/apple-mail accounts --json # confirm the account is present and reachable
.venv/bin/apple-mail awaiting-reply --account "$DEFAULT_MAIL_ACCOUNT" --days 7 --limit 5A zero-row result from an unreachable account is NOT a pass. A retired or
disconnected account (the former TU Exchange mailbox is the known example — that
server access has ended and it is no longer reachable) returns a confident empty
result that looks identical to "the AppleScript ran and found nothing." Never
verify against it: a gate that cannot fail is worse than no gate. Require the
account to appear in apple-mail accounts and the check to return real rows
before calling AppleScript changes verified.
Out of scope
- New feature implementation
- Version bump across the seven version files unless user explicitly requests a release
- Force push or amending pushed commits
Workflow
Copy and track:
Finalize progress:
- [ ] 1. plugin-validator: run and fix all reported issues
- [ ] 2. Scope the diff (what changed, why)
- [ ] 3. Code + tests verified
- [ ] 4. code-simplifier: pass over the diff (REQUIRED for any non-trivial change)
- [ ] 5. Docs, CLAUDE.md, skills, manifests synced (remaining drift)
- [ ] 5b. tasks/ hygiene: if planning artifacts moved or a workstream shipped: follow `tasks/CLAUDE.md` § Agent requirements; update `todo.md` + `INDEX.md`; run `python3 tools/validators/validate_tasks_layout.py`
- [ ] 6. skill-reviewer (if plugin/skills touched)
- [ ] 7. Rebuild release artifacts: `bash tools/gates/dev-check.sh release` (rebuilds **all three** artifacts: `apple-mail-plugin.zip` + `apple-mail.plugin` + `apple-mail-mcp-v{VERSION}.mcpb`, runs full validators including byte-parity check, runs mcpb unpack smoke). NEVER skip this step.
- [ ] 8. Final review checklist
- [ ] 9. Commit and push (default: yes, after release tier is green; open a PR if the branch is protected)
- [ ] 10. Merge (needs Cayman's explicit approval), then tag and release if the change carries a version. **A pushed branch is not a finished change** — stamp AFTER the merge, never before.1. plugin-validator first (required)
Delegate immediately to plugin-dev:plugin-validator (Task subagent_type="plugin-dev:plugin-validator" — the bare name plugin-validator is not a valid agent id). Do not run pytest or doc sweeps before this step completes.
Prompt must include:
- Full validation pass (manifests, tool counts, versions, MCPB parity, plugin structure)
- Fix every blocker and every fixable warning in-repo (doc test counts, stale MCPB descriptions, manifest args drift, etc.)
- Re-run
bash tools/gates/validate_manifests.shand report PASS/FAIL after fixes
If the validator reports FAIL or cannot fix something, stop finalize and surface blockers to the user. Do not proceed to step 2 until plugin-validator ends at PASS or the user accepts known exceptions.
2. Scope the change
git status
git log --oneline -5
git diff main...HEAD --statIdentify touched areas: plugin/apple_mail_mcp/tools/, plugin/skills/, tests/, manifests, README.md, docs/.
3. Verify code (delegate to shell subagent)
From repo root with .venv/:
.venv/bin/pytest tests/ -q
bash tools/gates/validate_manifests.sh
python3 tools/validators/validate_tasks_layout.py
python3 tools/validators/check_module_line_budget.py # 600 LOC warn report (regression enforced in pytest + manifests)
.venv/bin/pytest tests/infra/test_module_line_budget.py tests/infra/test_validate_manifests.py tests/infra/test_tasks_layout.py -qOptional when tools or CLI changed:
bash tools/gates/pre-commit-validate.sh
.venv/bin/apple-mail quick-check --json # live Mail smoke (~30s)All must pass before updating any remaining doc claims.
4. code-simplifier (REQUIRED for any non-trivial change)
Delegate to the code-simplifier:code-simplifier agent (Task
subagent_type="code-simplifier:code-simplifier"). This is non-optional
for any change beyond a one-line bugfix; root CLAUDE.md § Agent
orchestration mandates it as part of every "ready to ship" pass.
Scope the agent to the recently-modified files in the diff (it defaults to recent changes; pass explicit paths when the diff is large):
- Behavior must be preserved; pytest after the simplifier pass must match the pytest results from step 3.
- The simplifier collapses duplication, drops dead branches, tightens names; it does NOT redesign abstractions.
- Especially important after refactors touching many call sites (capability-token, structured-error, bounded-scan-style work), any file that grew past ~600 LOC, or any helper with >3 near-copies.
- If the simplifier returns edits, re-run pytest before continuing.
Skip only when: the diff is a one-line bugfix, a manifest version bump, or docs-only edits with zero Python changed.
5. Sync documentation (delegate to generalPurpose subagent)
Update only what the code change still affects after step 1. Do not rewrite unrelated files.
| If you changed… | Update | ||
MCP tools (@mcp.tool, params, defaults) | plugin/apple_mail_mcp/tools/CLAUDE.md, tool docstrings, README.md tool table, docs/CLAUDE-conventions.md, apple-mail-mcpb/manifest.json tools[].description | ||
| Plugin wiring / flags | plugin/docs/CLAUDE.md, plugin/apple_mail_mcp/CLAUDE.md, README.md Configuration | ||
| Agent workflows | plugin/skills/*/SKILL.md, plugin/skills/CLAUDE.md, docs/CLAUDE.md skill map | ||
| Planning / task artifacts | tasks/todo.md, tasks/INDEX.md, tasks/active/ (see tasks/CLAUDE.md § Agent requirements) | ||
| Test count | tools/expected_test_count.txt only (SSOT); after adding/removing tests run PYTEST_ADDOPTS='' .venv/bin/pytest --collect-only tests and update that file — dev-check fails on drift and prints the new number. Do not scatter counts in prose docs. | ||
| Module line budget | After intentional splits: python3 tools/validators/check_module_line_budget.py --write-baseline tests/fixtures/module_line_budget/baseline.json; do not refresh merely to allow growth | ||
| Tool count | The seven version files only on release; always sync claims: `find plugin/apple_mail_mcp/tools -name '*.py' | xargs grep -h '^@mcp.tool' | wc -l(recursive — every tool surface is a package, so a flattools/*.pyglob silently returns 0) vsplugin.json, marketplace, MCPB tools[]` |
Hub files to spot-check (stale cross-links or wrong counts):
AGENTS.md(root, canonical) andCLAUDE.md(root) — these two have drifted before around the § Version bump / tool-count paragraph; diff them against each other, do not update only oneplugin/docs/CLAUDE.md,plugin/apple_mail_mcp/CLAUDE.md,plugin/apple_mail_mcp/tools/CLAUDE.mdplugin/skills/CLAUDE.md,tests/CLAUDE.md,tools/CLAUDE.md,docs/CLAUDE.md.claude-plugin/CLAUDE.md,apple-mail-mcpb/CLAUDE.md,tasks/CLAUDE.md
Manifest rules (see tools/CLAUDE.md):
- Versions — seven files:
pyproject.toml,plugin/.claude-plugin/plugin.json,plugin/.codex-plugin/plugin.json,plugin/.cursor-plugin/plugin.json,.claude-plugin/marketplace.jsonplugins[0].version,server.json(both the top-levelversionandpackages[0].version—validate_manifests.pychecks each separately),apple-mail-mcpb/manifest.json - The Cursor manifest is enforced like the rest —
tools/validators/validate_manifests.pychecksplugin/.cursor-plugin/plugin.jsonversion; omitting it fails the gate - Do not bump
metadata.versionin marketplace.json - MCPB
tools[]names must match registered tool function names
6. skill-reviewer (if plugin skills touched)
If step 5 edited any plugin/skills/*/SKILL.md, delegate to plugin-dev:skill-reviewer and apply wording fixes.
7. Rebuild release artifacts (required; never skip)
Three artifacts must regenerate together from current sources before commit. All three ship with the repo, and drift between any of them has caused real installer failures.
| Artifact | Install path | Why drift breaks users |
apple-mail-plugin.zip | Claude Code plugin marketplace | Stale bytes → users get an older tool surface than the manifest claims |
apple-mail.plugin | Cowork → Customize → Add plugin → Upload plugin | Missing or diverged from the .zip → Cowork upload silently fails or installs stale code |
apple-mail-mcp-v{VERSION}.mcpb | Claude Desktop chat "Add Custom Plugin" | Wrong version filename or directory entries → Desktop installer aborts |
bash tools/gates/dev-check.sh releaseThat tier runs, in this order:
- Identity scan —
tools/validators/validate_no_committed_identity.py. Fails on a new real email address, absolute/Users/<name>/…path, or uppercase account UUID in any tracked text file. - Lint (fatal) —
ruff check+ruff format --check+mypy --strictoverplugin/apple_mail_mcp/. These are hard failures on this tier, not warnings; needs.venv/bin/pip install -e '.[dev]'. - Module line budget warn report (the 600 LOC regression is hard-gated inside
validate_manifests.py). tools/gates/build-artifacts.sh— the rebuild, detailed below.validate_tasks_layout.pyandvalidate_repo_root.py(a single stray untracked file at the repo root fails this).- pytest + the test-count gate against
tools/expected_test_count.txt(fails on drift and prints the new number). - Wrapper-surface check (
check_wrapper_surface.py). tools/gates/verify-offline-runtime.shagainst bothapple-mail-plugin.zipandapple-mail-mcp-v{VERSION}.mcpb.
Step 4 (build-artifacts.sh) is what actually regenerates the three artifacts:
- Prune stale
apple-mail-mcp-v*.mcpbat repo root (keeps only the currentpyproject.tomlversion). - Rebuild
apple-mail-plugin.zipwith the README exclusion list (venv,__pycache__,*.pyc,.DS_Store,CLAUDE.md,.env*, logs, temp/backup files). - Copy the zip bytes to
apple-mail.pluginso the Cowork artifact stays byte-identical to the marketplace zip. - Rebuild
apple-mail-mcp-v{VERSION}.mcpbviaapple-mail-mcpb/build-mcpb.sh(which prefers officialmcpb pack). - Re-run
APPLE_MAIL_REQUIRE_DIST_ARTIFACTS=1 bash tools/gates/validate_manifests.sh; fails if any of the three artifacts is missing, stale older.mcpbbundles remain, or the.pluginbytes diverge from the.zip. - Run
mcpb unpack+mcpb validateas an MCPB structural smoke (skipped with a printed notice if neithermcpbnornpxis available). - Unzip
apple-mail-plugin.zipand runclaude plugin validate --stricton it (skipped with a printed notice if theclaudeCLI is not onPATH). Cowork promotes warnings to errors, so--strictis the mode that matches the installer.
Because pytest runs after the rebuild on this tier, a green run also proves the artifacts were built from a tree that passes the suite.
If any step fails, fix the underlying issue; do not commit stale artifacts. Never delete apple-mail.plugin or build it manually; it must come from the build script's byte-copy, not a hand-zip, or the parity check rejects it.
8. Final review checklist
- plugin-validator PASS after fixes
- code-simplifier pass complete (or explicitly skipped per step 4 exceptions); pytest still green afterward
tools/gates/dev-check.sh releasefinished green (artifacts rebuilt,mcpb unpacksmoke OK,claude plugin validate --strictOK when CLI is available)apple-mail-plugin.zip,apple-mail.plugin, andapple-mail-mcp-v{VERSION}.mcpbmodified time newer than every changed plugin sourceapple-mail.pluginbytes ==apple-mail-plugin.zipbytes (validator enforces; manual check:cmp apple-mail-plugin.zip apple-mail.plugin)- Behavior described in docs matches
tools/compose/package defaults and other tool packages - No stale "open by default" or subject-matching guidance where
message_idis preferred - No skill suggests
compose_email/create_rich_email_draft/manage_drafts(action="create")for replies;standalone_confirmed=Trueis documented where standalone-with-Re: is legitimate email-draftingandapple-mail-operatorskills agree with README draft-safe sectiontasks/INDEX.mdandtasks/todo.mdupdated if a workstream opened, shipped, or archivedpython3 tools/validators/validate_tasks_layout.pypasses (no loose files attasks/root)- No secrets or local paths committed
- Unrelated dirty files left unstaged
9. Commit and push (default: yes; close the loop yourself)
Once steps 1-8 are green, commit and push without waiting to be asked. The user's standing preference is that finalize closes its own loop. Pause and ask only when there is genuine ambiguity (unrelated WIP in the tree, secrets in staged paths, partial implementation, or a force-push would be required).
Stage focused paths; never git add -A.
git add <relevant paths>
git commit -m "$(cat <<'EOF'
<1-2 sentences: why, not what>
EOF
)"Push as the closing action of finalize:
git push -u origin HEADIf HEAD is on a protected branch (e.g. main with branch-protection rules), switch to a feature branch and open a PR with gh pr create instead; same default-to-action principle.
10. Merge, tag, and release (required; the loop is not closed at "pushed")
A pushed branch is not a finished change. Finalize ends when the work is on
main and, if it carries a version, when that version is tagged and released.
Both halves are load bearing: v3.12.0 is tagged but never got a GitHub
Release, so that version has no downloadable .zip / .plugin / .mcpb.
First decide which version the notes belong under
Do this before writing a CHANGELOG entry, not at tag time. An empty
## Unreleased heading is not evidence that the newest dated section is
still open — that section may already be shipped, and appending to it makes the
published release notes for that tag describe code the tag does not
contain.
V=$(grep -m1 '^version' pyproject.toml | cut -d'"' -f2)
git tag --list "v$V" && gh release view "v$V" --json tagName,publishedAt 2>/dev/nullEither one returning a hit means that version is closed: bump to the next
patch, open a new dated ## X.Y.Z - YYYY-MM-DD section above it, and leave the
shipped section byte-identical to its tag (git diff vX.Y.Z -- CHANGELOG.md
should show only your new section). Both returning nothing means the version is
genuinely open and you may add to it without bumping.
Merging needs Cayman's explicit approval ("merge to main", "Cayman approved this merge", or equivalent). Never use GitHub native auto-merge. Ask for it as the closing action rather than leaving the PR open silently.
Once approved, the order below is not stylistic — each step invalidates the one before it:
.venv/bin/pip install -e . # only after a version bump; see note below
gh pr merge <N> --squash --repo Agentic-Assets/apple-mail-mcp # or --merge
git checkout main && git fetch origin && git pull --ff-only origin main
bash tools/gates/source-release-gate.sh # MUST come after the merge
bash tools/gates/create-release-tag.sh # preview; no signing
bash tools/gates/create-release-tag.sh --confirm-create
git push origin vX.Y.Z
bash tools/gates/marketplace-handoff.sh vX.Y.ZWhy that order. The gate's stamp binds HEAD's commit SHA, not its tree. Stamping on the feature branch and then merging produces a merge commit with an identical tree but a new SHA, so the stamp reads stale and the tag push is refused. Stamping before the merge is wasted work — budget ~7 minutes for the run and do it once, afterward.
Four preconditions that fail late if unmet:
- After a version bump, refresh the editable install before any gate. The
runtime version comes from installed distribution metadata, not from
pyproject.toml, so a bump without.venv/bin/pip install -e .failstest_package_version_matches_pyprojectroughly seven minutes into the release-tier run. The test names its own fix; running it up front saves the round trip. - A completely clean checkout, including untracked and gitignored files.
validate_repo_root.pyscans the filesystem, so a gitignored file still fails it.uv.lockis the recurring one: this repo uses pip +.venv, but anyuv runwhose cwd sits inside the tree walks up, finds the rootpyproject.toml, and writesuv.lockthere — an external MCP server doing this is enough. Park it outside the tree rather than deleting it (shared checkout, and it may be another agent's), then re-run the gate. user.signingkeymust be set and its key loaded.source_release.py create_tagrunsgit -c gpg.format=ssh tag -s, which forces the format but not the key. The key is machine-local and does not travel. It is passphrase-protected, sossh-keygen -Y signprompts and fails non-interactively when the key is not already inssh-agent. On this Mac the passphrase is in the login keychain, sossh-add --apple-load-keychainloads it without exposing or handling the passphrase — run that first and confirm withssh-add -lthat the fingerprint matchessigner_fingerprintinprovenance/source-release-policy.json. If the keychain does not have it, loading the key is the user's to do; never ask for or handle the passphrase.- HEAD must equal both the fetched and the live
origin/main. Runcreate-release-tag.shwith no flags first; it previews and prints the exact target SHA without signing anything.
Finally, attach apple-mail-plugin.zip, apple-mail.plugin, and
apple-mail-mcp-v{VERSION}.mcpb to the GitHub Release. Only the .zip is
tracked in git; the other two are gitignored and exist solely as build output,
so a Release without them ships an incomplete set.
11. Promote the payload to the Marketplace (the fix reaches nobody until this lands)
A GitHub Release is not delivery. Every install surface resolves through
Agentic-Assets/Agentic-Assets-Marketplace, so until the payload is promoted
there, mcp__plugin_apple-mail__* tools still execute the previously
installed version and will answer confidently from stale code. Verify fixes
through .venv/bin/python on repo source, never through MCP tools.
marketplace-handoff.sh only verifies the source side. The rest runs in the
Marketplace checkout, from current origin/main:
cd <marketplace-checkout>
python3 tools/prepare_plugin_update.py --plugin apple-mail --next-steps # read-only
git checkout -b chore/promote-apple-mail-X.Y.Z
python3 tools/prepare_plugin_update.py --plugin apple-mail --prepare --next-stepsThat prints the candidate payload digest, which names every file below.
Collect fresh acceptance evidence for the four surfaces in
provenance/plugin-policies.json → required_evidence_surfaces (codex_cli,
claude_code, cursor_local, macos_mail), commit and push the proofs
first so their blob URLs resolve, then build the evidence JSON referencing each
proof's pushed URL and SHA-256, and finish:
python3 tools/admit_plugin.py --plugin apple-mail --evidence docs/evidence/apple-mail-<digest>.json
python3 tools/attest_release.py --plugin apple-mail create --operator cayman
python3 tools/attest_release.py --plugin apple-mail sign \
--attestation provenance/attestations/apple-mail-vX.Y.Z-<digest>.json \
--signing-key ~/.ssh/id_ed25519_agentic_assets
export AA_MARKETPLACE_ALLOWED_SIGNERS="$HOME/.agentic-assets/marketplace-release/allowed-signers"
export AA_MARKETPLACE_SIGNER_FINGERPRINT="$(ssh-keygen -lf "$HOME/.agentic-assets/marketplace-release/release-key.pub" | awk '{print $2}')"
bash tools/gates/verify-marketplace-release.shThree traps, each of which costs a full gate re-run:
- Never point a client at the in-repo staged payload.
start_mcp.shbootstraps its venv in place, so a probe run withcwdinsideplugins/apple-mail/leaves a ~99 MBvenv/and__pycache__/behind. Both are gitignored, sogit statuslooks clean, but preflight then fails withpayload virtualenv forbiddenand, once the venv is deleted,provenance payload digest drift— and neither message names the cause. Copy the payload to a disposable directory, or clean both artifacts in a guaranteed cleanup path. - Drive Claude Code and Codex through isolated
CLAUDE_CONFIG_DIRandCODEX_HOMEdirectories. Older proofs describe snapshotting and restoring the operator's real config; isolation makes that restore step unnecessary and removes the failure mode where a crashed run leaves the operator's client pointing at a disposable preview. verifyneeds the external trusted allowed-signers path, notprovenance/allowed-signersin the repo — the point is that a single PR must not be able to edit both the signature and the trust root. Those two env vars are set nowhere by default; export them as above.
The macos_mail surface may invoke exactly one read-only tool
(list_accounts) and must retain only content-free metadata: no account names,
addresses, message metadata, or content ever enters a proof file. No proof file
may contain an absolute /Users/... path.
The Marketplace is not a protected production repo, so a completed PR there is
eligible for verified self-merge under policies/git.md and ADR 0006. After it
merges, run bash tools/gates/refresh-central-marketplace.sh back in this repo,
then read back the installed selector and version on each client you claim.
Release note
If shipping a version bump, bump all seven version files together (root AGENTS.md / CLAUDE.md § Version bump — pyproject.toml, the Claude, Codex, and Cursor plugin manifests, .claude-plugin/marketplace.json plugins[0].version, server.json, apple-mail-mcpb/manifest.json), re-run plugin-validator, then bash tools/gates/dev-check.sh release (which rebuilds all three artifacts (apple-mail-plugin.zip, apple-mail.plugin, and the .mcpb) and runs the structural mcpb-unpack smoke plus the byte-parity check between the zip and .plugin).
Additional resources
- Deep conventions: docs/CLAUDE-conventions.md
- Live verification: docs/AGENT_LIVE_TESTING.md
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

