Root causes:
1. Resume message said "re-spawn sub-agents" but didn't say WHICH ones
or that old agent IDs are dead — LLM tried to interact with old IDs
and got confused.
2. send_message_to_agent returned unhelpful "not found" error when the
LLM used old (dead) agent IDs after resume.
Fixes:
- _build_resume_context_message / _inject_resume_context_message now
accept the full checkpoint_data object and extract tracer_agents to
list every non-completed sub-agent by name and task. The LLM now
knows exactly which agents to re-spawn.
- Message explicitly forbids interacting with any agent ID from history
and instructs the LLM to call view_agent_graph first.
- send_message_to_agent returns an actionable error when target is not
found: explains it may be a dead session ID and tells the LLM to use
view_agent_graph then create_agent.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root cause of resume not working:
- generate_run_name() adds a random suffix every time, so without
--run-name the checkpoint from a previous session was never found.
- Ctrl+C during the first iteration (before any checkpoint was saved)
left no checkpoint to resume from.
Fixes:
1. _find_checkpoint_by_target_hash(): scans strix_runs/ for the most
recent checkpoint whose target_hash matches the current targets.
Now running `strix --target example.com` again automatically
resumes the last interrupted scan without needing --run-name.
2. _save_checkpoint_on_interrupt(): saves current agent state in both
the signal handler and atexit in cli.py and tui.py, so a Ctrl+C
mid-first-iteration still produces a valid checkpoint.
3. _setup_checkpoint_on_args() restructured: handles run_name=None,
--force-new, explicit --run-name, and auto-detect in one place.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Defines the missing helper function called in cli.py and adds the equivalent
to tui.py. Injects a user message into the restored AgentState so the LLM
knows the scan was interrupted and must continue rather than call finish_scan
or agent_finish due to an abruptly-ended message history.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three bugs fixed:
1. Ghost sub-agents (root cause of all sub-agent issues):
Restoring tracer.agents/tool_executions injected old sub-agent
entries that had no live instances. The TUI showed them as
interactive but they could not receive messages or run. Worse,
they polluted the agent message-routing system so new sub-agents
spawned after resume failed to communicate with the root agent.
Fix: only restore chat_messages, vulnerability_reports, and the
execution ID counter. The root agent's LLM context (message
history) already knows what all sub-agents did.
2. Root agent stuck in wait state after resume:
If the scan was interrupted while the root agent was in a wait
state (waiting_for_input=True, stop_requested=True, etc.) the
restored AgentState had those flags set and the loop froze
immediately. Fix: reset all blocking flags on restore in both
cli.py and tui.py.
3. Completed flag causing instant exit:
If completed=True was serialised into the checkpoint (edge case)
the loop would exit on the first should_stop() check. Fix:
reset completed=False on restore.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The previous guard `if not self.state.messages` broke sub-agents because
they can have pre-loaded context messages in their state before agent_loop
is called. This caused them to start without a task and produce no output.
Fix: only skip the initial task message when parent_id is None AND messages
is already populated (= root agent resume). Sub-agents always get their
task message regardless of whether their state has prior context.
- Fresh root agent: parent_id=None, messages=[] → adds task ✓
- Fresh sub-agent: parent_id=set, messages=[] → adds task ✓
- Sub-agent with context: parent_id=set, messages=[..] → adds task ✓
- Resumed root agent: parent_id=None, messages=[..] → skips ✓
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously checkpoints only saved tracer.chat_messages and
tracer.vulnerability_reports, leaving tracer.agents and
tracer.tool_executions empty on resume — so all sub-agents
(both in-progress and completed) were invisible after resuming.
Changes:
- checkpoint.py: add tracer_agents, tracer_tool_executions,
tracer_next_execution_id fields to CheckpointModel; populate
them in CheckpointManager.save() from the live tracer
- cli.py: on resume, restore agents dict, tool_executions dict,
and advance _next_execution_id to avoid ID collisions
- tui.py: same restore logic so TUI sidebar shows all previous
agents and their tool results immediately on resume
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Re-architects the agent loop to support interactive (chat-like) mode
where text-only responses pause execution and wait for user input,
while tool-call responses continue looping autonomously.
- Add `interactive` flag to LLMConfig (default False, no regression)
- Add configurable `waiting_timeout` to AgentState (0 = disabled)
- _process_iteration returns None for text-only → agent_loop pauses
- Conditional system prompt: interactive allows natural text responses
- Skip <meta>Continue the task.</meta> injection in interactive mode
- Sub-agents inherit interactive from parent (300s auto-resume timeout)
- Root interactive agents wait indefinitely for user input (timeout=0)
- TUI sets interactive=True; CLI unchanged (non_interactive=True)
The perplexity API key check in strix/tools/__init__.py used
Config.get() which only checks os.environ. At import time, the
config file (~/.strix/cli-config.json) hasn't been applied to
env vars yet, so the check always returned False.
Replace with _has_perplexity_api() that checks os.environ first
(fast path for SaaS/env var), then falls back to Config.load()
which reads the config file directly.
Users can now access the Caido web UI from their browser to inspect traffic,
replay requests, and perform manual testing alongside the automated scan.
- Map Caido port (48080) to a random host port in DockerRuntime
- Add caido_port to SandboxInfo and track across container lifecycle
- Display Caido URL in TUI sidebar stats panel with selectable text
- Bind Caido to 0.0.0.0 in entrypoint (requires image rebuild)
- Bump sandbox image to 0.1.12
- Restore discord link in exit screen
The badge image URL used invite code which is expired,
causing the badge to render 'Invalid invite' instead of the server info.
Updated to use the vanity URL which resolves correctly.
Fixes#313
* feat: add to readme new keys
* feat: shoutout strix models, docs
* fix: mypy error
* fix: base api
* docs: update quickstart and models
* fixes: changes to docs
uniform api_key variable naming
* test: git commit hook
* nevermind it was nothing
* docs: Update default model to claude-sonnet-4.6 and improve Strix Router docs
- Replace gpt-5 and opus-4.6 defaults with claude-sonnet-4.6 across all docs and code
- Rewrite Strix Router (models.mdx) page with clearer structure and messaging
- Add Strix Router as recommended option in overview.mdx and quickstart prerequisites
- Update stale Claude 4.5 references to 4.6 in anthropic.mdx, openrouter.mdx, bug_report.md
- Fix install.sh links to point to models.strix.ai and correct docs URLs
- Update error message examples in main.py to use claude-sonnet-4-6
---------
Co-authored-by: 0xallam <ahmed39652003@gmail.com>