Repo-specific working rules for masterplan. Generic agent policy (AUQ,
verification-before-completion, durable handoff, model routing) is global
fleet policy (/srv/workflows/policy/) and is not restated here. The
canonical CD-rule bodies
(CD-1…CD-11, referenced by live code via their IDs) live in
docs/conventions/cd-rules.md. This file collects
the masterplan-specific discipline that used to crowd AGENTS.md.
- Unit suite:
node --test test/*.test.mjs— the real, fast test surface forlib/*.mjs. Run it after any change to deterministic logic. (Report the actual pass count from the run; don't hardcode one.) - Doctor:
node bin/doctor.mjs— repo + bundle health checks; non-zero exit iff anyERROR. - Publish hygiene:
test/publish-hygiene.test.mjs(part of the suite) guards verb/skill-namespace consistency and path discipline.
- Never hand-write
state.yml/events.jsonl, and never let a wave member write state or commit. Every durable mutation goes through anmpsubcommand (CD-7) — a raw write both violates the single-writer rule and floods the screen with the diff (anti-flood). Wave members (agents / the L2 engine) return digests only; the shell is the canonical writer + committer, which is exactly what makes re-dispatch idempotent. - When you complete a task in a run bundle, append the activity via
mp event …(never hand-editevents.jsonl) and mark tasks withmp mark-task …. Never silently mark a task done. - Run bundle is the only source of truth (CD-7).
state.ymlplus bundled artifacts should be enough to resume any work. The shell is the sole writer (viamp); git is committed after thempwrite so a crash in between re-derives on resume.
Dispatch substantive work to agents (agents/*.md via the L2 engine), mp
subcommands, or superpowers skills. The orchestrator context holds sequencing
state only — never raw file contents or verification dumps. Subagents take a
bounded brief (Goal / Inputs / Scope / Constraints / Return shape), don't
inherit session history, and return compact digests. Model selection for
dispatches follows the central routing policy (policy/workflow-map.json); never
hardcode model tiers.
Don't add a verb or doctor check without updating every sync'd location.
- A verb lives in:
commands/masterplan.mdfrontmatterdescription:(line 2), the §1 reserved-verbs list + arg-precedence, the §3 routing table,README.md's verb table,docs/verbs.md, andskills/masterplan/SKILL.md's verb lists.lib/hygiene.mjsparseReservedVerbs()parses the frontmatter list andtest/publish-hygiene.test.mjsasserts the surfaces agree. - A doctor check is a new
lib/doctor/<check>.mjsmodule (auto-discovered bybin/doctor.mjs) plus a test, documented indocs/internals/doctor.md's module table.
Drift breaks autocomplete, the hygiene test, or silently skips checks.
Don't trust your own confirmation bias on large markdown/code edits. After a
multi-edit pass, dispatch a fresh-eyes reader subagent over the changed files
end-to-end for contradictions or dangling references. For a reviewable diff,
prefer a cross-vendor pass — the harness-native adversary class (breaker role,
frontier lane; adversarial panel for cross-vendor coverage — resolved from the
checked-in policy/workflow-map.json) — over a same-vendor
self-check (central policy: diff-review routes cross-vendor). Scope it
correctly: hand it a path-filtered git diff -- <paths> rather than a
whole-tree scan; in a dirty bundle (active state.yml, WORKLOG.md,
sibling-wave edits) commit first and use --base <ref>, or pass a scoped diff.
masterplan's own mp-adversarial-reviewer already does this — it reviews a
pre-built path-filtered diff, never a whole-tree scan.
The finish flow (commands/masterplan.md §2c)
verifies and cites output → writes retro.md if absent → opens the durable
branch_finish gate → archives last. Archiving earlier strands the run
(the discover filter hides archived bundles). Verification before completion
(CD-3): cite real command output and exit code — "should work" is not evidence.
When a named agent (mp-spec-decomposer, mp-planner, etc.) fails to
resolve — or a dispatch path looks unavailable — the orchestrator MUST NOT
silently run that role inline and "record the decision" as cover. "Recording"
a bypass is not a fix; only a code/config/behavior change is (see the global
Hindsight rule). The escape ladder is strict:
- Retry once — a transient resolve error is not a verdict on availability.
- Probe the real state —
subagent({ action: 'list' })for agent resolution andmp doctor(routing-policy-health) for the routing policy. Never assert "degraded" without one of these; an unverified excuse is the anti-pattern. - Escalate — open an AUQ (
ask_user_question) with concrete options, or surface viacontact_supervisor. Do not proceed on an unverified assumption.
If the root cause is a registration gap (e.g. mp-* not discovered on a host), fix the registration rather than working around it. Registration is host-specific:
- Claude Code discovers
agents/mp-*.mddirectly via its plugin loader as themasterplan:mp-*colon namespace. Those files are the single source of truth for role contracts; CC is unchanged by pi registration. - pi hosts discover a different set of paths (
~/.pi/agent/agents/,.pi/agents/,.agents/) and resolve CC baremodel:lane names (a lane such asfrontiermaps to its model ref frompolicy/workflow-map.json, e.g.litellm/gpt-6-astra) — but not to a host-native fallback. So a pi host needs adapted copies. Runbin/register-pi-agents.mjsto generate them at~/.pi/agent/agents/— bare-only (mp-spec-decomposer.mdetc.). The lane map swapsmodel: frontier→litellm/gpt-6-astra. Colon alias copies (masterplan:mp-*) are retired: write mode removes managed leftovers derived fromagents/mp-*.md(+ SKIP_FOR_PI);--checkflags those as drift. Unmanagedmasterplan:mp-*.mdoutside that set are left alone. Idempotent. The former skynet-MCP implementer agent is gone: implementer tasks now route through the governed routing-policy lane — the plan task'sclass(e.g.bounded-edit/agentic-loop) resolves to thebuilderrole, dispatched by its bare name (Pi) or the plugin namespace (CC). CC still loadsagents/as themasterplan:mp-*plugin namespace independently.
On pi, call bare names only: subagent({ agent: 'mp-spec-decomposer' }).
Colon alias files are no longer installed; CC-authored masterplan:mp-* names
still resolve on Claude Code via the plugin loader. A host where
subagent({ action: 'list' }) shows no mp-* is a registration gap to fix
(re-run the script), not a license to inline.
This complements CD-3: CD-3 ensures you verify completion; CD-11 ensures the delegation actually happened rather than being narrated into existence.