Skip to content
DocsPermissions & security
On this page

Execution budgets

Budgets are the limits that stop one command, script or batch of child agents from running forever or taking over your machine. By default a shell command has two minutes, four child agents run at once, and a child agent cannot start its own. Change them when a build needs longer, or when you want fewer things running at once.

A budget is not a security boundary. It bounds a command that hangs or loops; it does not stop code that is trying to do harm.

Change a budget

Put the settings under execution in haarness.json: ~/.config/haarness/haarness.json for all projects, or haarness.json or .haarness/haarness.json in one project. A project value replaces only the settings it names.

{
  "execution": {
    "shell_timeout_ms": 600000,
    "subagent_concurrency": 2
  }
}

In config.toml, the same keys go under [execution]. Unknown keys are an error.

Why did my command stop after two minutes?

A shell command the agent runs has two minutes by default. The agent can set a different limit on a single command. To change the default, set shell_timeout_ms; 0 removes the limit.

When the limit is reached, the command and every process it started are stopped. Without a limit, Esc Esc in the terminal UI, or stopping the turn in Desktop, still stops it.

Where did the rest of the output go?

When a command prints more than 50 KiB or 2,000 lines, the full output is saved to a file. The agent sees the end of it and the file's path, and can read the rest.

How many child agents run at once?

Four at a time, at each level. By default a child agent cannot start children of its own.

To Set
Run fewer child agents at once subagent_concurrency to a smaller number
Let child agents start their own children subagent_depth to 2
Stop the agent from starting child agents subagent_depth to 0

Stopping a turn stops all of its child agents too.

What runs at the same time?

Reads, file listings, searches and web fetches run together, up to read_parallelism at a time. Child agents started together run side by side, up to subagent_concurrency. Edits, shell commands, MCP tools and everything else run one at a time, in the order the agent asked for them.

All settings

Setting Default Means
shell_timeout_ms 120000 Shell command limit; 0 means none
subagent_concurrency 4 Child agents running at once, per level
subagent_depth 1 How many levels of child agents; 0 turns them off
read_parallelism 8 Reads and searches run together
media_max_bytes 20971520 Largest image, PDF, audio or video the agent reads (20 MiB)
code_timeout_ms 60000 Time limit for a script the agent writes; 0 means none
code_max_calls 100 Tool calls one such script may make; 0 means no limit
code_max_source_bytes 262144 Largest such script; 0 turns the check off
plan_read_tools [] Extension tools the plan agent may use

subagent_concurrency, read_parallelism and media_max_bytes must be greater than zero.

The code_* settings apply to the execute tool, where the agent writes a short JavaScript program that calls MCP and browser tools. It needs bun on your PATH.

plan_read_tools lists exact extension tool names, such as ext__code_search__query, that you have checked only read. Wildcards are refused. The plan agent can then use them.

Limit the number of tool rounds

A turn can call tools as many times as it needs. To cap it:

{
  "tools": { "max_rounds": 64 }
}

When a turn reaches the cap, its tools are switched off and the model is asked to sum up. A custom agent's own step limit takes precedence.

Extension limits

Extensions have their own limits, in extensions.json next to your other configuration (or .haarness/extensions.json in a project):

{
  "enabled": true,
  "timeout_ms": 30000,
  "tool_timeout_ms": 120000,
  "payload_max_bytes": 2097152,
  "entries": []
}
Setting Default Means
timeout_ms 30000 Default limit for every step; 0 means none
init_timeout_ms timeout_ms Loading the extension
hook_timeout_ms timeout_ms Each hook it runs
tool_timeout_ms timeout_ms Each tool call
payload_max_bytes 2097152 Largest message to or from it (2 MiB)

When a call times out or you stop it, the extension is stopped and the call is not retried. Its tools fail until you reload or restart Haarness. Return large results as files instead of in the message.

Hook limits

A command hook has 60 seconds by default. Set timeout (in seconds, 1 to 600) on the hook to change it.