Skip to the content.

DOS Kernel Transfer Playbook

This playbook covers driving the repo under the DOS kernel’s per-call hook adjudication (the dos plugin’s PreToolUse / PostToolUse / Stop hooks) and auditing what the hooks intervened on afterward.

A transfer pass is one window in which a fleet of agents (Claude Code and Codex) drove the repo with the hooks live. The kernel records every adjudication to .dos/metrics/observations.jsonl (gitignored, re-derivable host state). The audit below folds a pass into the few numbers that decide whether to file new process debt.

Advisory audit (tree_known=false admission cautions)

The lane-admission rung proves a tool call’s file-tree footprint is disjoint from every held lane lease before allowing it. When the hook cannot derive a footprint for a call — a free-form shell command, or an editor call whose edited path the hook can’t see — the footprint is unknown (tree_known=false). With a lane held, an unknown footprint cannot be proven disjoint, so the rung emits an advisory caution (outcome=warn, rung=admission): the call still proceeds, nothing is refused. These cautions are the expected cost of proving disjointness over opaque calls, not a failure.

Audit command

Two lenses, both portable, run from the repo root:

# Lens 1 — the folded enforcement summary: refused + advisory, by reason and tool.
dos helped

# Lens 2 — the raw observation grep: count the tree_known=false admission cautions.
Get-Content .dos\metrics\observations.jsonl |
  ForEach-Object { try { $_ | ConvertFrom-Json } catch {} } |
  Where-Object { $_.outcome -eq 'warn' -and $_.tree_known -eq $false } |
  Measure-Object

Cross-platform lens 2 (Python — dos doctor reports the interpreter it found):

python - <<'PY'
import json
n = 0
for line in open(".dos/metrics/observations.jsonl", encoding="utf-8"):
    line = line.strip()
    if not line:
        continue
    try:
        o = json.loads(line)
    except ValueError:
        continue
    if o.get("outcome") == "warn" and o.get("tree_known") is False:
        n += 1
print(n)
PY

Codex session witness

For a specific Codex thread, the dogfood witness folds the same stream and observation evidence into its saved JSON under checks.dos_session_audit:

python tools\codex_dogfood_witness.py `
  --session $env:USERPROFILE\.codex\sessions\YYYY\MM\DD\rollout-...jsonl `
  --thread-id <codex-thread-id> `
  --fak-bin .\fak.exe

That report records the per-session .dos/streams/<thread>.jsonl step count, the timestamp-window fold over .dos/metrics/observations.jsonl, the tree_known=false admission-warning rate, delegate count, stop blocks, and a short recommendation list. It copies only timestamps, tool names, counts, latencies, and hash digests; it does not copy prompts, tool arguments, tool results, diffs, or model text. The observation join is explicitly a timestamp window, so concurrent sessions in the same window can contribute rows.

For a multi-session Codex pass, use the rollup:

python tools\codex_dos_recent_audit.py `
  --repo-root . `
  --codex-home $env:USERPROFILE\.codex `
  --limit 10 `
  --since-days 7 `
  --check-latest `
  --out experiments\agent-live\codex-dos-recent-audit.json

The rollup matches Codex session IDs to DOS stream files, reports aggregate unknown-footprint and delegate rates across the recent sessions, and, with --check-latest, compares the locally installed dos-kernel package with the configured PyPI index. By default this is the public PyPI at https://pypi.org/pypi/dos-kernel/json; set the PYPI_INDEX_URL environment variable to point to a private or mirror index instead.

Freshness is not the same as fast-path wiring. The same report also includes codex_hook_fast_path: it reads the cached DOS hook manifest under the Codex home and reports whether Codex-dialect hooks use the bundled native launcher or the slower Python CLI hook path. It records only manifest-relative paths and mode counts, not hook command bodies.

If that check is WARN, inspect the repair plan first:

python tools\codex_dos_hook_doctor.py --codex-home $env:USERPROFILE\.codex

The dry-run prints both current hook modes and projected hook modes after apply. Treat projected_codex_command_modes: {"native_launcher": N} with zero projected python_cli hooks as the proof that the repair would clear the Codex fast-path warning.

Run the same dry-run against Claude Code’s plugin cache when Claude Stop hooks are showing hook JSON errors or shell-form command warnings:

python tools\codex_dos_hook_doctor.py --codex-home $env:USERPROFILE\.claude --target-shell powershell

That report is the same privacy-preserving shape: manifest-relative paths and mode counts only. A WARN with replacements_available means cached DOS plugin hooks can be rerouted away from shell-form/native-launcher drift; do not edit the cache by hand.

Then apply it explicitly:

python tools\codex_dos_hook_doctor.py --codex-home $env:USERPROFILE\.codex --apply

For Claude’s plugin cache, use the same explicit apply with the Claude home:

python tools\codex_dos_hook_doctor.py --codex-home $env:USERPROFILE\.claude --target-shell powershell --apply

The doctor rewrites cached DOS hook manifests to call the bundled native PowerShell launcher first and leaves the Python CLI hook as the delegate fallback. It writes a sibling backup before changing a manifest. Like the audit, its report copies only manifest-relative paths and mode counts, never hook command bodies.

After a repair, the rollup adds two post-repair lenses:

Add --fail-on-warn when this should act as a local transfer gate instead of an observational report. The default budget is the playbook’s 2% unknown-footprint line; override it with --max-unknown-tree-rate and cap native-hook fallbacks with --max-delegates.

When you need a post-repair risk gate that keeps the residual shell-opacity debt visible but does not fail on it, use:

python tools\codex_dos_recent_audit.py `
  --repo-root . `
  --codex-home $env:USERPROFILE\.codex `
  --limit 10 `
  --since-days 7 `
  --fail-on-actionable-warn `
  --max-delegates 0

That gate still fails on an unrepaired fast path, post-repair delegates, stop failures, unparseable shell commands, shell_out_of_tree_write_target, or mutating opaque shell families such as git_write. It does not turn shell_no_write_target_detected into a pass for the strict transfer gate; it reports read/inspect opacity as actionability.residual: ["HOST_SHELL_OPACITY", ...].

To make the remaining host-opacity debt issue-ready without copying commands or prompts, emit the sanitized packet. It includes shell shape, family, and mutating family categories, not raw command text:

python tools\codex_dos_recent_audit.py `
  --repo-root . `
  --codex-home $env:USERPROFILE\.codex `
  --limit 10 `
  --since-days 7 `
  --check-latest `
  --out-debt experiments\agent-live\codex-dos-host-opacity-debt.md

After routing Git mutations through structured fak gates, include those gate reports in the audit so historical git_write remains visible but does not masquerade as a new post-mitigation failure:

python tools\codex_dos_recent_audit.py `
  --repo-root . `
  --codex-home $env:USERPROFILE\.codex `
  --limit 10 `
  --since-days 7 `
  --gate-report experiments\agent-live\codex-fak-gate-git-add.json `
  --gate-report experiments\agent-live\codex-fak-gate-git-commit.json `
  --gate-report experiments\agent-live\codex-fak-gate-git-push.json `
  --fail-on-actionable-warn `
  --max-delegates 0

