# 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 ` 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: 1. The settings document pointed `PostToolUse` at 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. 2. The mission container uses `CLAWMATES_RUNTIME_IMAGE`, not the shared `clawmates-runtime` container — it was on an older image whose daemon schema had no `settings` field, so the prop write returned `404 path_not_found`. 3. The drain used `connect_with_local_defaults()`; the server reaches Docker through a **socket proxy**, so it failed — and returned `Ok(())` 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 1. **Prove the PreToolUse gate in a real VM.** `vm_tool_gate` is 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.jsonl` after a mission that tries something denied. 2. **Give the direct-session tier a tap.** It is the one tier with no observability at all — `session_executor::run_session` is a single `container_exec::exec` returning a string. Same settings document, written into a container instead of a VM. 3. **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 make `clawmates_skills` genuinely 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. 4. **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_candidate` items with no human click (`CLAWMATES_SKILL_SELF_AUTHORING=0` restores the gate). `identity_refinement` and `brain_consolidation` still 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-commits` and `tdd-red-green-refactor` are the next candidates and both need the repository diff rather than the turn text. ## Deliberately not done - **The mission executor swap** (running turns through `ProviderExecutor` or the chat `Runtime`). The blockers are structural, not wiring: `cm-runtime`'s `files` tool rejects absolute paths *by construction*, `shell` runs in a per-agent sandbox with no mission mount, `ToolContext` carries no path or VM handle, and approvals key on `(session_id, message_id)`. The cheap fixes deliver what it was wanted for. - **`cm-brain` offline tests** — 6 of 9 need live `clawbrainhub.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 `Bash` and `Write` with 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.