Commit graph

178 commits

Author SHA1 Message Date
alex s
de730119f0
feat(cli): strix cloud — managed platform CLI (login, scans, billing, and the rest of the API) (#1177)
* 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
2026-09-01 14:39:34 -04:00
devin-ai-integration[bot]
608ef4a37b
Make MCP connections survive transient transport failures (#1184) 2026-09-01 08:11:43 -07:00
Ahmed Allam
944274e12f fix(runtime): remove the extra-file staging dir on cleanup and failed bring-up 2026-09-01 16:54:20 +03:00
Ahmed Allam
eeca404716 fix(runtime): stage extra-file bind mounts under the temp dir so remote docker daemons can resolve them 2026-09-01 16:54:20 +03:00
oyasumi
1df67c52e2
fix(viewer): harden PDF report rendering (#1192)
* fix(viewer): harden PDF report rendering

* test(viewer): cover crossed markdown emphasis

---------

Co-authored-by: oyasumi <oyasumi@kantilabs.xyz>
2026-08-31 20:22:33 -04:00
alex s
3c767cdd47
csv injection hardening (#1203)
* fix(report): neutralize CSV formula injection in vulnerabilities.csv

write_vulnerabilities() wrote finding titles straight into vulnerabilities.csv.
The csv module escapes CSV syntax but has no notion of spreadsheet formula
triggers, so a title beginning with =, +, -, @, tab or CR reached the cell
intact and was evaluated when a human opened the file (CWE-1236).

That input is attacker-influenced by design: Strix scans untrusted targets and
the agent quotes target content verbatim into finding titles, so a scanned page
can dictate a cell's literal contents. _validate_required_text only checks the
title is non-blank.

Add csv_safe() and apply it to every cell written. A value starting with a
formula trigger is prefixed with an apostrophe, the standard mitigation:
spreadsheets render the rest as literal text and hide the apostrophe.

This follows the module's existing safe_fence() precedent, which already guards
the markdown path against the same class of attacker-influenced content.

Adds regression tests covering the six trigger characters, that the payload
survives intact behind the guard, and that benign titles are untouched.

* report: single-line titles, exact CSV bytes, accurate csv_safe docstring

Strip control characters from finding titles at the ReportState choke point so
the guard in the CSV writer is defense-in-depth rather than the only layer, and
write artifacts with newline="" so the CSV's own \r\n terminators are not
rewritten to \r\r\n on Windows.

* report: normalize hydrated titles on resume

* report: rewrite finding markdown when resume cleans its title

---------

Co-authored-by: itzzdev09 <devved90@gmail.com>
2026-08-30 23:36:16 -04:00
0xallam
0a6e8b01bf Fix user message retry lifecycle and TUI sync 2026-08-28 23:46:49 +03:00
Ahmed Allam
1f3f9b31ae fix(report): keep strix.report import-light so it never races the warm-up thread into the agents SDK graph 2026-08-28 20:02:33 +03:00
devin-ai-integration[bot]
cf179d564e
fix(llm): bind dedupe credentials to a provider; send reasoning=max via extra_body (#1187)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-08-28 09:27:57 -07:00
devin-ai-integration[bot]
583af23d9a
fix(llm): only attach prompt-cache points on routes LiteLLM serves (#1186)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-08-28 09:26:57 -07:00
yoni-at-strix
717ffc8f4c
Isolate MCP connections per task and surface connection status in the UIs (#1181) 2026-08-27 14:10:44 -07:00
yoni-at-strix
cbb0f57058
Reach MCP tools on demand instead of registering every one (#1175) 2026-08-26 16:31:08 -07:00
Ahmed Allam
8b655de615 Mirror the run's threat models into its state dir so resume keeps them 2026-08-27 01:36:47 +03:00
Ahmed Allam
7d8d71beea Scope threat models to the current run instead of caching them on disk 2026-08-27 01:36:47 +03:00
devin-ai-integration[bot]
bfaaa904f2
fix(update): re-exec runs the new binary after self-update (endless update-prompt loop) (#1168)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-08-25 15:13:35 -07:00
alex s
187f41f36f
Treat literal 'null'/'none' strings as absent for optional tool args (#1164)
* 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.
2026-08-25 13:21:12 -04:00
yoni-at-strix
f4ef8867f6
Add MCP server support (#1137)
* 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
2026-08-24 14:00:16 -04:00
devin-ai-integration[bot]
391d81bea7
feat(agents): evidence discipline, and coverage as a first-class artifact (#961)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-08-24 03:34:09 -07:00
devin-ai-integration[bot]
1c499c5b2d
perf: bootstrap Caido concurrently with the scan start (#1143)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-08-21 12:09:59 -07:00
devin-ai-integration[bot]
1ce43d1b94
perf: take heavy imports off the startup path and pre-warm them in the background (#1141)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-08-20 20:24:08 -07:00
RAJVARDHAN PATIL
e152c4c7c0
fix(report): raise RuntimeError on non-object run.json (fixes #1109) (#1116) 2026-08-20 13:41:04 -07:00
oyasumi
deb2057e20
fix(tui): preserve cost when state is truncated (#1086)
Co-authored-by: oyasumi <oyasumi@kantilabs.xyz>
2026-08-20 13:36:01 -07:00
Alex Schapiro
d6f2218756 Drop strict tool schemas on Claude routes 2026-08-20 23:12:23 +03:00
oyasumi
6f88b7d7d5 Require viewer session for run data 2026-08-19 15:25:57 -04:00
oyasumi
8d3693df8c Expose viewer host option 2026-08-19 15:25:57 -04:00
alex s
8ede419dcc
handle resume tokens gracefully (#1097)
* Fix telemetry deltas for resumed runs

* Fix resumed telemetry duration
2026-08-17 16:55:27 -04:00
Ahmed Allam
a46a60cf6a feat(reporting): require contextual CVSS and usage evidence on dependency reports 2026-08-17 14:35:21 +03:00
Ahmed Allam
e442db9c93 Contextual CVSS as a full 8-metric breakdown, computed like a normal finding 2026-08-17 13:03:41 +03:00
Ahmed Allam
9c0d30a0d0 reporting: require the source-to-sink trace in reachability evidence, not just CVSS reasoning 2026-08-17 13:03:41 +03:00
Ahmed Allam
99e2d5d826 reporting: drop per-metric contextual CVSS reasoning, keep the summary 2026-08-17 13:03:41 +03:00
Ahmed Allam
310f310e28 feat(reporting): contextual CVSS environmental metrics on dependency reports 2026-08-17 13:03:41 +03:00
yoni-at-strix
8551339130
feat: place caller-provided files into the sandbox workspace (extra_files, --workspace-file) (#1085)
* 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
2026-08-14 16:43:08 -04:00
Alex Schapiro
8ca0c4a9b8 Fix LiteLLM cost model resolution 2026-08-12 17:26:00 +03:00
devin-ai-integration[bot]
174c16fa26
fix(llm): send OpenRouter app attribution on the request itself (#1045) 2026-08-10 11:24:02 -07:00
Ahmed Allam
649a2e2140 fix(llm): omit parallel_tool_calls on tool-less requests 2026-08-09 15:44:16 +03:00
Ahmed Allam
06b158d1fa
fix(runner): settle child agents before closing sessions at wind-down (#1025) 2026-08-08 18:17:58 -07:00
Ahmed Allam
c29eb73c7f
fix(tools): coerce an empty-string list/dict argument to an empty container (#1024) 2026-08-08 16:58:30 -07:00
Ahmed Allam
72833b8e43
fix(runner): resume after a user interrupt instead of failing (#1023) 2026-08-08 16:44:12 -07:00
Ahmed Allam
1117ba6d4a
fix(sessions): open a sqlite connection per operation, not per thread (#1022) 2026-08-08 16:20:01 -07:00
Ahmed Allam
53e4658d88
fix(todo): stop a todo plan failing on priority or duplicates (#1021) 2026-08-08 15:18:48 -07:00
Ahmed Allam
58df71d3db
fix(agents): let an agent wait on what it already said (#1020)
* let an agent wait on what it already said

An agent that answers in plain text is nudged to call a tool, and the only tool
that hands control back takes a required message. So it says the same thing
twice: once as text the user has already read, once as the argument it had to
supply to stop. Seen on a run whose whole instruction was "hi" - a greeting, then
the same greeting again through respond_to_user.

message is optional now. The nudge arms the tool with the text that was
delivered and says not to repeat it, so an agent that has said its piece can park
on it with an empty call. Anything it does want to add it passes normally.

Parking still cannot leave the user on silence: an empty call is refused unless
something was actually said, and the arming is single use - execution clears it
as soon as a turn ends any other way.

The interactive prompt now also says to answer and stop in one respond_to_user
call, which is what avoids the nudge in the first place.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* drop the worked example from the interactive prompt

"the user greeted you, asked something you can answer outright, or you need a
decision" was the run I had been reading, written into a rule that holds
whatever the reason. The rule is that replying and stopping is one call; listing
occasions only invites the model to check whether this is one of them.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* drop the arming flag; an empty message just waits

Passing the delivered text from execution into the tool, and refusing an empty
call without it, was machinery guarding against an agent parking having said
nothing. That leaves the user looking at "waiting for your reply" with a cursor
in front of them - they type. It does not need a mechanism.

What is left is the default on message, and the nudge saying the text already
landed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* only offer waiting on words that were written

The nudge told every agent its text had already been delivered, but it fires
whenever a turn leaves the agent running, and a turn can end with no tool call
and no text at all - _final_output_preview has carried <none> and <empty>
branches all along. An agent that said nothing was being invited to wait on an
answer the user never received, leaving them at a bare prompt.

It now reads the turn: waiting on what was said is offered only when something
was, and otherwise the agent is told plainly that the user has read nothing and
to send its message.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* leave the continuation nudge alone

Rewording it meant asserting from the outside whether the agent had spoken, and
the nudge fires whenever a turn leaves the agent running - text or no text. The
agent knows which it did without being told, so the guidance belongs in its
prompt, where the condition is its own to read.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* say it in the nudge, where the agent is reading

An agent stranded by the nudge reasons off the nudge. Told only to call
respond_to_user, it supplies a message, and since it has just answered in plain
text that message is the same answer again. The system prompt saying otherwise
sits thousands of tokens earlier and loses.

The clause goes on the line the agent acts on: call respond_to_user, with no
message if it has already said it. That reads true whatever the turn did,
including one that produced no text, because the agent is the one who knows
which — nothing here has to work it out from the outside.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-09 00:57:16 +03:00
Ahmed Allam
0b9e029a5d
test(tui): correct the nudge the internal-turn test asserts (#1016)
* correct the nudge the internal-turn test asserts

The test expected "ended the autonomous Strix run", which strix.core.execution
does not inject; it says "ended the autonomous run". The classifier was right and
the test was not, so the suite failed on main while the behaviour it guards was
fine.

The sentence is written inline in another module and copied by hand into the
classifier and again into the test, which is how it drifted. A second test now
reads it back out of that module's source, joining the adjacent string literals
its line wrapping leaves behind, and fails if either nudge is no longer injected
verbatim. Reworded one and it reports which nudge went missing and what a resumed
scan would do about it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* read the nudges out of what the module can inject, not out of its text

Searching the source accepted the sentence anywhere in the file, so a stale copy
left behind in a comment would have kept the guard passing after the message it
guards had changed - the drift it exists to catch.

Parsing the module instead limits it to strings the code can actually inject.
Comments never reach the tree, docstrings are dropped as description rather than
behaviour, and adjacent literals are joined during parsing, which the line
wrapping needed and the regex was only approximating.

Checked by rewording the message and leaving the old wording in a comment: the
guard fails, where searching the text passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-08 22:34:45 +03:00
Ahmed Allam
b260a4ee38
fix(tui): make the mount prompt clickable, and skip the mount instead of abandoning the scan (#1015)
* make the working-directory prompt answer the mouse

Its Confirm and Cancel were drawn as buttons and did nothing when clicked: the
modal mouse handler had a case for every dialog except this one, so a click fell
through and the scan sat waiting on an answer the user believed they had given.
Only the keyboard could answer it.

The prompt is docked in a corner rather than centered, so it also needs its own
bounds; the centered ones every other dialog uses would have put the buttons in
the wrong place. Those bounds now come from the same placement cornerOverlay
draws with.

Two returns that hand back the model alongside a call that mutates it are now
sequenced explicitly. They work, but only because the compiler happens to
evaluate the call first, and one of them is what puts the prompt back in the
composer when the mount is declined.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* skip the mount instead of abandoning the scan

Declining the working-directory prompt threw the whole launch away and dropped
back to the start screen, which is a lot to lose for answering one question
about one directory. The two answers are now about the directory alone: mount it,
or run without it. The prompt is the whole of the input either way.

The buttons say which is which - Mount and Skip rather than Confirm and Cancel -
and the prompt says what skipping costs.

A run with neither target nor directory is a real run, so two things follow it.
It can be resumed: its instruction is what drives it, and that is in the run
record. And it tells the agent plainly that it has neither, because an agent
given no scope goes looking for the one it assumes it was meant to have.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-08 22:34:02 +03:00
alex s
9dae76667b
expand firebase storage rules coverage (#1002) 2026-08-06 23:22:06 -07:00
Ahmed Allam
b69af37cb2 feat(report): keep dependency findings from distinct manifests separate in dedupe 2026-08-06 02:20:46 +03:00
Ahmed Allam
72cb15a20a feat(reporting): require repo-relative manifest_path on dependency CVE findings 2026-08-06 02:20:46 +03:00
Alex Schapiro
97336d53e4 feat(reporting): structured reachability evidence ladder for dependency CVE findings 2026-08-06 00:25:08 +03:00
devin-ai-integration[bot]
0abe82d622
fix(agents): collapse repeated waits queued inside one model turn (#979)
* fix(agents): collapse repeated waits queued inside one model turn

* fix(agents): state that one wait is enough in every prompt variant

---------

Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-08-06 00:07:30 +03:00
devin-ai-integration[bot]
6735a6f89e
fix(llm): abandon a model stream that stops producing events (#978)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-08-06 00:07:14 +03:00
devin-ai-integration[bot]
8bd6c8e87a
fix(llm): cap the tool calls one assistant response may queue (#977)
* 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>
2026-08-06 00:06:59 +03:00