The gate reports must be expected-deny results for git_add, git_commit, and git_push. When all three are proven, the audit adds a post-gate command-shape lens; any git_write after that timestamp still fails actionability.

The two lenses count over different windows — dos helped folds the lane journal while the raw grep counts the per-call observation log — so they report two nearby totals, not a disagreement (dos helped says as much in its own output).

Hook launcher failures vs advisory repeats

A Claude “failed PreToolUse” / “failed PostToolUse” banner means the hook command itself crashed before DOS could apply its fail-safe contract. That is different from a DOS advisory warning. Healthy hook no-ops emit nothing and exit 0:

'{}' | python -m dos.cli hook pretool --workspace .
'{}' | python -m dos.cli hook posttool --workspace .
'{}' | python -m dos.cli hook stop --workspace .

The checked-in .claude/settings.json therefore uses Claude Code’s exec-form hook shape ("command": "python", "args": ["-c", "..."]) rather than a shell-form command string. The launcher delegates to python -m dos.cli ... and exits 0 after the delegate returns, so Git Bash/profile startup output cannot be prepended to hook stdout and trigger Claude’s JSON parser. Real denies and Stop blocks are still preserved because they are stdout protocol objects, not nonzero process exits. The repo-guard PreToolUse hook follows the same rule: the launcher prefers the compiled tools/.bin/repoguard(.exe) when present and falls back to tools/repo_guard.py, then exits 0 so a missing binary never becomes a hook failure banner.

PostToolUse also has one expected “background” shape: polling a still-running background task can produce repeated identical tool results. DOS may resurface that as additional advisory context so the next turn notices the repeat, but it does not block the tool and should not be treated as a failed hook.

What a healthy pass looks like

Measured on a live pass (window 2026-06-21T20:05Z → 2026-06-22T08:01Z, 21,156 adjudicated calls):

metric value
advisory cautions, all reason=admission 192
of those, tree_known=false 177 (0.84% of all calls)
refused calls (held-lane collision) 3
dominant opaque tool Bash

All metrics from the same window: 2026-06-21T20:05Z → 2026-06-22T08:01Z (21,156 adjudicated calls).

Every tree_known=false caution traced to a genuinely opaque call — free-form shell and editor calls the hook can’t introspect — not to a call that does carry a visible path. That is the accepted floor.

Threshold for filing new process debt

File a new dos-kernel footprint-derivation issue (the hook change is out of scope for this repo — see below) when a transfer pass crosses either line:

  1. Ratetree_known=false admission cautions exceed 2% of adjudicated tool calls. (First transfer pass: 1.3%, 305 / 22730. This pass: 0.84%. The 2% line is ~1.5× the first-pass rate — a material widening of the footprint gap, not noise.)
  2. Shape — the remaining cautions stop being dominated by genuinely opaque calls (free-form shell) and start hitting calls that carry a visible path (Edit / Write / apply_patch). That points at a footprint-extraction regression in the hook, not inherent opacity, and warrants a dedicated issue.

Below both lines the cautions are the known, accepted cost of proving lane disjointness over opaque calls — do not file.

What this repo can and cannot fix

The footprint derivation — teaching the hook to read a read-only or path-scoped footprint out of a shell command or editor call — lives in the dos-kernel plugin, not in this repo. The dos.toml workspace policy declares the lane taxonomy and refusal vocabulary the hook consumes; it carries no knob for per-call footprint extraction. So: