File tools
target pathWrite, Edit, MultiEdit, NotebookEdit (and the Codex apply_patch / Gemini / Antigravity write aliases). Every touched path must be under scratch.
Press ← or → to navigate between chapters
Press S or / to search in the book
Press ? to show this help
Press Esc to hide this help
A friction-free, session-scoped working directory for an agent's throwaway files: patch diffs, fetch dumps, screenshots, draft PR bodies, captured build output. Writes whose target resolves under a recognized scratch root ($TOOL_GATES_SCRATCH, or Claude Code's native session scratchpad) auto-allow in every permission mode, so agents stop prompting for intermediate work.
The base
The base is $TOOL_GATES_SCRATCH (default ~/.cache/tool-gates-scratch). The convention is to write under a per-project, per-session subtree so parallel work never collides and scratch lines up with the session transcript:
$TOOL_GATES_SCRATCH/<project-slug>/$CLAUDE_CODE_SESSION_ID/
The project slug mirrors the ~/.claude/projects/<slug>/<session>/ transcript scheme (the working dir with / turned into -), and the session id lets a session's subagents and workflow agents resolve the same dir. Those segments are organizational only: the permission decision is a pure prefix match against the base, so the leading $TOOL_GATES_SCRATCH is the only part that matters for auto-allow.
Second root
Claude Code creates its own per-session scratchpad at session start and hands the agent the literal path in the system prompt, no variables required:
<tmpdir>/claude-<uid>/<project-segment>/<session-id>/scratchpad/
Claude Code auto-allows its file tools there, but not Bash, so a redirect, mkdir, tee, or cp into it would still prompt. tool-gates recognizes this directory as a second scratch root with the same upgrade set as below. The match is bound to the current session: the session-id path component must equal the gate's own CLAUDE_CODE_SESSION_ID (UUID-shaped), the claude-<uid> component is exact, and scope ends at scratchpad/, so another session's scratchpad, the tasks/ sibling, and anything else under the temp dir still prompt. Other clients never set that variable, so the root is inert for them.
What auto-allows
Each of these upgrades a would-be ask to allow when (and only when) the thing being written resolves under the scratch base.
Write, Edit, MultiEdit, NotebookEdit (and the Codex apply_patch / Gemini / Antigravity write aliases). Every touched path must be under scratch.
mkdir, touch, tee (all targets); cp, mv (destination); chmod/chown/chgrp (the files); sd in-place edits.
> / >> / &> redirects (including quoted targets), curl -o, and wget -O / -P.
What still asks
Excluded by design. Tools whose command sublanguage can run shell or write outside the named target are deliberately left asking, because a scratch target does not bound what they do: sed -i (the e command runs shell, w writes any file), sqlite3 (.shell / .system / .output), zip (-O redirects output elsewhere), and ouch / tar decompression (zip-slip).
Deferred. Tools that need careful per-command parsing before they can be scratch-scoped still prompt for now: tar, ln -s, and git init / clone / worktree.
The boundary
The auto-allow is destination-gated and one-directional. You can write, move, or copy into scratch without a prompt, but moving or copying out of scratch to anywhere else (the project, /etc, ~/.ssh) prompts like any normal write. Reading a file from elsewhere into scratch (cp /etc/x scratch/) is allowed by design: the write lands in scratch, the read is harmless, and nothing leaves the machine.
It only upgrades ask to allow, never relaxes a block. Targets are canonicalized first (symlinks and .. resolved), so a path that escapes the base still gates. A dangerous-path block, a settings.json deny, and the AI-config file guards all still win. On plan mode the file-tool path skips the upgrade entirely. The upgrade is a wire allow, so whether it removes the prompt depends on the client: a true allow on Claude, a fall-through to the approval policy on Codex, and inert on Gemini and Antigravity, where the native engine keeps the stricter decision so scratch writes still prompt.
Setup
Set TOOL_GATES_SCRATCH in your environment. Putting it in the env block of ~/.claude/settings.json makes it ambient: it reaches every Bash call, every subagent, and every workflow agent, and survives context compaction.
{ "env": { "TOOL_GATES_SCRATCH": "/home/you/.cache/tool-gates-scratch" } }
There is no config.toml toggle; relocate the base only via the env var. The literal $TOOL_GATES_SCRATCH token in a command is substituted only while the env var is set: unset, the shell would expand it to nothing, so the gate leaves the token alone and prompts (fully-spelled paths under the default base still match). An override that contains an unresolvable variable makes this root inert (fail closed: nothing resolves under it); the session-scratchpad root above is independent and keeps matching. The gate only removes the prompt, so the other half is instructing your agent to write its throwaway and intermediate files under the canonical path (and to mkdir -p it first) instead of /tmp.