-
Notifications
You must be signed in to change notification settings - Fork 0
Orchestration Contract
This document defines the formal boundary between mq-mcp and its callers — primarily mq-agent, but also Claude Desktop, the OpenAI bridge, Codex, and any other MCP client.
The boundary is not aspirational. It is enforced structurally:
- Path resolvers reject access outside declared roots (ADR-001)
- No tool commits or pushes git state (ADR-002)
- Every tool has a declared safety class (ADR-003)
- Every tool output has a predictable structure (PHI-001)
Authoritative identity contract: docs/RUNTIME_CONTRACT.md
Architecture memory: architecture_memory/
Last updated: 2026-05-31 (v1.9.0).
- Invoke any tool by name with the declared argument types.
- Rely on tool output being a
str(plain text or structured text). - Pass file paths as repo-relative strings (not absolute paths).
- Set environment variables listed in
docs/architecture/SYSTEM_OVERVIEW.mdto configure runtime behavior.
- Pass absolute filesystem paths directly — resolvers will reject them unless
they fall within
MQ_MCP_ALLOWED_PATHS. - Invoke Class C or D tools without explicit user confirmation in the calling orchestrator.
- Assume that a Class A tool has no side effects on external systems — review tools make OpenAI API calls which are billable and rate-limited.
- Chain tool calls that together produce a git commit or push — each tool is independently scoped; the chain does not inherit a broader permission.
| Tool class | Caller action required |
|---|---|
| A | None — safe to auto-invoke |
| B | None — safe to auto-invoke (may make network calls) |
| C | Explicit user approval — writes files |
| D | Explicit user approval — opens apps or runs subprocesses |
All tools return a str. Callers must not assume JSON unless the tool
explicitly documents --json or json=True output.
Error returns always begin with {tool_name} failed: or ERROR:.
A caller that receives output starting with these prefixes must treat the
call as failed and not parse the remainder as success output.
Structured output that can be machine-parsed:
-
detect_architecture_drift—[SEVERITY] location\nbodyblocks -
review_file/review_diff/review_repo—[SEVERITY] file:line\nbodyblocks -
validate_orchestration_contract—[PASS]/[FAIL]/[WARN]lines
Review tools use a fixed severity vocabulary. Callers that parse review output must handle exactly these labels (case-sensitive):
RISK · ARCHITECTURE · WARNING · MISSING · SUGGESTION · NOTE
No other severity labels will appear in review output. If a label outside this set appears, it is a contract violation in the review engine.
Context-building tools (build_repo_context) write to review_engine/context/.
These files are best-effort cache — callers must not assume they reflect the
current state of the repo without running build_repo_context first.
- Commit to git
- Push to a remote
- Send network requests outside of explicitly declared API calls
(OPENAI_API_KEY tools,
get_public_ip, repo-signal CLI tools) - Modify files outside
REPO_ROOTandMQ_MCP_ALLOWED_PATHS - Persist state in a location not declared in the tool docstring
| Tool | Side effect | Location |
|---|---|---|
review_file |
Saves findings | review_engine/memory/review_history.json |
build_repo_context |
Writes context + generated artifacts |
review_engine/context/, generated/architecture/
|
extract_coding_conventions |
Writes ADR file | architecture_memory/decisions/ |
record_architecture_decision |
Writes ADR file | architecture_memory/ |
update_repo_file |
Modifies repo file | caller-specified path |
edit_image |
Modifies image file | caller-specified path |
take_screenshot |
Writes PNG |
~/Desktop/ or caller-specified |
set_clipboard |
Modifies clipboard | macOS clipboard |
store_semantic_memory |
Writes knowledge item | semantic_memory/store.json |
bootstrap_semantic_memory |
Writes doc summaries | semantic_memory/store.json |
export_symbol_index |
Writes symbol map | generated/symbols/symbol_index.json |
risk_review_file |
Saves findings | review_engine/memory/review_history.json |
risk_review_diff |
Saves findings per file | review_engine/memory/review_history.json |
Any tool not listed here has no persistent side effects.
mq-agent
│
├── invokes tool with args
│
▼
mq-mcp/server.py
│
├── resolve_repo_file / resolve_allowed_local_file [path boundary]
├── _load_review_contract() [contract selection]
├── _load_architecture_role() [context: arch map]
├── _build_rich_cross_file_context() [context: callgraph]
├── ArchitectureMemory.format_context_block() [context: ADRs]
├── ReviewMemory.format_past_context() [context: history]
├── ContextSelector (budget cap, priority order) [context assembly]
│
├── OpenAI API call (if applicable)
│
└── returns str to caller
Context injected into model calls, in priority order:
- Architecture decisions (relevant ADRs from
architecture_memory/) - Past review findings for this file
- Cross-file context (related file roles, symbols, last review)
- Architecture role (one-line label from
architecture_map.json)
The caller does not control context selection. mq-mcp owns context assembly.
These define what mq-mcp expects from each ecosystem partner and what it provides back. These contracts are currently documented in prose; v1.3.0 makes them explicit and verifiable.
mq-agent is the orchestration layer. It may:
- Discover tools via MCP protocol
- Invoke any Class A/B tool without approval gates
- Invoke Class C/D tools only after presenting the tool's safety_notes to the user
- Read
tool_safety_reportto display safety classification - Route review and architecture analysis requests to mq-mcp tools
mq-agent must not:
- Reimplement review logic locally
- Construct filesystem paths outside of tool arguments
- Assume mq-mcp maintains session state between calls
- Invoke tools in a sequence that collectively produces a git commit
repo-signal provides read-only repository intelligence:
-
repo_signal_analyze/repo_signal_checklist/repo_signal_inspect/repo_signal_doctor_json— mq-mcp proxies these as Class B tools - Expected output: structured text or JSON from repo-signal CLI
- repo-signal v1.1.0+ writes packs to
.repo-signal/exports/;callgraph_builder._try_merge_repo_signal_packs()merges them automatically
mq-mcp must not: duplicate repo-signal's graph-building logic.
mq-hal provides runtime and model health summaries:
-
hal_repo_report— mq-mcp proxies as Class D (runs mq-hal CLI) - Expected output: text report from mq-hal
mq-image-analyze provides visual analysis:
- Invoked as an external tool; output is a structured JSON blob (
visual_architecture_observation.v1) - mq-mcp does not call mq-image-analyze directly — callers invoke it and pass the result as context to mq-mcp review tools
mq-mcp guarantees to callers:
- All tool output is a
str - Error output begins with
{tool_name} failed:orERROR: - Review output uses the fixed severity vocabulary
- No output contains API keys, tokens, or local machine paths in cleartext
- Tool names are stable across patch versions; breaking renames require a minor bump
Each profile in profiles/ declares a recommended_tools list that restricts
which tools the profile's client should invoke. Profiles are not enforcement
mechanisms — they are guidance. Enforcement is the client's responsibility.
| Profile | Intended caller | Max tool class |
|---|---|---|
read-only.json |
Any read-only client | A |
repo-only.json |
Repo-focused client | A/C |
claude-desktop.json |
Claude Desktop | A/B |
codex.json |
OpenAI Codex | A/B |
openai-bridge.json |
OpenAI bridge | A/B |
developer.json |
Local developer | A/B/C/D |
local-macos.json |
Local macOS workflows | A/B/C/D |
mq-agent.json |
mq-agent orchestrator | A/B |
validate_orchestration_contract checks that profiles declaring a max class
do not include tools above that class in their recommended_tools.
The following are always true regardless of tool, caller, or configuration:
- No tool reads or writes outside
REPO_ROOTunlessMQ_MCP_ALLOWED_PATHSis set - No tool executes a dynamically-constructed shell command
- No tool commits or pushes git state
- No tool output contains redactable secrets in cleartext
- All tool names registered in
@mcp.tool()appear indocs/TOOL_SAFETY.md - All tools with
write: trueorsubprocess: trueintool_contracts.jsonare classified Class C or D.write: trueis allowed for Class D subprocess tools when the subprocess may create local artifacts, such as diagnostic bundles. - Class C learn/bootstrap tools may be intentionally profile-free because they are user-invoked write operations, not automated profile defaults.
- Every tool call is stateless with respect to prior calls — no implicit session
These guarantees are verified by validate_orchestration_contract and
detect_architecture_drift.
validate_orchestration_contract and detect_architecture_drift emit [WARN]
findings that do not block a release but signal potential drift.
| WARN | Acceptable when |
|---|---|
ORCHESTRATION_CONTRACT.md older than server.py |
No new @mcp.tool() functions were added in the commits since the last contract update. The diff-aware message confirms this by listing no new tools. |
RUNTIME_CONTRACT.md older than server.py |
The changes to server.py were internal helpers, refactors, or bug fixes that do not affect the declared guarantees or tool surface. |
architecture_map.json older than server.py |
build_repo_context() has not been re-run since the last server.py change. Acceptable in development; run before a review or release. |
- WARN lists specific tool names as "new tools since last contract update" → update the contract.
- WARN fires after adding a new tool class or safety boundary → update
RUNTIME_CONTRACT.md. - WARN persists across multiple commits with new tools → treat as FAIL for release purposes.
The release gate (scripts/release-check.sh) does not block on WARNs, but
they should be reviewed and resolved before tagging a release.