Skip to content

fix(jail): map scc, rtk and codegraph past the sandbox's private home - #31

Merged
protonspy merged 2 commits into
mainfrom
fix/jail-toolchain-maps
Aug 28, 2026
Merged

fix(jail): map scc, rtk and codegraph past the sandbox's private home#31
protonspy merged 2 commits into
mainfrom
fix/jail-toolchain-maps

Conversation

@protonspy

Copy link
Copy Markdown
Owner

The bug

ai-jail's private home replaces $HOME with a fresh tmpfs and binds only the command it was handed — it says so plainly: tools with needs beyond their install directory stay on the --map escape hatch — and then prunes PATH to the directories that survived.

So scc launch --jail ran RTK's preflight, wrote the block telling the agent to prefix every command with rtk, and then started it somewhere ~/.cargo/bin does not exist. An npm-installed scc goes the same way, and every rule scaffolded here answers questions with scc. The agent finds that out one failed command at a time and works around it by reading whole files, which is the cost this methodology exists to remove.

A jail that starts an agent unable to run the tools the file in front of it names is a jail that starts a useless agent — the same failure as one that cannot reach its model, arriving a step later.

The fix

--map becomes the third flag scc asks for, read off ai-jail --help like the other two, with no substitute when a build does not advertise it.

  • A compiled binary is mounted read-only at the name PATH knows and brings nothing with it. That is rtk; ~/.cargo/bin does not come along. It is also what makes the npm distribution work, since os.Executable() is the real Go binary behind the node shim and mounting it at the shim's path takes node out of the picture.
  • A script brings its bin directory, its outermost node_modules and its shebang interpreter, because node resolves a script's real path before looking for anything beside it. That is codegraph.
  • The list is closed at scc, rtk, codegraph — what scc's own guidance names and nothing else. Every mount is reported in jail.maps and printed in the command line; a tool scc never mentioned stays on --jail-arg.

Everything else remains policy, and policy stays in ~/.ai-jail / ./.ai-jail.

Ordering

The jail argv is now composed after the graph and RTK steps rather than beside the refusal: a run that has just installed rtk has to map the binary it installed. The refusal itself stays where it was — before the graph is built or the entry file is touched — so a launch that cannot be jailed still leaves the workspace exactly as it found it.

Verification

gofmt, go vet, go test ./... green. The mapping walk is unit-tested with the hidden root and the toolchain injected, covering both install shapes, a tool the sandbox already keeps, a build with no --map, and the shebang forms (env, env -S, env NAME=value).

Not verified end to end: the development machine is Windows, which has no sandbox backend. The real check is scc launch claude --jail --dry-run under WSL2 — the printed line should carry --map <rtk path> before the --.

ai-jail replaces $HOME with a fresh tmpfs and binds only the command it was
handed — "tools with needs beyond their install directory stay on the --map
escape hatch" — then prunes PATH to what survived. So `scc launch --jail` ran
RTK's preflight, wrote the block telling the agent to prefix every command with
rtk, and started it where ~/.cargo/bin no longer exists; an npm-installed scc
went the same way, while every rule scaffolded here answers questions with it.
The agent discovers that one failed command at a time and falls back to reading
whole files, which is the cost this methodology exists to remove.

--map becomes the third flag scc asks for, read off `ai-jail --help` like the
other two and never guessed at. A compiled binary is mounted read-only at the
name PATH knows and brings nothing with it — which is also what makes the npm
build work, since os.Executable is the real Go binary behind the node shim. A
script brings its bin directory, its outermost node_modules and its shebang
interpreter, because node resolves a script's real path before looking for
anything beside it. The list is closed at scc, rtk and codegraph: what scc's own
guidance names, nothing else, every mount reported in jail.maps and printed.

The jail argv is now composed after the graph and RTK steps rather than beside
the refusal, because a run that has just installed rtk has to map the binary it
installed. The refusal stays where it was, before anything touches the
workspace.
@protonspy
protonspy merged commit 87399b6 into main Aug 28, 2026
4 checks passed
@protonspy
protonspy deleted the fix/jail-toolchain-maps branch August 28, 2026 14:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant