Skip to content

Sandbox friction log

Re-filed S504 (ruling R10), from runbooks/: a log, not a procedure.

Single append-only log of commands that hit Claude Code sandbox friction. Maintained by the /handoff skill (Step 2 item 6): at session close, append a row for any NEW friction command not already listed. Durable fixes live in .claude/settings.json (sandbox.excludedCommands, sandbox.filesystem.allowWrite, sandbox.network.allowedDomains, sandbox.enableWeakerNetworkIsolation) — this log records the history and the un-fixables so no session rediscovers them. start-session does not read this file; it exists so /handoff can dedupe and so fixes have provenance.

Settings-key placement gotcha (root cause of the chronic gh failure): sandbox boolean flags (enableWeakerNetworkIsolation, excludedCommands, …) sit directly under sandbox, NOT under sandbox.network, and never as a dotted literal key — the settings validator silently drops unknown keys.

Command / classError signatureStatus / fixFirst seen
gh / gh-axi (any Go-binary HTTPS)tls: x509: OSStatus -26276 (Go can’t reach trustd)FIXED 2026-07-15: sandbox.enableWeakerNetworkIsolation: true (was a dead misplaced key inside network since ~S440). Security note: opens trustd access — accepted trade.~S440
git push / pull / fetch (https)x509 as aboveExpected fixed by the same flag — VERIFY next session; if still failing it’s a different class, log it separately~S440
launchctlwrite EPERM outside allowlistFIXED 2026-07-15: sandbox.excludedCommands~S440
lavish-axi server launchserver inherits sandbox → 500s on session-openFIXED 2026-07-15: sandbox.excludedCommands (never start it sandboxed)S442
~/.mempalace writes (mempalace CLI: repair/mine/diary)write EPERMINTENTIONAL — do NOT blanket-allow (DR-009 single-writer posture, runbooks/mempalace-repair.md §3): reads work via mode=ro&immutable=1 with no allow; repairs run deliberately with sandbox disabled~S440
git worktree add.claude/agents write-deny EPERMbypass (dangerouslyDisableSandbox) — candidate for excludedCommands if it keeps recurringS443
Top-level worktree create/remove (../<name>)outside write allowlistbypassS447
Git ops that delete files (merge / reset / worktree remove)Operation not permittedbypassS447
Worktree-husk rm -rf (nested .claude/agents)EPERM (FR-006)bypass~S440
supabase db pushdirect DB connection blocked (non-HTTP)bypass. gen types works sandboxed with DO_NOT_TRACK=1 (telemetry write crash otherwise)S444
Shell redirect into supabase/types/database.types.tswrite deniedworkaround: generate to scratchpad, then cp into place (works sandboxed)S444
ledger-cli WRITE pathpatch-server health check EPERM (reads fine)bypass — root cause not yet diagnosed (allowLocalBinding is true, so not port-binding; investigate)S470
next build (Turbopack)documented sandbox failurebypasspre-S440
cmux CLIstale socket path in allowlistFIXED ~S443+: allowUnixSockets includes ~/.local/state/cmux/cmux-501.sockS443
git cherry-pick/commit touching .claude/skills/**Operation not permitted (unlink; sandbox deny on .claude/skills)bypass (dangerouslyDisableSandbox) — hit when cherry-picking session-driver-cmux script changes (id-150) onto mainS473
git push (docs-site, HTTPS)unable to get credential storage lock in 1000 ms: Operation not permittedBENIGN — the ref update SUCCEEDS; only the credential-helper cache write is blocked. No fix needed (an SSH remote would silence it)S473
bun run knip (in-sandbox)read-deny on supabase/types/database.types.ts + lib/mcp/plugin-bundle.ts → FALSE counts (files +1, unresolved +156) while the baseline gate reads clean numbers outsidebypass (dangerouslyDisableSandbox) — knip must run unsandboxed or its counts are wrong; the baseline checker inherits the same requirementS486
git add/commit/tag/stash-drop in sibling task-view repo (git -C /Users/.../task-view …)Operation not permitted (index.lock create; task-view path outside allowWrite)bypass (dangerouslyDisableSandbox) — recurring for any sibling-repo lane dispatchS475
bunx tsc --noEmitTS5033 tsbuildinfo write EPERM (spurious “error”)bypass (dangerouslyDisableSandbox) or ignore the TS5033 line — real errors unaffectedS474
bun run test:e2e (Playwright webServer boot)Turbopack “Symlink [project]/node_modules is invalid” — same class as the next build entrybypass (dangerouslyDisableSandbox)S474
gh run view --log-failed (CI failure triage)failed to get run log: creating cache entry: open ~/.cache/gh/run-log-*.zip: operation not permitted — gh caches the run-log zipbypass (dangerouslyDisableSandbox); durable fix would be sandbox.filesystem.allowWrite on ~/.cache/gh. gh run list/gh pr checks/gh run view --json are unaffected (no cache write)S476
git merge origin/main touching .claude/{skills,agents}/**error: unable to unlink old '.claude/…': Operation not permitted (Merge with strategy ort failed) — same .claude sandbox-deny class as the S473 cherry-pick entry, but a merge leaves untracked residue that must be git cleaned before retrybypass (dangerouslyDisableSandbox)S476
git worktree remove on canonical/.claude/worktrees/*Operation not permitted (dir deletion outside allowWrite)bypass (dangerouslyDisableSandbox) — hit pruning 16 landed S474 worktreesS478
ledger-cli WRITE path (refinement of the S470 entry)Ledger server failed to become healthy within 10000ms deadline (inv 54) … no fallback to ungated write pathbypass — the sandbox blocks the spawned patch-server’s port-file/cache writes, so health never turnsS478
executor git commit (heredoc message) in agent worktreesEPERM + stray shell text corrupting the commit messagebypass + file-based --amend (-F <msgfile>); recurring in Lane B2/D executorsS478
  • S477 git tag/git push in the task-view sibling checkout — unable to create temporary file: Operation not permitted (.git outside write allowlist) — bypass (sandbox override per sibling-lane convention); push additionally needs the one-off HTTPS+token URL (no SSH key).

  • S477 bare mktemp -dOperation not permitted (used /var/folders default instead of $TMPDIR) — fix: ALWAYS mktemp -d "$TMPDIR/XXXX"; the silent empty-var fallout made --ledger-dir "" hit the REAL ledger (9990 incident).

  • S477 git worktree removefailed to delete .git/worktrees/...: Operation not permitted — bypass (override); worktree metadata dir is deny-listed. | leaf-executor git/prettier ops in canonical/.claude/worktrees/agent-* (dispatched from the procurement checkout) | EPERM on commit/format/rm — Agent-tool worktrees resolve under the canonical root, outside the procurement session’s write-allowlist | bypass per exec; durable fix = extend sandbox.filesystem.allowWrite with the canonical worktrees glob | S479 | | cmux worker writing OQ/final_report to the main-repo $KH_CMUX_EVENTS_DIR from a worktree cwd | EPERM (path outside worker sandbox allowlist); relative .claude/cmux-events silently writes the worktree copy instead (invisible to parent) | bypass + brief workers with the ABSOLUTE main-repo path; durable fix = allowlist $KH_CMUX_EVENTS_DIR in worker launch env | S479 | | EVERY sandboxed Bash spawn (S481, whole session) | E2BIG at spawn — “command line plus environment exceed the OS exec argument limit”: the sandbox profile embeds a deny path per registered git worktree (153 at session start) and the frozen profile never shrinks mid-session | bypass all session (dangerouslyDisableSandbox per call); durable fix = sweep landed canonical/.claude/worktrees/agent-* at session close (S481 did: 48→2 kept) so the NEXT session’s profile builds lean; restart Claude Code rebuilds the profile | S481 | | git merge --ff-only origin/main touching hooks/** (main checkout) | error: unable to unlink old 'hooks/…': Operation not permitted — and the failed FF leaves the working tree HALF-UPDATED (files from the target commit written, HEAD not moved), so a naive retry then fails “local changes would be overwritten” | bypass + recover with git reset --hard origin/main (safe only after confirming zero local-only commits/work) | S483 | | bun install | error: bun is unable to access tempdir: PermissionDenied | bypass (dangerouslyDisableSandbox) | S483 | | gh run view --job <id> --log (sandboxed) | failed to get run log: creating cache entry: open ~/.cache/gh/run-log-*.zip: operation not permitted — gh writes its log cache outside the allowlist | bypass; durable fix candidate = add ~/.cache/gh to sandbox.filesystem.allowWrite | S484 | | ssh root@87.106.72.59 (Server B / VPS ops — deploy-proof loopback probes, docker exec) | network deny (host not in sandbox.network.allowedHosts) | bypass per call; durable fix candidate = add 87.106.72.59 to sandbox.network.allowedHosts | S485 | | git cherry-pick creating NEW files under hooks/ (main checkout) | unable to create file hooks/okf/…: Operation not permitted — the .claude/hooks-adjacent deny collides with the repo’s React hooks/ dir (same class as the S483 merge entry, cherry-pick variant); the failed pick leaves BOTH modified tracked files AND untracked created files, so retry needs git reset --hard + git clean -fd <paths>; concurrent agent worktrees sharing .git can also add a transient index.lock failure on the retry | bypass + two-step recovery above | S488 |

  • S489 (Intent clone /Users/liamj/intent/workspaces/okf-system/canonical, provisioning class) — fresh Intent worktree shipped WITHOUT .env.local (added mid-session); both ledger-cli and the GLM-5.2 OpenRouter producer need it — fix: copy .env.local into the clone before any ledger/producer work.

  • S489 — .cache/task-view-* vendored dir needed bun install before ledger-cli mutations worked (missing deps → mutation failure) — fix: bun install in the clone before first ledger write.

  • S489 — .claude/skills/session-driver-cmux/scripts absent in the Intent clone → 177 oq/* tests fail environmentally (not a real regression) — fix: expect environmental failures, or hydrate the scripts dir before running those suites.

  • S489 — the Python OKF producer does NOT auto-read .env.local (unlike bun, which auto-loads it) — env must be loaded explicitly (e.g. set -a; source .env.local; set +a) before invoking the producer.

  • S489 (harness watchdog, not sandbox) — long quiet pytest runs trip the stream watchdog and get killed — fix: run gates FOREGROUND + streamed (PYTHONUNBUFFERED=1, pipe to tail) so output keeps the stream alive.

  • S489 — ledger-cli mutations confirmed to require sandbox DISABLED (docs-site write + spawns a ledger server) — same class as the S470/S478 ledger-cli WRITE entries; bun auto-loads .env.local for these.

  • S490 — in-sandbox git fetch/push (canonical workspace): “fatal: unable to get credential storage lock in 1000 ms: Operation not permitted” — bypass (run git network ops with sandbox disabled).

  • S490 — in-sandbox access to out-of-repo paths (e.g. git -C $KH_PRIVATE_DOCS_DIR ...): blocks indefinitely instead of clean EPERM (agent hangs to turn ceiling) — durable fix applied: sandbox.filesystem.disabled=true in .claude/settings.json (landed 03ad0ae1).