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]>
140 lines
6.8 KiB
Markdown
140 lines
6.8 KiB
Markdown
# 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:
|
||
|
||
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.
|