Skip to main content

Tool Guards

The Bash mutation fence was removed

Earlier versions gated Bash, Write, Edit, and MultiEdit behind a pre-mutation fence that checked KBD project identity, control-plane reachability, and lifecycle state. That fence and the protected-test PreToolUse hook no longer exist. Bash, Python, Write, and Edit are not gated.

What still guards a tool call​

MatcherScriptWhat it blocks
Write|Edit|MultiEdit(none)Nothing
Bash(none)Nothing
Python(none)Nothing

Protected BDD integrity is checked at final local certification by scripts/verify-protected-tests.mjs. It compares committed Git states, so it detects content changes, deletion, rename, or mode changes regardless of which tool caused them. Intentional changes require an SSH-signed canonical approval manifest. Missing approval does not block creative work; it fails certification.

Why the fence was removed​

The fence attempted to arbitrate contention between several agents by blocking the operator's own tools. It protected against a failure mode that was not occurring while imposing one that was.

Every gate failed closed. A stopped daemon, an uninitialized runtime, or a phase that had merely finished would deny ls, git status, and cargo test. Because the fence covered all of Bash rather than only mutating commands, the denial also removed the diagnostics each error message recommended, and the recovery commands documented for that state. Finishing a phase — an ordinary, successful outcome — left the runtime in completed and disabled the shell with no in-band way out.

The scope guards (scope-guard.sh, check-child-scope.sh) compounded it by flagging writes outside a change's declared scoped_paths. Editing a submodule or a sibling project that the current change depends on is ordinary work, and it was flagged every time.

What the KBD adapter still does​

shared/scripts/kbd-harness-adapter.sh runs on four observational events:

EventBehavior
session_startRenders the bounded re-anchor block (committed revision, lifecycle, active path, next work)
post_compactSame re-anchor after context compaction
promptQueues a deferred event for the daemon
stopQueues a deferred event; advisory only

All four exit 0 unconditionally. None can refuse a tool call. The generated adapters for Codex, OpenCode, and Kimi carry the same event set — verified by scripts/check-harness-adapters.js and by prometheus doctor's hooks.harness-adapters check.

What is unchanged​

Phases, progress.json, current-waypoint.json, position-reminder.txt, and reflections all still work. They record position so a session — or a different harness entirely — can resume with one read. That bookkeeping never blocked anything, and it is the part that carries its weight.

Lifecycle state remains committed to the event journal and visible through prometheus kbd status and the REST API. Command concurrency is enforced at the journal transaction boundary, not by intercepting shell tools.