Files
cleveragents-core/.opencode/opencode.json
T
drew db12f45acb feat(controller): Phase 1m — wire response-builder MCPs into OpenCode (Option A)
The trial-path expedient (legacy_adapter harvesting chat-JSON) is now
the SAFETY NET; the architecture-intended path (agents call the
controller's response-builder MCPs, which validate against V1 +
write canonical JSON) is now wired end-to-end.

Four pieces:

1. MCP `finalize` accepts `output_path` argument
   ``mcp/_builder_base.finalize_and_emit`` adds ``output_path: str | None``
   kwarg. Precedence: explicit arg > ``CONTROLLER_CANONICAL_OUTPUT_PATH``
   env > stdout. This solves the per-attempt path problem that
   blocked opencode.json registration (the env var is static; the
   per-attempt path comes from the prompt, the agent passes it as a
   tool arg). Each role's finalize updated:
   - estimator_finalize(output_path)
   - implementer_finalize(output_path)
   - reviewer_finalize(output_path)
   - conflict_finalize(output_path)
   - summarizer_finalize(output_path)
   Creates parent directory if missing (so the controller doesn't
   need to pre-create). Returns ``wrote_to`` in the ok dict so tests
   can pin the path.

2. opencode.json registers the 5 controller MCPs
   ``.opencode/opencode.json`` adds:
   - implementer-response-builder
   - reviewer-response-builder
   - estimator-response-builder
   - conflict-resolver-response-builder
   - summarizer-response-builder
   Each spawned via ``python -m tools.controller.mcp.{role}_builder``
   with PYTHONPATH=/repo-root so the controller imports resolve.

3. Controller prompt builder injects the EXACT tool sequence
   ``worker/prompts.py`` rewrites each role's "Output contract"
   section. The old "PREFERRED MCP / FALLBACK file-write" instruction
   becomes a single REQUIRED contract: numbered tool calls (``X_start``,
   ``X_set_*``, ``X_finalize(output_path=...)``) with the explicit
   per-attempt path baked in. Explicit "DO NOT emit a JSON object in
   your final chat message" instruction to override the legacy
   contract baked into the agent system prompts.

4. Agent permission whitelists include the new MCPs
   - ``.opencode/agents/task-implementor.md`` (source for tier-{0,1,2,min}
     variants — regenerated via tools/sync_tier_models.py)
   - ``.opencode/agents/pr-review-worker.md``
   - ``.opencode/agents/estimator-implementation.md``
   - ``.opencode/agents/conflict-resolver-worker.md``
   Each adds the matching ``"{role}*": allow`` pattern.

Safety net preserved:
The legacy_adapter (commit bcc59d38a) is KEPT as a fallback path.
If an agent ignores the new instruction + emits chat-JSON anyway,
``opencode_session.py:inline_output_callback`` harvests it +
``legacy_adapter`` normalizes to V1 + writes to the canonical out
path. Both paths produce valid V1 → ``strict_parse`` succeeds. The
MCP path is now the WORKING preferred path; the chat-JSON harvest
is the safety net.

Total: 738 controller tests pass (+0 net — wiring change, no new
behavior tests), 0 regressions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 18:10:48 -04:00

121 lines
3.3 KiB
JSON

{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"graphify": {
"type": "local",
"enabled": true,
"command": [
"/home/drew/repos/cleveragents-core/.venv/bin/python",
"/home/drew/repos/cleveragents-core/tools/mcp_graphify_server.py"
],
"environment": {
"GRAPHIFY_OUT_DIR": "/home/drew/repos/cleveragents-core/graphify-out",
"GRAPHIFY_BIN": "/home/drew/.local/bin/graphify"
}
},
"ci": {
"type": "local",
"enabled": true,
"command": [
"/home/drew/repos/cleveragents-core/.venv/bin/python",
"/home/drew/repos/cleveragents-core/tools/mcp_ci_server.py"
],
"environment": {
"CI_GATE_SCRIPT": "/home/drew/repos/cleveragents-core/tools/local_ci_gate.sh"
}
},
"forgejo": {
"type": "local",
"enabled": true,
"command": [
"/home/drew/repos/cleveragents-core/.venv/bin/python",
"/home/drew/repos/cleveragents-core/tools/mcp_forgejo_server.py"
]
},
"git": {
"type": "local",
"enabled": true,
"command": [
"/home/drew/repos/cleveragents-core/.venv/bin/python",
"/home/drew/repos/cleveragents-core/tools/mcp_git_server.py"
]
},
"handoff": {
"type": "local",
"enabled": true,
"command": [
"/home/drew/repos/cleveragents-core/.venv/bin/python",
"/home/drew/repos/cleveragents-core/tools/mcp_handoff_server.py"
]
},
"block_store": {
"type": "local",
"enabled": true,
"command": [
"/home/drew/repos/cleveragents-core/.venv/bin/python",
"/home/drew/repos/cleveragents-core/tools/mcp_block_store_server.py"
]
},
"implementer-response-builder": {
"type": "local",
"enabled": true,
"command": [
"/home/drew/repos/cleveragents-core/.venv/bin/python",
"-m",
"tools.controller.mcp.implementer_builder"
],
"environment": {
"PYTHONPATH": "/home/drew/repos/cleveragents-core"
}
},
"reviewer-response-builder": {
"type": "local",
"enabled": true,
"command": [
"/home/drew/repos/cleveragents-core/.venv/bin/python",
"-m",
"tools.controller.mcp.reviewer_builder"
],
"environment": {
"PYTHONPATH": "/home/drew/repos/cleveragents-core"
}
},
"estimator-response-builder": {
"type": "local",
"enabled": true,
"command": [
"/home/drew/repos/cleveragents-core/.venv/bin/python",
"-m",
"tools.controller.mcp.estimator_builder"
],
"environment": {
"PYTHONPATH": "/home/drew/repos/cleveragents-core"
}
},
"conflict-resolver-response-builder": {
"type": "local",
"enabled": true,
"command": [
"/home/drew/repos/cleveragents-core/.venv/bin/python",
"-m",
"tools.controller.mcp.conflict_resolver_builder"
],
"environment": {
"PYTHONPATH": "/home/drew/repos/cleveragents-core"
}
},
"summarizer-response-builder": {
"type": "local",
"enabled": true,
"command": [
"/home/drew/repos/cleveragents-core/.venv/bin/python",
"-m",
"tools.controller.mcp.summarizer_builder"
],
"environment": {
"PYTHONPATH": "/home/drew/repos/cleveragents-core"
}
}
}
}