Records the verified result (10 tool.call, 4 file.touch on a real mission), how hooks succeed where stream-json could not, the production state and its rollback, and the three same-shaped bugs the live test found. Also records that CI's build failures were disk pressure from my own manual runtime builds on gw-04 — not code — and that a docs-only commit was the first casualty, which made it look like a regression. Co-Authored-By: Claude Opus 5 <[email protected]>
6.8 KiB
Where this left off — 2026-08-20
Read CAPABILITY-REVIEW.md for the system picture,
TOOL-CALL-ARCHITECTURE.md for the current investigation, and
SKILL-USE-BASELINE.md for the measurement.
State of the tree
Everything is pushed. main is at 128b423; the fork's
merge/upstream-v0.8.4 is at db1c50966. The local suite is green — 106 test
binaries, zero build errors, frontend builds.
Container-tier tool gate + telemetry — SHIPPED 2026-08-21
The tier that actually runs missions now has both, verified end to end on a real mission (locally first, then deployed):
tool.call 10 Bash 6, Read 3, Write 1
file.touch 4 research/tapproof.md
That is the first time the container tier has ever been observable.
How, after stream-json failed. Claude Code runs its tools inside its own
subprocess, so they never reach ZeroClaw's executor and never become a
TurnEvent::ToolCall. Hooks bypass that entirely: claude -p --settings <doc>
honours PreToolUse and PostToolUse, so the gate blocks and the tap records
without ZeroClaw being involved at all.
Pieces: --settings on claude_cli (fork be9c34b1c),
container_tool_hooks writes both hook scripts and one settings document into
the mission container, set_claude_cli_settings points the provider at it, and
phase_runner::drain_finished_container_phases collects the tap into
mission_events (idempotent by truncation — no cursor column).
Production state: server on f6e6037;
CLAWMATES_RUNTIME_IMAGE=clawmates-runtime:hooks in /opt/clawmates/.env
(backup at .env.bak.prehooks; rollback = restore it and recreate). Note that
host uses legacy docker-compose, not the v2 plugin.
Not yet observed in production — no prod mission has run since the flip. Prod auth is Clerk, so a mission cannot be launched from here by password. The check when one runs:
ssh gw-04 'docker logs clawmates_server_1 2>&1 | grep -E "per-mission runtime image|drained .* tool call"'
Three bugs the live test found, all the same shape
Each left every other link looking correct:
- The settings document pointed
PostToolUseat a path the installer never wrote. Claude Code does not complain about a missing hook command — it records nothing. A test now compares the document's commands against the files the installer creates. - The mission container uses
CLAWMATES_RUNTIME_IMAGE, not the sharedclawmates-runtimecontainer — it was on an older image whose daemon schema had nosettingsfield, so the prop write returned404 path_not_found. - The drain used
connect_with_local_defaults(); the server reaches Docker through a socket proxy, so it failed — and returnedOk(())silently.
CI: build failures were disk, not code
Runs 503–506 failed at build with an unreadable log, and the first casualty
was a docs-only commit. Cause: building runtime images by hand on gw-04
competes with CI for the same 150G volume; the frontend image build lost.
docker builder prune reclaimed 34GB (22G → 57G free) and the next run went
green. The build job now writes breadcrumbs, a df -h snapshot, and which
services actually pushed — the failing runs had pushed server, aborted on
frontend, and left :latest unmoved, which surfaced three steps later as
"the deploy did not happen".
Operational note: do not build images by hand on gw-04 while CI may run.
Then, in order
-
Prove the PreToolUse gate in a real VM.
vm_tool_gateis unit-tested and shell-tested on the host; it has never run in a guest. Four of its bugs were found only by executing the generated script, and two of them (syntax error,IFS) produce a gate that looks installed while being fully closed or fully open. Check/root/toolgate/denied.jsonlafter a mission that tries something denied. -
Give the direct-session tier a tap. It is the one tier with no observability at all —
session_executor::run_sessionis a singlecontainer_exec::execreturning a string. Same settings document, written into a container instead of a VM. -
Deploy the door we already built (
docs/TOOL-CALL-ARCHITECTURE.md§3). Create/zeroclaw-data/clawmates-mcp.json, add a door-shaped provider alias, bind mission claws to it. This is config, not code — the provider feature is ours and shipped. It would also makeclawmates_skillsgenuinely reachable, which is the precondition for moving skills from inlined bodies to progressive disclosure and making Skill-Use Trigger measurable the way the paper defines it. -
Pull upstream's egress policy —
0db7d999a feat(plugins): add shared egress policy foundation (#9137). We are 218 commits behind; this is the one item identified as worth taking, and it is defence for a problem we have not solved.
Open decisions that are yours
- Self-authoring scope. Agents now apply their own
skill_candidateitems with no human click (CLAWMATES_SKILL_SELF_AUTHORING=0restores the gate).identity_refinementandbrain_consolidationstill wait for a human, because they change what an agent IS rather than adding a procedure it can consult. Say if you want those autonomous too. - Skill-Use Compliance coverage. Most skills still score
not_applicable— we cannot tell whether they changed anything.small-focused-commitsandtdd-red-green-refactorare the next candidates and both need the repository diff rather than the turn text.
Deliberately not done
- The mission executor swap (running turns through
ProviderExecutoror the chatRuntime). The blockers are structural, not wiring:cm-runtime'sfilestool rejects absolute paths by construction,shellruns in a per-agent sandbox with no mission mount,ToolContextcarries no path or VM handle, and approvals key on(session_id, message_id). The cheap fixes deliver what it was wanted for. cm-brainoffline tests — 6 of 9 need liveclawbrainhub.com. Stubbing means reproducing an external registry protocol we have no spec for.- Graph memory /
clawhdf5-agent— in the workspace manifest, used by no crate. Measure against a baseline before migrating.
Two corrections made this session, worth remembering
- "Missions can't call tools at all" was wrong. They call
BashandWritewith permissions pre-accepted. The gap was observing and gating, not having. - Raw test counts are a bad coverage metric. They pointed at
cm-safety, whose seven tests already covered its critical paths, and missed a Slack replay hole that let one captured request authenticate forever.
The recurring shape, now seven times over: a claim in a comment or a doc, believed and never checked. Every significant finding this session came from running the thing rather than reading about it.