guide · computers

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.

July 14, 2026 · By Alastair Fraser

A friendly retro robot stands at a three-section sorting bin labeled /tmp/ (long scripts in jars), write_file (small files in envelopes), and AVOID (a messy pile of bash heredoc paper). A small human figure on the right places a long script into /tmp/ and a small note into write_file.

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:

  1. Bash heredoc in the terminal tool. Writing a 200-line Python script via cat > /tmp/script.py <<EOF in 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).
  2. Bash echo + quote in a long single line. echo 'long content with ''quotes' > file is even worse — escaping rules vary by shell, multi-line content is impossible.

  3. 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 / typeRight approach
Single command (ls -la, curl -I, git status)terminal tool, inline
≤30 lines scriptwrite_file to /tmp/, then python to run
30-300 lines scriptwrite_file to /tmp/, then python to run
>300 lines scriptwrite_file to /tmp/, never inline
Edit existing repo filepatch tool (preferred) or write_file
In-tree config snippetwrite_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:

  1. Draft. The agent drafts /tmp/gen_batch_N.py via write_file, then runs it.
  2. Run. timeout 300 /opt/hermes/.venv/bin/python /tmp/gen_batch_N.py. Exit 0 + 3 PNG+WebP pairs.
  3. Recover. If the run fails, re-read the script in /tmp/gen_batch_N.py to understand the failure. The script is persistent.
  4. Clean up. The agent doesn’t clean up /tmp/; the user does. Don’t rm /tmp/gen_batch_N.py as 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 /srv or /etc from 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

Last verified: 2026-07-14 against today’s image-gen batch scripts at /tmp/gen_batch_*.py.

Sources

#tmp#write-file#hermes#boundary#convention

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.

Your email address will not be published. Required fields are marked.