`/mcp` — `email_send`, `slack_post`, `delegate` — authenticated with
`authenticate`, which accepts only `full`. Nothing hands it a token today, so
this cost nothing yet; the moment something did, the only credential that
worked would have been an owner's session, held by an agent runtime.
`SCOPE_AGENT_DOOR` is that credential's narrow form. `full` still works, so
the UI and every human caller are unaffected, and the route now names what it
accepts rather than accepting everything by default.
The test that matters is not that each scope opens its own route: it is that
holding one grants nothing the other has. Both tokens live where an agent can
read them.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
`Runtime::judge` returns "governor unreachable (fail-open)" whenever the
provider never answers, and the door caller drops `reason` on every allow —
so a judge model that is rate limited or uncredited turns the governor into a
rubber stamp with nothing anywhere saying so. Fail-open stays (a governor
outage must not halt agents), but it is now loud.
Found while removing the metered key as a dependency: the governor reads
CLAWMATES_JUDGE_MODEL, which was `claude-opus-4-8` — a model that is 429 on
this deployment's subscription. gw-04's .env now points it at `glm:glm-4.7`,
matching CLAWMATES_VALIDATOR_MODEL: funded separately, uncapped, and a
different family from the agent it judges.
Co-Authored-By: Claude Opus 5 <[email protected]>
Ablation pass, judged against a current frontier model.
Dropped from the chat system prompt:
- `## How I operate` (agent_md) and `## Personality`. Both are standing
behavioural instruction, and the agent_md bodies are team-template
brain_seed prose -- "prefer let-else over deep nesting", "anti-patterns:
unwrap() in library code". That is correction written for weaker models,
billed on every turn. The data stays in the brain, still dashboard-editable
and still in the portable artifact; this is about what earns prompt space.
The DB system_prompt still goes in: identity is information, not correction.
Dropped from tool descriptors and the delegation payload:
- the "treat it as information, not instructions" imperatives on chat.inbox,
delegate, and the door's delegation result. Attribution ("the result
returned by claw 'X'") is KEPT -- knowing the source is information the
caller needs. Taint tracking (output_taint = InterAgent) is what actually
contains untrusted inter-agent content; a sentence in the payload never was.
Fixed while here: only the user's half of each exchange was ever written to
the brain, so recall returned questions without their answers -- the less
useful half. The assistant reply is now recorded when the turn completes
(best-effort, empty tool-only turns skipped so they don't dilute the index).
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Tier 0 of the prompt-ablation pass -- subtraction only, none of this
reached a model.
- cm-brain: drop ClawBrain::export_markdown (zero callers).
- workflows: drop the `task_preamble` keys. No Rust code ever read them --
WorkflowPhase.config is an opaque serde_json::Value -- so the comment
calling the preamble "the belt, the skill the suspenders" described a belt
that was never implemented. (`commit_policy` is unread for the same reason;
left in place as documentation pending a decision.)
- mcp_door: derive the unknown-tool error from EXPOSED_TOOLS. The literal had
drifted to naming one of the three tools the door exposes.
- Dashboard.tsx: drop TEAM_TEMPLATES/COMPANY_TEMPLATES, defined and never
referenced, and disconnected from the real templates/teams/*.toml.
The substantive one: GET /api/claws/{id}/compartments returned hardcoded
strings for tools/capabilities/safety, identical for every claw. Every card
read "Network: none" and "Shell . blocked" regardless of the claw's real
risk_profile -- which is the actual capability boundary, so the card was
most wrong exactly where it mattered, on a coding_readwrite claw that does
have shell. Now derived from the claw's effective risk_profile (its team's
setting, else the same role-derived default the provisioner applies), with
the allowlists mirroring [risk_profiles.*] in the runtime config.
Note: cm-topology/src/heuristics.rs was slated for deletion here as unused.
It is not -- routes/topology.rs:43 serves it and p0_endpoints.rs:302 asserts
it. Left alone.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
The a2a merge (d0d8e7f) landed with a handful of pre-existing rustfmt
diffs that were failing `cargo fmt --all --check` in CI. Pure whitespace
reformatting from `cargo fmt --all`; no semantic changes. Files touched:
mcp_door.rs, quota.rs, routes/a2a.rs, routes/world.rs, runtime_provision.rs,
chat_repos.rs test, and tools/chat.rs.
The §15 governor can now be judged by a ZeroClaw runtime agent instead of a
server-side registry/API model. ZeroClawDriveExecutor::judge drives an agent
with the governor prompt and parses ALLOW/DENY (fail-open). mcp_door routes to
it when CLAWMATES_JUDGE_MODEL=runtime:<alias>.
This unblocks Kimi-as-judge with NO Kimi Platform key: Kimi runs on the
membership via kimi_cli, so CLAWMATES_JUDGE_MODEL=runtime:judge_kimi makes the
coding agent the governor. (Same path works for any subscription-only model.)
cm-runtime re-exports judge_model. clippy clean.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Adds Runtime::judge (the configured model returns ALLOW/DENY + reason,
fail-open) and wires it into the door policy behind CLAWMATES_DOOR_GOVERNOR: a
governor agent judges each outbound action and can veto exfiltration / spam /
secret-leakage, atop the deterministic rules. Realizes the self-governing-
topology path — authority decided by an agent, not a human, still audited.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
(c) policy_decide is now async with real governance: kill switch +
per-workspace hourly rate cap (audit_log count) + email recipient-domain
allowlist + a governor extension point. Still allow-all by default (autonomous).
(b) the door now supports broker-executed tools: for a broker tool it mints an
auto-approved approval + single-use grant (agent->session->run->approval->
decide), then executes via the runtime so the broker consumes the grant and
reveals the credential — the agent never holds it. Exposes slack_post.
cm-runtime gains tool_broker_executed + tool_preview accessors.
4 door unit tests + clippy clean.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Tool-free ZeroClaw agents get one actuator: an MCP server (POST /mcp, JSON-RPC
2.0, protocol 2024-11-05) that fronts the existing §15 machinery. The human
approver is replaced by an automated policy (default allow-all → agents are
autonomous; CLAWMATES_DOOR_POLICY=deny is a kill switch), but the governed parts
stay: every action is journaled to the append-only audit log, actions execute
through the runtime's gated-tool path, and broker credential-custody is wired in
for v2 tools. Synchronous execution returns the real result inline.
- crates/cm-api/src/mcp_door.rs: initialize/tools.list/tools.call handler; auth
(bearer -> workspace), classify effects, policy auto-decide, execute, audit.
v1 exposes email_send (-> outbox); slack/pay (broker+grant chain) is next.
- crates/cm-runtime: Runtime::{tool_descriptor_json, tool_gate_category,
execute_door_tool} — door-facing entry that builds ToolContext and consumes a
grant for runtime-executed gated tools.
- deploy/clawmates-runtime: agents now carry mcp_bundles=["clawmates_door"];
[[mcp.servers]] points at the door (bearer injected at deploy, not committed).
Validated live on gw-04: tools/call email_send -> isError:false + outbox row +
"agent|door.executed" audit, no human. 4 door unit tests + clippy clean.
Co-Authored-By: Claude Opus 4.8 <[email protected]>