Background
The budget system (cost / token caps, landed in 0.12.x) prevents runaway spending, but not runaway frequency. A loop bug or a model going in circles can fire hundreds of run_command calls in seconds — fine on cost terms (each call is cheap) but bad for filesystem / disk / spawn pressure, and a real DoW vector when the loop also makes API calls.
OWASP AI Agent Cheat Sheet § 5 cites "max_calls": 100, "window_seconds": 60 as the canonical pattern.
Proposal
Sliding-window rate limiter at the tool-dispatch boundary. Defaults (suggested, not load-bearing):
run_command / run_background: 60 calls / 60s
- All tools combined: 200 calls / 60s
When the limit fires, the tool call returns an error to the model ("rate-limited, slow down"); the next loop tick can retry once the window slides. UI surfaces the throttle state.
Open design questions
This is rfc-tagged — please discuss in the issue before opening a PR:
- Per-tool vs aggregate vs both?
- Sliding window vs token bucket?
- What does the model see — a real error, or a synthesized "wait" instruction the model can comply with?
- How does this interact with the existing budget system — combine, or stay separate?
- Configurable in user config? Per-project override?
Acceptance criteria (post-RFC)
Out of scope
- Cross-session limits (this is per-session)
- Network-level rate limiting (handled by upstream API providers)
References
Background
The budget system (cost / token caps, landed in 0.12.x) prevents runaway spending, but not runaway frequency. A loop bug or a model going in circles can fire hundreds of
run_commandcalls in seconds — fine on cost terms (each call is cheap) but bad for filesystem / disk / spawn pressure, and a real DoW vector when the loop also makes API calls.OWASP AI Agent Cheat Sheet § 5 cites
"max_calls": 100, "window_seconds": 60as the canonical pattern.Proposal
Sliding-window rate limiter at the tool-dispatch boundary. Defaults (suggested, not load-bearing):
run_command/run_background: 60 calls / 60sWhen the limit fires, the tool call returns an error to the model ("rate-limited, slow down"); the next loop tick can retry once the window slides. UI surfaces the throttle state.
Open design questions
This is
rfc-tagged — please discuss in the issue before opening a PR:Acceptance criteria (post-RFC)
ToolRegistry.dispatch(or wherever the boundary lands after design)Out of scope
References
src/core/budget*.tsgit branch -dbypasses review mode #257, fix(shell): demote destructive flags on allowlisted commands #258