Skip to main content
On every ChatCLI startup an isolated scratch directory is created at $TMPDIR/chatcli-agent-<random>/ and exposed to the agent via the CHATCLI_AGENT_TMPDIR environment variable. This solves two recurring pain points:
  1. The agent needs to create a temporary script (e.g. a .sh for a complex patch) but the /coder boundary blocks writes outside the project tree, forcing the agent to pollute the repository.
  2. When a tool result is truncated and ChatCLI saves the full content to disk with the marker [full output saved to /tmp/...], the agent cannot read that file — the path was outside the workspace boundary.
Starting with this release, the session workspace solves both: the agent has automatic read and write permission inside it, and the tool-result-budget overflow files now live there too.

Layout

The <random> suffix comes from os.MkdirTemp — unique per process. This avoids collisions when multiple chatcli instances run in parallel on the same host.

How does the agent know it exists?

The /agent and /coder system prompt automatically receives a block with:
  • The literal scratch path resolved at startup (the agent doesn’t have to expand any variable).
  • Instructions to use $CHATCLI_AGENT_TMPDIR in shell commands when that’s more convenient.
  • Usage pattern for truncation markers: when reading [full output saved to /tmp/chatcli-agent-XXX/tool-results/...], open the file with read_file instead of re-running the original tool call.

Scenario 1 — Create and run a temporary script

In /coder, the model has two ways to stage a script:

Direct path (absolute)

The engine’s validatePath recognises the aux path registered by InitSessionWorkspace and allows the write.

Shell expansion in exec

The engine doesn’t validate paths here because it’s just a command string — the $CHATCLI_AGENT_TMPDIR expansion happens in the child shell, which inherits the variable from the ChatCLI process.
Do not use $CHATCLI_AGENT_TMPDIR in the file argument of write or patch. validatePath runs filepath.Abs but does not expand environment variables — $CHATCLI_AGENT_TMPDIR/x becomes a literal <cwd>/$CHATCLI_AGENT_TMPDIR/x and gets blocked by the normal boundary check. Use the absolute path that appears in the system prompt for that path.

Scenario 2 — Recover the middle of a truncated output

The tool result budget truncates large tool outputs (> 20K chars by default) and saves the full content to tool-results/. The preview returned to the model contains a marker like:
Before this release, that marker was a dead end — the read tool blocked the path because it was outside the workspace. Now the scratch dir and tool-results/ are on the agent’s read allowlist, so the model just opens the file:
And gets exactly the slice it needs, without re-running the original tool call (which would burn tokens again and likely truncate a second time).

Lifecycle


Configuration

To investigate an agent issue after the session ends:
On exit, ChatCLI logs the scratch path and keeps every script and overflow there for you to inspect with ls, cat, grep.

Security

The session workspace does not loosen the agent boundary against sensitive system paths:
  • The scratch dir lives under os.TempDir() ($TMPDIR on macOS, /tmp on Linux), with 0700 permissions on the session root.
  • Validators (engine.validatePath, SensitiveReadPaths.IsReadAllowed) keep enforcing the core protections: blocks on sensitive paths (/etc/shadow, ~/.ssh, ~/.aws/, ~/.gnupg, etc.) and the project boundary.
  • The @webfetch save_to_file confines writes to the scratch dir via filepath.Base + post-resolve check, even if the model passes an absolute path.

/tmp and os.TempDir() allowlisted by default

Starting this release, the entire os.TempDir() and /tmp (when it exists) are added to the read/write allowlist at session init. The practical reason: virtually every modern model, when writing a throwaway script, emits paths like /tmp/check.sh or /tmp/debug-X.py by default. Before, this would trip the boundary check (path "/tmp/check.sh" is outside workspace boundary) and force the model to guess safer paths — leading to silent failures or retries.
Opt-out for strict sandboxing: if you run on a shared host or CI where /tmp is writable by untrusted siblings, set CHATCLI_BLOCK_TMP_WRITES=true and only the session-isolated scratch dir stays accessible:
Expanding to /tmp does not loosen the sensitive-paths block — /etc, ~/.ssh, ~/.aws, ~/.gnupg, etc. remain blocked via sensitivePaths and SensitiveReadPaths. The scope of this change is strictly the OS tmpdir.
Symlinks inside /tmp still go through filepath.EvalSymlinks before allowlist checking — a symlink /tmp/evil/etc/shadow is still blocked by sensitivePaths.

Next Steps

Tool Result Management

How the budget decides what to truncate and where to persist.

Subagent Delegation

Delegate heavy tasks to a subagent with isolated context.

Web Tools

@webfetch save_to_file uses the scratch dir.

Environment Variables

Full list of variables that control the workspace.