| name | finalize-apple-mail-mcp |
| description | 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, CLAUDE.md/README/skills/MCPB sync, and commit/push when the user asks. Use when finishing a change, before release, when the user says finalize, sync docs, update manifests, or ship the branch. |
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 on TU Exchange (apple-mail awaiting-reply --account "TU - Cayman" --days 7 --limit 5) before ship. |
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 | verify + run skills |
| 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 |
Out of scope
- New feature implementation
- Version bump across six 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 (default: yes, after release tier is green)
- [ ] 10. Push (default: yes, to current branch; open PR if branch is protected)
1. plugin-validator first (required)
Delegate immediately to plugin-dev:plugin-validator (Task subagent_type="plugin-validator"). 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.sh and 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 --stat
Identify 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
.venv/bin/pytest tests/infra/test_module_line_budget.py tests/infra/test_validate_manifests.py tests/infra/test_tasks_layout.py -q
Optional when tools or CLI changed:
bash tools/gates/pre-commit-validate.sh
.venv/bin/apple-mail quick-check --json
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 | Six version files only on release; always sync claims: `find plugin/apple_mail_mcp/tools -name '*.py' |
CLAUDE.md hubs to spot-check (stale cross-links or wrong counts):
CLAUDE.md (root)
plugin/docs/CLAUDE.md, plugin/apple_mail_mcp/CLAUDE.md, plugin/apple_mail_mcp/tools/CLAUDE.md
plugin/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:
pyproject.toml, plugin/.claude-plugin/plugin.json, plugin/.codex-plugin/plugin.json, .claude-plugin/marketplace.json plugins[0].version, server.json, apple-mail-mcpb/manifest.json
- Do not bump
metadata.version in 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 release
That tier runs validate_manifests + pytest + the wrapper-surface check, then invokes tools/gates/build-artifacts.sh to:
- Prune stale
apple-mail-mcp-v*.mcpb at repo root (keeps only the current pyproject.toml version).
- Rebuild
apple-mail-plugin.zip with the README exclusion list (venv, __pycache__, *.pyc, .DS_Store, CLAUDE.md, .env*, logs, temp/backup files).
- Copy the zip bytes to
apple-mail.plugin so the Cowork artifact stays byte-identical to the marketplace zip.
- Rebuild
apple-mail-mcp-v{VERSION}.mcpb via apple-mail-mcpb/build-mcpb.sh (which prefers official mcpb 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 .mcpb bundles remain, or the .plugin bytes diverge from the .zip.
- Run
mcpb unpack + mcpb validate as a final structural smoke (if mcpb CLI present).
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
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 HEAD
If 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.
Release note
If shipping a version bump, bump all six version files together (root CLAUDE.md § Version bump), 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