Execution Guards
The write guard, argv-only subprocess schema and timeouts that sit alongside the sandbox.
Filesystem write guard
go-pkg/filesystem write APIs (WriteFile, WriteJSON, AppendText, CheckDir) all enforce IsDenied internally. Any agenvoy code that bypasses go-pkg/filesystem and writes via os.WriteFile directly escapes the policy — this is forbidden.
The internal/filesystem package retains only path computation, runtime limits, and domain wrappers. It does not duplicate read/write logic.
Outside $HOME, run_command needs the paths declared up front: the call carries write_paths (absolute paths only), the user approves them with the system password, and only then are they bound read-write into the sandbox for that session. A write to an unapproved path fails with an explicit message, and a permission error on an unbound path outside $HOME gets a hint to re-run with write_paths rather than a bare error the model would misread as an ownership problem.
Subprocess argv-only schema
run_command accepts only argv: string[] (minItems 1) plus optional write_paths and, since v1.0.25, network (boolean, default off). It does not accept a command: string with auto-tokenization. This zero-parsing approach removes shell-injection surface in the agent layer.
At the top level, sudo is rejected (declare write_paths instead), rm is routed to the trash, and cd switches the work directory after verifying the path.
Shell features (pipes, redirects) require an explicit ["sh", "-c", "cmd | pipe"] (or bash -c). That script is parsed with mvdan.cc/sh rather than string-matched, and every command node inside it is checked:
| Rule | Effect |
|---|---|
| Bare command names only | /usr/bin/curl is rejected — the binary must be written as curl |
| No dynamic commands | A command built from a variable or command substitution is rejected outright |
No rm or sudo |
Both are rejected inside sh -c |
| Denied binaries | Anything on denied_command is rejected, inside sh -c as well |
| Shell builtins | A fixed set (cd, echo, test, export, ...) passes without an allowlist entry |
Nested sh -c |
Recursively validated with the same rules; a nested script that is not a static string is rejected |
Timeouts
Every tool carries its own timeout, defaulting to one minute and overridden per tool at registration (open_file 10 s, html_template 30 s, fetch_page and search_web 90 s, generate_audio 5 min, download_file 10 min, generate_image 15 min, run_command 60 min; ask_user has none). Subagent invocations, including slot-wait time, are capped by MaxSubagentTimeoutMin (30 min).
These are package-level values — the environment-variable overrides that used to control them were removed.