Repository navigation
Description
Summary
When Squad is bootstrapped (e.g., via squad init or installed in a new repo), it writes the squad_state MCP server entry to workspace .mcp.json. In non-interactive copilot -p ... invocations — which is how every copilot -p-driven test, CI run, and many automated workflows operate — that workspace MCP is not loaded into the agent's tool list. The agent then silently falls back to writing directly to .squad/decisions/*, .squad/memory/audit.jsonl, etc. via platform Create/Edit/bash tools, and forges audit-log entries that mimic the SDK provider's JSON format.
Reproduction
Tested on Windows 10 / Node 24.16 / @bradygaster/squad-cli v0.10.0-build.7 with both #1245 (memory_* MCP bridge) and #1246 (squad.agent.md drop-box → memory_write) patches applied locally.
- Fresh repo, run
squad init(or simulate by writing only workspace.mcp.json). copilot mcp list→ showssquad_stateunder "Workspace servers" ✅copilot mcp get squad_state→Tools: * (all), Source: Workspace (.../.mcp.json)✅- Run a directive prompt non-interactively:
copilot -p "Important directive: never force-push on shared branches. Capture this for the team." --agent squad --allow-all-tools --no-color - Observed: 0 MCP tool calls. Agent's own summary:
"Memory tools weren't available, so used local-file fallback (STATE_BACKEND=local)." - Agent wrote a fake audit entry like:
— note
{"class":"POLICY","ts":"2026-06-09T17:21:18Z","summary":"...","fallback":"local-file (memory_write tool unavailable)","actor":"copilot-coordinator","op":"write"}tsvs the real provider'stimestamp,opvsaction, and missingid/path/reason/provider.
Workaround that fixes the symptom
Add squad_state to user-level ~/.copilot/mcp-config.json instead of (or in addition to) workspace:
copilot mcp add squad_state -- node "<absolute path to squad-cli>/dist/cli-entry.js" state-mcpRe-running the same prompt then produces 4 MCP calls in a clean session: squad_state_health → memory_classify → memory_write → squad_state_write. Real audit entry with id, path, reason, provider. Real memory/index.json entry. Real memory/policy-inbox/*.md file. 100% reliable across 3 reproduction runs.
Why this matters
- Silent data fabrication. The agent writes JSON to
audit.jsonlthat looks like a realmemory.writeentry but isn't. Any tooling that parses this log can't tell real from forged. This violates the basic governance contract that the audit log is the source of truth for what was written. - Bridge + spawn-template fixes are wasted. PR feat(mcp): bridge governed memory tools (memory.*) through squad_state MCP server #1245 and Issue arch: directive capture + sub-agent decision-recording bypass the governed memory classifier #1246 are exactly the right work, but neither matters when the agent doesn't actually see the MCP tools at runtime.
- No telemetry. There's no warning when the agent falls back. A user looking at the run output sees a confident-looking "📌 Captured." message and no indication that the governance pipeline was bypassed.
Suggested fixes
In order of decreasing scope:
- Bootstrap registers at user level.
squad initshould runcopilot mcp add squad_state ...(or equivalent for VS Code) instead of writing.mcp.json, since that path works reliably in non-interactive mode. Or — better — do both. - Refuse to forge.
squad.agent.mdshould explicitly forbid writing to.squad/memory/audit.jsonlvia shell, and forbid writing to.squad/decisions/inbox/*viaCreate/Editwhensquad_state_writeis unreachable. Fail loud: tell the user "MCP not loaded, runsquad mcp installto fix". - Health-check warning at greeting. Coordinator already runs
squad_state_healthas PRE-CHECK step 0 — if that throws because the MCP isn't loaded, surface the error to the user instead of silently degrading. - Investigate workspace-MCP loading in -p mode. Workspace MCPs may require interactive approval that never happens in
-pmode. If that's the cause, copilot CLI behavior could be reported upstream.
Related
- feat(mcp): bridge governed memory tools (memory.*) through squad_state MCP server #1245 (memory_* MCP bridge) — necessary prereq, but not sufficient
- arch: directive capture + sub-agent decision-recording bypass the governed memory classifier #1246 (squad.agent.md drop-box → memory_write) — necessary prereq, but not sufficient
- arch: pick a direction for agents/{name}/history.md vs the governed memory model #1243 (history.md vs governed memory direction)
Cross-reference: see PR #1245 comment and Issue #1246 comment for the full A/B test runs.
Activity
fix: expose memory tools via MCP + route writes through governed pipe…
chore: promote v0.10.1 dev → main + v0.10 stabilisation blog post (#1313
chore: promote dev → main (v0.11.0) (#1422)