Tmp Folder vs Write_file: The Rule
When the agent writes to /tmp/ vs when to use write_file: long scripts (>300 lines) go to /tmp/, short content uses write_file. The bash heredoc trap and the agent-tool boundary.

The rule in one sentence
Long-form scripts (>300 lines or multi-iteration) go to /tmp/<name>.py and are run via the venv Python. Small content (<300 lines, single-pass) goes through write_file directly. The terminal-tool bash heredoc is a third-class approach for both — avoid.
The boundary is whether the content would survive a tool failure mid-stream. write_file re-sends the whole file on retry; /tmp/ persists across the agent session.
When to use /tmp/
Use /tmp/ for:
- Image-gen batch scripts (
/tmp/gen_batch_N.py) — typically 60-110 lines, run once per batch, persist across the agent session. - Investigation scripts — one-off scripts that look at a problem and surface a result.
- Re-build / repair scripts — a script the agent runs that itself writes files to disk.
- State-tracking scripts — scripts that interact with a process, network, or database across multiple calls.
The convention is /tmp/<descriptive-name>.<ext>:
/tmp/gen_batch18.py— the batch-18 image-gen script./tmp/verify_batch_19.py— the batch-19 wc-verify script./tmp/check_rss_alive.sh— a one-shot RSS liveness probe.
/tmp/ is ephemeral — reboots clear it. None of these scripts are meant to survive a reboot; they’re session-scoped.
When to use write_file
Use write_file for:
- Small content edits (a single sentence, a 5-line paragraph).
- In-tree files (
src/...) — files that live in the repo. - Markdown / docs / config snippets — anything that needs to be canonical.
- Single-pass scripts — under ~300 lines, no iteration expected.
The write_file tool takes the full path + full content. It’s atomic; retries send the whole file again. The tool returns on success or a structured error.
When to use neither (avoid)
Three failure shapes worth knowing:
-
Bash heredoc in the terminal tool. Writing a 200-line Python script via
cat > /tmp/script.py <<EOFin a terminal call is a fragile approach:- The shell truncates or expands
$, backticks, and backslashes if you forget quotes. - The shell limits the heredoc to a single command call; if the call errors mid-stream, the file is partial.
- The agent has no idea what was written (terminal output is opaque for writes).
- The shell truncates or expands
-
Bash echo + quote in a long single line.
echo 'long content with ''quotes' > fileis even worse — escaping rules vary by shell, multi-line content is impossible. -
Embedded
python3 -c "..."with the script as the argument. Functions over 20 lines become unreadable; multi-line scripts are inaccessible.
The terminal tool’s # Bash tool: ... style is fine for short commands. Long-form goes to /tmp/ via write_file.
The exact rule
| Content length / type | Right approach |
|---|---|
Single command (ls -la, curl -I, git status) | terminal tool, inline |
| ≤30 lines script | write_file to /tmp/, then python to run |
| 30-300 lines script | write_file to /tmp/, then python to run |
| >300 lines script | write_file to /tmp/, never inline |
| Edit existing repo file | patch tool (preferred) or write_file |
| In-tree config snippet | write_file to the canonical path |
Anything in /src/, /public/, /tools/ | write_file or patch |
The threshold of 30 lines is conservative; the right call is “longer than fits comfortably in a chat message” goes to /tmp/.
Why >300 lines matters
write_file re-sends the entire content on retry. If the agent’s first send fails (rate limit, transient network), it retries by sending the full content again. With a 700-line script, that’s 70 KB re-sent on retry; with a 30-line script, it’s 3 KB. The model budget on the retry path matters less than the time spent — long content takes longer to send, retry, parse.
Also: long scripts’ error messages are harder to associate with the script. A 700-line script with a NameError on line 423 — finding line 423 means re-reading the script. A 30-line script, the error is closer to the source.
The lifecycle of /tmp/gen_batch_N.py
A typical image-gen script lifecycle:
- Draft. The agent drafts
/tmp/gen_batch_N.pyviawrite_file, then runs it. - Run.
timeout 300 /opt/hermes/.venv/bin/python /tmp/gen_batch_N.py. Exit 0 + 3 PNG+WebP pairs. - Recover. If the run fails, re-read the script in
/tmp/gen_batch_N.pyto understand the failure. The script is persistent. - Clean up. The agent doesn’t clean up
/tmp/; the user does. Don’trm /tmp/gen_batch_N.pyas part of the run.
A 100-line script persisted in /tmp/ is recoverable, reproducible, and auditable. A 100-line script embedded in a bash heredoc is none of those.
The verify
A list of files in /tmp/ should never grow unbounded:
ls -la /tmp/gen_batch_*.py 2>/dev/null | wc -l
# Expect 0-3 (last few batches)
ls -la /tmp/*.py 2>/dev/null | wc -l
# Expect <30 (a few weeks of session-scoped scripts)
If /tmp/gen_batch_*.py has 30+ files, that’s fine — each is small and named. If /tmp/*.py has 100+ files, consider cleaning up. The agent does NOT auto-clean /tmp/; this is operator-managed.
What NOT to do
- Don’t write long scripts inline in a bash command.
python3 -c "...700 lines..."is unreadable. - Don’t use bash heredocs to write scripts. Shell quoting + variable expansion is fragile.
- Don’t write to
/srvor/etcfrom agent code;/tmp/is the agent’s writable home. - Don’t rely on
/tmp/across reboots; ephemeral. - Don’t let image-gen scripts pile up unboundedly — clean up periodically.
Sources
- Filesystem Hierarchy Standard (FHS 3.0)
- ABS companion: Terminal Commands Versus Python
- ABS companion: Search the Codebase Before Fixing Anything
Last verified: 2026-07-14 against today’s image-gen batch scripts at /tmp/gen_batch_*.py.


Submit a take
Have a different read on this? Drop a comment below — your email isn't published, and I read every one. Nothing leaves the site until I approve it.