* feat(cli): add strix login for managed platform sign-in (device flow)
* feat(cli): add --scopes flag to strix login
* docs: document strix login and managed billing in README, AGENTS, docs, and managed skill
* fix(cli): handle malformed login responses and credential file failures
* fix(cli): reject sign-in responses without an API token
* feat(login): interactive workspace and scope selection with presets
* fix(login): reject malformed API token values in sign-in responses
* fix(login): skip the scope prompt when stdin is not a terminal
* fix(login): tolerate malformed selection containers and remove unreadable credential files on logout
* fix(login): treat overflowing timing values as invalid
* fix(login): show the configured platform host in the sign-in banner
* fix(login): bound device flow timing values and clean up unreplaced secret temp files
* feat(cli): add the strix cloud command surface for the managed platform
* feat(cli): manage workspaces and hosted onboarding links from strix cloud
* fix(cli): report a leftover temporary secret file instead of hiding it
* feat(cli): pass a Stripe payment method to the top-up wallet client
* docs(cloud): recommend the Stripe agent wallet as the default payment path
* fix(cloud): preserve API auth during MPP payment
* fix(cloud): drop knowledge query and settings commands removed from the API
* fix(cloud): align agent commands with API contracts
* fix(cloud): send required PR review integration fields
* fix(cloud): preserve scopes when switching workspaces
* fix(cloud): make session command help non-destructive
* feat(cloud): improve human navigation and output
* feat(cli): add native shell completions
* feat(cloud): tailor human list and detail views
* feat(cloud): upload local source for managed scans
* fix(cloud): infer scan type from local targets
* Add agent-friendly managed cloud CLI
* Harden cloud CLI type boundaries
* Clarify cloud test user MFA options
* Correct cloud vulnerability status guidance
* Clarify chat file path handling
* Allow signed storage upload URLs
* Fix provider token request handling
* Improve cloud CLI human list views
* Make cloud CLI workflows actionable and safe
* Make cloud workspace switching session-safe
* Preserve CLI session metadata in JSON output
* Remove preview protection bypass plumbing from cloud CLI
* 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
* fix(llm): cap the tool calls one assistant response may queue
* fix(llm): cap the subscription backend's responses too
---------
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
A tool call for a name Strix does not register raised ModelBehaviorError
from the SDK turn resolver, which nothing retries: the root agent's raise
tore down the whole scan and a sub-agent died before its status was set.
Opt into the SDK's tool_not_found_behavior="return_error_to_model" so the
unknown call comes back as a tool result and the agent self-corrects.
The setting landed in openai-agents 0.19.0, which requires openai>=2.45,
so both pins move.
Some OpenAI-compatible gateways don't support Server-Sent Events (or
deliver them unreliably), but the SDK run loop Strix uses only issues
streamed requests, so such a gateway fails every turn. Add an opt-in
LLM_DISABLE_STREAMING setting that wraps the resolved model in
_NonStreamingModel: each turn makes one non-streaming get_response and
replays the completed result as a single terminal stream event, so tool
calls, usage, and the rest of the agent loop are unchanged. Subscription
(ChatGPT) models are always streamed and are not wrapped.
cryptography 49.x ships arm64-only macOS wheels (no universal2), forcing the
Intel macOS (macos-x86_64) release runner to build from sdist under
`uv sync --frozen`. Pin to 48.0.1, which still clears GHSA-537c-gmf6-5ccf
(fixed in 48.0.1) and provides a macosx_10_9_universal2 wheel.
Resolves GHSA-537c-gmf6-5ccf (vulnerable OpenSSL in cryptography wheels,
fixed in 48.0.1) and CVE-2026-59885 / CVE-2026-59886 (pyasn1 DoS via
OBJECT IDENTIFIER / REAL decoding, fixed in 0.6.4).
* fix(deps): cap openai<2.45 and add litellm[proxy] so fresh installs can run
* chore(deps): sync uv.lock with openai cap and litellm[proxy]
Regenerate the lockfile so locked/frozen installs pick up the openai<2.45 cap and litellm[proxy] extras (fastapi, orjson, ...); remove inline dependency comments.
Co-Authored-By: Ahmed Allam <ahmed39652003@gmail.com>
---------
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
* feat: add bedrock + vertex optional extras with install docs and import hints (#574)
Declare [project.optional-dependencies] with vertex (google-auth) and
bedrock (boto3) extras so "strix-agent[vertex]" / "strix-agent[bedrock]"
install the provider SDKs. Add an Installation section to the Bedrock docs
mirroring Vertex, and a _provider_import_hint helper in warm_up_llm that
surfaces a pip-install hint when a provider dependency is missing.
Fixes#574, #573
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(providers): use pipx in install hint to match docs
A pipx-installed strix can't add an extra with 'pip install' (wrong env);
mirror the documented 'pipx install "strix-agent[...]"' command. Addresses
Greptile review.
* fix: resolve pre-commit check failures
- Change RuntimeError to TypeError for type validation in report/writer.py
- Update pyupgrade to v3.21.2 for Python 3.14 compatibility
* feat(cli): add --max-budget-usd flag
Raises BudgetExceededError in ReportUsageHooks after each LLM call when
accumulated cost reaches the limit, with clean "stopped" status and
child-agent cancellation in non-interactive mode.
* test: add budget enforcement unit tests
7 tests covering no-budget, under-budget, at-limit, over-limit, error
message content, None report state, and exception hierarchy.
Also adds pytest/pytest-asyncio to dev deps and a mypy override for tests.
* fix(budget): validate positive budget and check the live cost ledger
Two hardening fixes for --max-budget-usd enforcement:
- Reject non-positive budgets. ReportUsageHooks now raises ValueError for
max_budget_usd <= 0, and the CLI validates the flag via a custom argparse
type so '--max-budget-usd 0' fails fast with a friendly message instead of
silently killing the scan on the first model response.
- Read the live cost. The budget check now reads ReportState.get_total_llm_cost()
(the live ledger) instead of the persisted run-record snapshot, so it stays
accurate even when a usage save fails after a model call.
* fix(budget): stop the entire scan deterministically when the limit is hit
Previously a BudgetExceededError was handled per-agent: it was swallowed in
interactive mode (the loop kept waiting), a child's error escaped its detached
task as an unretrieved-exception warning, the parent was never released from
wait_for_message, and the stop was logged at ERROR with a traceback as if the
agent had failed.
Replace that with a single scan-wide signal on the coordinator:
- AgentCoordinator.trigger_budget_stop() sets a flag and wakes every parked
agent; wait_for_message returns as soon as the flag is set.
- The run loops check coordinator.budget_stopped and raise to exit cleanly,
marking themselves 'stopped'. The root's exception reaches run_strix_scan's
handler, which cancels descendants and tears the scan down once; child
exceptions are swallowed in their detached task.
- The budget stop is logged at INFO, not as a failure.
This is deterministic regardless of tree depth or which agent first sees the
limit, fixing the interactive/TUI hang where a deep agent's stop never reached
a parked root. Also re-raises BudgetExceededError explicitly in the stream
handler so it can't be mistaken for the LiteLLM 'after shutdown' race.
* fix(budget): treat a budget stop as a clean stop in the TUI
Add an explicit BudgetExceededError handler in the TUI scan thread so that, if
the error ever reaches it, the budget stop is logged as a graceful stop rather
than surfaced as a red scan error by the broad 'except Exception'. The runner
normally absorbs the error and returns cleanly, so this is defensive depth for
a money-spending feature.
* docs(cli): document --max-budget-usd behavior and limitations
Clarify that the budget is cumulative across all agents, checked after each
model response, that the scan stops cleanly (not as a failure), that the value
must be > 0, and that spend can slightly overshoot due to in-flight calls and
best-effort cost estimation.
* Apply suggestions from code review
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
---------
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Register a litellm.success_callback that captures kwargs['response_cost']
into a new observed-cost bucket on LLMUsageLedger. record() skips the
tokens-times-registry estimate for LiteLLM-routed models so we do not
double-count with the callback; OpenAI direct routes keep estimating
since LiteLLM is not invoked for them. Per-agent attribution for
LiteLLM-routed calls is apportioned by token share at to_record() time.
A scan that crashes or is stopped can now be resumed by re-invoking
``strix`` with the same ``--run-name``. Resume is implicit — presence
of ``{run_dir}/bus.json`` triggers it. To force a fresh start, delete
the run dir.
What survives a process restart with the same scan_id:
* Root agent's LLM history — already worked (root SDK SQLiteSession).
* Every non-terminal subagent's LLM history — new. ``create_agent``
now opens SQLiteSession(session_id=child_id,
db_path={run_dir}/sessions/{child_id}.db) per child and passes it
to ``run_with_continuation``.
* Bus topology — new. ``AgentMessageBus`` gains snapshot/restore/
_maybe_snapshot async methods plus a ``metadata`` field that holds
per-agent {task, skills, is_whitebox, scan_mode, diff_scope}.
``register``, ``finalize``, ``park``, and ``mark_llm_failed`` each
call ``_maybe_snapshot`` to atomically persist the bus to
{run_dir}/bus.json (tempfile + Path.replace).
* Vulnerability reports — new. ``ScanArtifactWriter._write_
vulnerabilities`` now also writes ``vulnerabilities.json``
(atomic). ``Tracer.hydrate_from_run_dir`` reads it on resume so
new vuln-NNNN ids don't collide with prior on-disk files.
What does not survive: the sandbox container itself (fresh per
process), so ``/workspace/scratch`` and Caido state are lost.
``/workspace/sources`` re-mounts from the host so source code is
unchanged.
``orchestration/scan.py:run_strix_scan`` does the actual resume:
1. Resolve run_dir up front; if bus.json exists it's a resume.
2. Acquire {run_dir}/.lock (fcntl.flock) so a second strix process
can't run concurrently on the same scan_id.
3. ``bus.set_snapshot_path(...)``, ``tracer.hydrate_from_run_dir()``.
4. On resume: load + bus.restore, find root_id from snapshot (the
agent with parent_of[id] is None), spawn the sandbox, skip the
root's bus.register (already in snapshot).
5. ``_respawn_subagents`` walks every agent with status in
running/waiting/llm_failed: reopens its SQLiteSession, rebuilds
the child agent via the captured factory, builds run config /
context, asyncio.create_task the run with initial_input=[] so
the SDK replays from session. Per-child failure (missing/corrupt
DB, factory raises) finalizes that child as crashed and continues.
6. Open root SQLiteSession at the same path, run the root with
initial_input=[] on resume (or the formatted root task on a
fresh run), and let SDK replay drive the next turn.
7. ``finally``: close every per-agent session, take a final
snapshot, tear down sandbox, release the lock.
HARNESS_WIKI.md updated with the new run-dir layout (sessions/,
bus.json, vulnerabilities.json, .lock) and the resume contract.
Net: +500 LoC across 7 files. No new deps.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>