Handoff Contracts
Related source file:
src/agentmux/workflow/handoff_contracts.py
Handoff contracts define the structured interface between workflow phases. Each contract specifies the fields an agent must produce, validates submissions, and drives the orchestrator to materialize derived artifacts.
Overview
Agents submit phase outputs by writing the canonical file, then calling the MCP submission tool as a completion signal:
- Write the output file — the agent writes the artifact directly (e.g.,
02_architecting/architecture.md,04_planning/plan.yaml). Shared prompt fragments ([[shared:handoff-contract-*]]) embedded in agent prompts provide the schema and examples. - Call the MCP signal tool — the
agentmuxMCP server exposessubmit_*tools that validate the agent-written file, append a minimal signal entry totool_events.jsonl, and return a confirmation string (or a validation error the agent can act on). The tools write no files themselves.
The orchestrator observes the signal event, materializes derived companions and scheduling files, and drives the state transition.
Completion semantics are phase-specific:
- Architecture — the architect writes
architecture.mddirectly. No YAML is produced; the planner consumes the Markdown file directly. - Plan — the planner writes one
plan.yaml(version 2) containing all sub-plans and execution metadata. The orchestrator materializesplan_N.md,tasks_N.md,execution_plan.yaml, andplan.mdautomatically. - Review —
review.yamlis the canonical structured review artifact. Ifreview.mdis missing when all reviewers have passed, the orchestrator materializes it from the collected review results before dispatching the summary prompt (_request_summary()inhandlers/reviewing.py), so downstream prompts can continue to read the Markdown companion. A consolidatedreview.mdis generated: single reviewer → their text verbatim; multiple reviewers → combined document with per-role sections.
Contracts
Architecture
- MCP tool:
submit_architecture - Artifacts: see phases/02_architecting.md
- Validation:
architecture.mdmust be non-empty
Plan
- MCP tool:
submit_plan - Artifacts: see phases/04_planning.md
- Full schema: see artifacts/plan-yaml.md
- Required fields:
version(must be2),plan_overview,groups,subplans,review_strategy,needs_design,needs_docs,doc_files
For the complete field-level schema with types, constraints, and examples see artifacts/plan-yaml.md.
Groups reference sub-plans by index. Indices must start at 1 and be contiguous (1, 2, 3, …). The orchestrator converts {index: N, name: "..."} → {file: plan_N.md, name: "..."} when materializing execution_plan.yaml.
Review
- MCP tool:
submit_review - Artifacts: see phases/07_review.md
- Full schema: see artifacts/review-yaml.md
- Required fields:
verdict("pass"or"fail"),summary - Conditional fields:
findings(required onfail— list of{location, issue, severity, recommendation}),commit_message(optional onpass)
Parallel reviewer usage: When running parallel reviewers (reviewer_logic, reviewer_quality, reviewer_expert), each reviewer must pass the role parameter:
submit_review(role="reviewer_logic")This causes the tool to read 07_review/review_<role>.yaml (instead of the legacy review.yaml) and serializes {"role": "<role>"} into the tool event payload in tool_events.jsonl. This allows the orchestrator to correlate submissions from concurrent reviewers. Calling submit_review() without role reads the legacy 07_review/review.yaml. Invalid role values raise a ValueError.
Preference persistence via submit tool parameter
All four submit tools (submit_architecture, submit_pm_done, submit_plan, submit_review) accept an optional preferences parameter:
submit_review(
preferences=[
{"target_role": "coder", "bullet": "- Keep regression tests"}
]
)When provided, the MCP server calls apply_preference_entries(project_dir, preferences) which appends bullets to .agentmux/prompts/agents/<role>.md under ## Approved Preferences — creating the section and file if absent. Deduplication is applied on a normalized casefold basis. The preferences parameter is independent of the YAML artifacts; it is a direct tool call argument, not a YAML field.
validate_submission(contract_name, data) in handoff_contracts.py performs:
- Required-field presence — all required fields must be present
- Type checking — loose type validation against field specs (
str,bool,int,list[str],list[dict],dict) - Allowed-value enforcement — fields with constrained values (e.g., verdict:
pass/fail) are validated - Contract-specific rules:
- Plan:
versionmust be2; groups non-empty with uniquegroup_idand validmode; subplans non-empty with required string fields, non-emptytasksandowned_files, contiguousindexvalues starting at 1 - Review:
failverdict requires non-emptyfindingswithissueandrecommendation
- Plan:
MCP tools raise a validation error with all issues listed; agents receive the error message and can correct their submission.
Shared prompt fragments
Three shared fragments provide agents with file-writing instructions and YAML schema examples:
| Fragment | Included by | Purpose |
|---|---|---|
handoff-contract-architecture.md | architect.md | Architecture submission instructions |
handoff-contract-plan.md | planner.md, change.md | Plan submission instructions (plan.yaml v2) |
handoff-contract-review.md | review_logic.md, review_quality.md, review_expert.md | Review submission instructions |
These are inlined at template-load time via the [[shared:fragment-name]] syntax.