`failed` means an agent has exhausted its own recovery and parks until a human
tells it to go again. That is the right design; the gate is per-agent and only
the addressed agent's is lifted, while in practice the user can only reach the
root. So the word never arrives for anything below it and a child that dies
stays dead for the rest of the scan.
A message from the user is that word for all of them. It sits beside the
budget-pause release directly above it, which already treats a user message as a
scan-wide signal with the same `exclude` for the agent being addressed.
Nothing else revives an agent, so there is no runaway to bound and no attempt
budget to keep: the person deciding whether to try again is the limit. Revival
also never asks how an agent died, only that it did.
This replaces an automatic revival keyed on a turn landing somewhere in the
scan, which needed a budget precisely because no human was in the loop, and
before that a check that recognised a provider's billing rejection by its
response body. `execution.py` is untouched again as a result.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Recovery was keyed on recognising a provider billing rejection by its response
body. That is a guess about one provider's prose: reword the message, add a
provider, and detection silently fails back to the original bug. It also had to
be right about the cause, when the cause was never the point.
The stranding is general. A failed agent is gated behind a user message and the
user can only realistically reach the root, so any child that dies stays dead for
the rest of the scan - however it died. Credit exhaustion was only conspicuous
because it took eighteen agents down at once.
So revive on evidence the scan works rather than on a theory of what broke: a
turn that lands anywhere buys every casualty another attempt, bounded by a
budget the agent refunds by landing a turn of its own. That budget is what a
cause analysis was standing in for, and it holds for causes nobody enumerated.
It joins the bounded-recovery limits already governing retries, compaction and
tool nudges, all of which have run by the time an agent reaches this state.
Reviving off live status rather than a marker set at failure time also removes a
race: a marker could be cleared by a recovery that overtook the agent recording
its own status, stranding it for good.
A billing 400 that LiteLLM re-wraps as a 500 mid-stream now spends the transient
retry budget before failing. That is the honest reading - a 500 is retryable by
contract, and only the prose said otherwise - and it costs bounded wall-clock,
no tokens, and self-heals through revival.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
An exhausted provider balance fails every in-flight agent within seconds, and
a failed agent is gated behind a user message. The user can only realistically
message the root, so the rest of the fleet stayed dead for the life of the scan
even after credits were topped up, and the header kept reporting a failure that
had already resolved.
Treat a billing rejection as its own class of failure:
- Detect it from the response body across the whole exception chain. The status
code is not a signal: the same rejection arrives as a 400 pre-stream and as a
LiteLLM-rewrapped 500 mid-stream, and the 500 shape was being replayed through
the full transient-retry budget on a failure no retry can fix.
- Tag the runtimes it stops, so the first call that succeeds again lifts their
human-wake gate and hands each agent a note explaining the gap. Their sessions
and tasks are intact throughout - only the gate kept them parked.
- Report it as one actionable sentence and one log line per agent rather than a
LiteLLM traceback per agent.
Unlatch the TUI alongside it. `scan_state` had no path back from "failed" and
`controller.error` was never cleared, so a resolved error stayed on screen for
the rest of a working scan; an agent's `error_message` was likewise write-only,
pinning it to a healthy agent. An unchanged error is now announced once rather
than once per retry, since a revived agent reads as "running" the instant it is
woken and again the instant it dies.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Treat literal 'null'/'none' strings as absent for optional tool args
Models routinely pass the literal string "null" or "none" instead of
omitting an optional argument. Taken at face value it becomes a filter
that matches nothing, so tools like list_notes / list_reports /
list_requests silently return no results.
Coerce such values to None in the central argument-coercion layer, but
only for parameters the schema allows to be null (or that are absent from
a declared "required" list), so required strings keep the literal value.
The list/filter helpers normalize the same values too, so a direct call
can't regress.
* Limit nullish coercion to query tools and keep literal tags
A literal "null"/"none" is only a mistake where the argument is a filter, so
gate the coercion on read-only query tools; a tool that writes keeps the value,
which stops update_note(content="none") from being read as "leave unchanged".
Stop dropping nullish entries from a notes tag filter too: tags are free-form,
so a literal "none" tag stays filterable and mixed tag queries keep every
branch.
* add a generic MCP client and a config for connecting MCP servers
* Add MCP docs and CLI polish: docs page, startup connect summary, --mcp-config flag, compact tool output
* Add MCP connection notes and per-run selection; clean up on cancel and dedupe names
* Show errored MCP tool calls as failed in the TUI
* Sanitize namespaced tool names so model APIs accept them
* Show MCP tool calls distinctly in the terminal and the run viewer
* Say what MCP servers are worth connecting for
* Correct the notes docstring to match how notes reach the agent
* keep the mcp tests from reading your shell's STRIX_MCP_* vars
- Remove --mount from two skills: the flag does not exist in the CLI. Local
paths are mounted writable when passed with -t.
- Document --target-list, --scope-mode, --diff-base, and OpenAPI/Postman
targets, so agents stop putting spec URLs in --instruction prose.
- Add the application-security-testing skill as the entry point for
whole-product AppSec requests, routing each asset to the right workflow.
- Drop contractions and Latin abbreviations across the skill prose.
* add extra-files plumbing so orchestrators can drop single files into the sandbox workspace
* reject extra-file paths that collide with a local source tree
* add --workspace-file so CLI users can place files in the sandbox workspace
* reject repeated and control-character workspace paths
* revalidate persisted workspace files when resuming a run
* drop the workspace-file size limit