Integration fixes the merge required:
- guard tools after the strict-schema downgrade, so the copy
dataclasses.replace returns is the object the safety wrapper mutates
- await _ctx_client, which main made async for the Caido bootstrap handle
- pass main's extra_files through with the isolated local sources
- keep DEFAULT_SAFETY_MODE alongside main's new report/state imports
- rebuild the committed viewer bundle from the merged frontend sources
- pin the browser-session safety phrase in test_safety_prompt so it no
longer matches unrelated prompt text, and stamp safety_mode on the
workspace-file resume record
- 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
Guarded review was blocking or prompting on any non-empty hard gap even when the
reviewer had already determined the missing evidence was irrelevant — a file the
command only writes (an output that does not exist yet), a benign parser
misclassification, or a data file that is only read. The reviewer's own reason
would say the action is safe, then defer anyway.
- Reviewer prompt: a hard gap is missing evidence, not proof of danger. After
inspecting, the model judges whether the gap could change the action's effect —
allow when it cannot, block when it could hide a dangerous effect it cannot rule
out, and defer only for genuine ambiguity. It no longer blocks or defers merely
because a gap remains.
- Remove the code override that forced an incomplete-evidence "allow" into a defer
(interactive) or block. The reviewer's verdict now stands, gated by the existing
confidence threshold: an unsure allow still defers to the human.
Headless runs are unchanged — incomplete evidence still fails closed before the
reviewer, preserving the autonomous guarantee. Forced inspection and the
inspection-failure guard remain.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
repeat_request replays a captured HTTP request with optional modifications.
Its effective bytes are fully determined before dispatch — the captured request
is immutable and the modification overlay is deterministic — so it no longer
needs a blanket deterministic block.
- Extract resolve_effective_request in the proxy tool so the tool and the safety
layer build the {method, url, headers, body} from the same function; the
reviewed request is byte-for-byte the one that is sent.
- compile_network_evidence freezes that request as an evidence packet; the
runtime routes repeat_request through the reviewer (and human approval when
guarded+interactive), sending only if allowed and failing closed when the
request cannot be resolved.
- Approval prompts now carry the real tool name (via _ExecReview.tool_name), so
a deferred repeat_request no longer shows as exec_command.
- Reviewer prompt notes the replayed-request shape.
Tests cover allow/block/unresolvable/deferred paths and the packet shape.
Full Python suite, ruff, and mypy strix/ pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Resolve conflicts from main's mount-prompt refactor against the safety
approval UI:
- update.go / vulnerabilities.go: keep the variadic cornerPrompt + cornerButton
needed for the three-button safety prompt while adopting main's mount changes
(Mount/Skip labels, mountPromptBounds + labelHitAt, direct answerMountConfirmation).
- Reconcile main's new runner-lifecycle tests (interrupt, teardown) with the
now-default guarded mode by running them with safety off, matching their intent.
Full Python (1168) and Go suites, ruff, and mypy strix/ pass on the merge.
Engine + integration:
- Reviewer inspection now surfaces the real frozen source of an already-frozen
workspace script/dependency instead of an empty string, so workspace-resident
scripts resolve without a needless human defer.
- Guard effectful static tools via an explicit, documented set plus the SDK's
per-tool needs_approval signal; give the exec/stdin wrappers the same
idempotency guard as their sibling wrappers.
- Centralize DEFAULT_SAFETY_MODE and share one resume safety-mode rule between the
CLI and runner so the two cannot drift; type InspectionContext.runner, reuse
RUNTIME_STATE_DIR_NAME, and drop a dead workdir parameter and a write-only field.
TUI approval experience:
- Approve All drops the run into dangerous mode: it approves the pending call and
turns review off for the rest of the run, with a standing "review off" status flag.
- The status row shows the owning agent as paused while it waits on a decision.
- Redesigned prompt: a risk + tool header, a collapsible command/reason preview
that expands (e) and scrolls, and no internal digest, agent, or request ids.
Full Python (1138) and Go suites, ruff, and mypy strix/ pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A scan runs dozens of agents concurrently, each holding a sandbox session, a
browser session, a model client, and a SQLite handle. At the common 1024 soft
file-descriptor limit that budget is exhausted around ~32 agents, after which
SQLite can no longer open agents.db and agents fail en masse with
"unable to open database file" (an fd-exhaustion symptom, not DB corruption).
Measured directly: fd usage scales ~linearly with concurrent agents and hits
1024 at 32 agents; fds are reclaimed as agents finish, so this is a ceiling
problem, not a leak. Strix never set its own limit, inheriting whatever the
launching shell had (often 1024).
Raise RLIMIT_NOFILE toward the hard cap at scan start (best-effort, idempotent,
POSIX-guarded; warns when the hard cap is itself too low to lift without a
privileged operator). Runs no longer depend on the operator setting ulimit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>