Summary
bash.watch_sync_max_ms caps how long a single bash_watch call can block, which is useful for keeping a model's prompt cache warm. However, bash({ wait: true }) bypasses every time cap in the config, so a single call blocks for as long as the command runs. Please add a config setting, for example bash.wait_max_ms, that caps wait: true. When the cap is reached, the command should be promoted to a background task with the usual completion notice, the same way a normal foreground call is promoted after foreground_wait_window_ms.
Why
Anthropic's default prompt cache lasts 5 minutes. Claude Code uses it for subagents, and so do OpenCode setups that mirror Claude Code's cache placement. If no model request happens for over 5 minutes, the next request rewrites the whole context into the cache.
AFT's injected guidance tells agents to use bash({ command, wait: true }) for long commands such as test suites and builds. A subagent then blocks inside that one tool call for the full run, and the cache expires mid-call when the run goes past 5 minutes.
I set bash.watch_sync_max_ms: 270000 specifically so that waits end, and the model takes a cheap step, before the 5-minute cache expires. That works for bash_watch, but wait: true skips it.
Observed (AFT 0.58.2, OpenCode 1.18.x, Claude Sonnet 5.5 subagent)
- The worker called
bash with wait: true, timeout: 900000 to run a Playwright suite.
- The command took 308 s.
- The next model request had
cache_read: 0 and cache_write: 221,505, so the full context was rewritten. Every request before and after it read the cache normally.
- Over two days, 5 of 1,855 tool calls by Sonnet subagents ran past about 5 minutes. Each one was a full cache rewrite of a 150–250K context.
Where it happens in the code (dist/index.js, 0.58.2)
requestedWait = !backgroundDisabled && coerceBoolean(args.wait) (≈ line 42077)
blockToCompletion = subagentForcedForeground || backgroundDisabled || requestedWait (≈ line 42093)
foreground_wait_window_ms is only consulted for non-blocking calls, and the only bound on a wait: true call is the agent's own timeout argument.
- Config keys today (
config.d.ts): foreground_wait_window_ms, watch_sync_max_ms, long_running_reminder_*. None of them limits wait: true.
Proposal
- When the cap is reached, the result reads exactly like today's auto-promotion: a task id and a note that it's still running, plus the existing completion reminder. The agent can then
bash_watch it, and each watch is already capped by watch_sync_max_ms.
- Subagents with
bash.subagent_background: false: background isn't available, so either ignore the cap or document that it doesn't apply.
- Optional: also clamp the agent-supplied
timeout semantics. Today a very large timeout with wait: true means "block up to that long". With the new setting it would still kill at timeout, but stop blocking the turn at wait_max_ms.
Workaround today
Prompt-level only: tell agents to keep each tool call under about 4 minutes and to background long commands. That conflicts with AFT's injected guidance recommending wait: true, so agents follow it inconsistently.
Summary
bash.watch_sync_max_mscaps how long a singlebash_watchcall can block, which is useful for keeping a model's prompt cache warm. However,bash({ wait: true })bypasses every time cap in the config, so a single call blocks for as long as the command runs. Please add a config setting, for examplebash.wait_max_ms, that capswait: true. When the cap is reached, the command should be promoted to a background task with the usual completion notice, the same way a normal foreground call is promoted afterforeground_wait_window_ms.Why
Anthropic's default prompt cache lasts 5 minutes. Claude Code uses it for subagents, and so do OpenCode setups that mirror Claude Code's cache placement. If no model request happens for over 5 minutes, the next request rewrites the whole context into the cache.
AFT's injected guidance tells agents to use
bash({ command, wait: true })for long commands such as test suites and builds. A subagent then blocks inside that one tool call for the full run, and the cache expires mid-call when the run goes past 5 minutes.I set
bash.watch_sync_max_ms: 270000specifically so that waits end, and the model takes a cheap step, before the 5-minute cache expires. That works forbash_watch, butwait: trueskips it.Observed (AFT 0.58.2, OpenCode 1.18.x, Claude Sonnet 5.5 subagent)
bashwithwait: true, timeout: 900000to run a Playwright suite.cache_read: 0andcache_write: 221,505, so the full context was rewritten. Every request before and after it read the cache normally.Where it happens in the code (dist/index.js, 0.58.2)
requestedWait = !backgroundDisabled && coerceBoolean(args.wait)(≈ line 42077)blockToCompletion = subagentForcedForeground || backgroundDisabled || requestedWait(≈ line 42093)foreground_wait_window_msis only consulted for non-blocking calls, and the only bound on await: truecall is the agent's owntimeoutargument.config.d.ts):foreground_wait_window_ms,watch_sync_max_ms,long_running_reminder_*. None of them limitswait: true.Proposal
bash_watchit, and each watch is already capped bywatch_sync_max_ms.bash.subagent_background: false: background isn't available, so either ignore the cap or document that it doesn't apply.timeoutsemantics. Today a very largetimeoutwithwait: truemeans "block up to that long". With the new setting it would still kill attimeout, but stop blocking the turn atwait_max_ms.Workaround today
Prompt-level only: tell agents to keep each tool call under about 4 minutes and to background long commands. That conflicts with AFT's injected guidance recommending
wait: true, so agents follow it inconsistently.