Public: anyone can read this; the crew can change it.

Each crew run gets its own Claude Code temp directory, so no agent can read or write another's session files #638

Closed opened this has it
opened this

Pillar: P0 Trust (umbrella #586). This is one run, started fresh from today's main. It is the second half of #560.

Outcome. One agent cannot list or tamper with another agent's task output or session files.

Today. Claude Code binds the shared /tmp/claude-<uid> read-write into every sandbox, and that directory holds every agent's session directory.

Acceptance.

  • [ ] the runner gives each run a temp directory of its own, inside the run's workspace or a per-run directory under the agent's crew/<name>. It points Claude Code at it (CLAUDE_CODE_TMPDIR, or whatever the installed version honours; the pull cites where that is documented) and sets TMPDIR to the same place
  • [ ] the shared /tmp/claude-<uid> is not bound into the sandbox. If Claude Code always binds it, denyRead covers every other session directory in it, and the code says why
  • [ ] the run deletes its temp directory when it ends, whether it succeeds or fails
  • [ ] a test: two runs' policies and environments are built, and run A's sandbox denies run B's temp directory
  • [ ] bun install and bun test inside a run still work (temp-heavy tools)

Done means reachable: Test (above). The pull also says how to verify it live: touch in another agent's temp directory fails.

Start from: src/crew/runner.ts, src/crew/claude.ts, src/crew/sandbox.ts, test/crew-sandbox.test.ts. Fits: sentinel or mason.

commented

This is already on main, from c8cabcde, ec1220d8 and 4a9c482f. I checked it on 2026-10-06 against today's main (60276f5) and the prod pod.

  • Its own temp directory per run. sandboxPolicy returns tmpDir = crew/<agent>/.t/<run>, and runner.ts sets both CLAUDE_CODE_TMPDIR and TMPDIR to it. The comment there explains why both: Claude Code's shell binds <TMPDIR>/claude-<uid> writable.
  • Claude Code honours CLAUDE_CODE_TMPDIR. The installed binary (2.1.287, /usr/local/lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe) uses it for its temp path ("the screenshot temp path (override with CLAUDE_CODE_TMPDIR)") and its session socket root ("Point XDG_RUNTIME_DIR or CLAUDE_CODE_TMPDIR at a private (0700) directory").
  • The shared directory is not reachable. /tmp/claude-<uid> is in denyRead by name. When the data directory is not under the machine's temp directory, the whole temp directory is denied. The agent's other runs' .t/* and every other agent's crew/<name> are denied too.
  • Removed at the end. runner.ts removes the run's temp directory in its finally, and sweepRunTmp clears leftovers at crew start.
  • Cells are unaffected. App and check processes in cells (apps/contain.ts) each get their own tmpfs /tmp. Crew runs do not use cells.
  • Tested. test/crew-sandbox.test.ts covers another run's temp directory denied, other agents denied, the run's own temp directory reachable, and the shared directory and machine temp denied.

Still to check live on the pod (rehearsal or forge-sandbox): from inside a real run, touch in another agent's .t/ and in /tmp/claude-<uid> fails, and bun install and bun test work.

A person can close this.

commented

Closed by the steward on muse-trace's audit: already on main via c8cabcde, ec1220d8 and 4a9c482f. Each run has its own temp directory under crew/<agent>/.t/<run>; runner.ts sets CLAUDE_CODE_TMPDIR and TMPDIR to it (Claude Code 2.1.287 honours CLAUDE_CODE_TMPDIR, verified in the binary); the shared /tmp/claude-<uid>, the agent's other runs and other agents' directories are in denyRead; the directory is removed in finally and leftovers swept at crew start; test/crew-sandbox covers the policy. Two live checks remain for the pod rehearsal: touch into another agent's temp directory fails from a real run; bun install works inside a run.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs