-
-
Notifications
You must be signed in to change notification settings - Fork 10
Feature Multi Backend
Argo runs the same multi-stage pipeline on a swappable agent backend, so you can run it with whatever you already have — Claude Code, the Codex CLI (OpenAI), or a local/open-source model — without changing any audit logic. This also makes Argo a vehicle for a clean cross-model comparison: identical prompts and pipeline, different model, directly comparable results.
AgentRunner (ABC)
├─ HeadlessClaudeRunner # `claude -p` — Claude Code
├─ CodexRunner # `codex exec` — OpenAI, or local/OSS via --oss
├─ MockClaudeRunner # fixtures (zero tokens; the test suite)
└─ FallbackRunner # wraps an ordered chain of the above (resilience, below)
--runner {headless|codex|mock} picks the backend (default headless = Claude Code).
One SessionPolicy — no network except the two OSINT stages (research + corroborate), and the
repo is never writable — and each backend translates it into its own dialect:
| Guarantee | Claude | Codex |
|---|---|---|
| Repo read-only | via --add-dir + chmod |
outside the workspace + chmod, never --add-dir'd |
| Writes only scratch | session cwd = scratch |
-s workspace-write, cwd = scratch |
| No network (default) | tools stripped from allowlist | OS sandbox denies egress |
| Network only for research/corroborate | OSINT tools kept for those stages | network re-enabled only for those stages |
| Never a sandbox escape | network/mutation tools always disallowed | never danger-full-access
|
Both mappings are unit-tested independently. See Guardrails & Safety.
Any model Ollama or LM Studio serves works — including Qwen (qwen2.5-coder, qwen3) and DeepSeek
(deepseek-coder, deepseek-v3, deepseek-r1):
ollama pull qwen2.5-coder:32b
python -m argo.cli pipeline --runner codex --codex-oss --codex-local-provider ollama \
--codex-model qwen2.5-coder:32b --brief BRIEF.txt --repo PATHCost is ~$0 for local models. Caveat: capability, not plumbing. Some stages are format-strict — recon must emit prompts carrying the RoE/prohibited-techniques anchors verbatim, audit must emit schema-valid JSON. A capable coder model clears the bar; very small (~7B) models may not — exactly what the Benchmarks & Costs harness measures.
Cost note: Claude Code returns real total_cost_usd per call; Codex reports tokens, not dollars, so
Argo estimates USD from a price table (unknown/OSS/local models estimate to $0). The consequence:
with Codex, the hard mid-session budget kill is unavailable — the per-run budget abort between
stages still applies, on the estimated cost.
Backends and accounts chain transparently: when one hits a session/rate limit (429), the same call is retried on the next (a per-run circuit breaker disables the walled one; a non-retryable error propagates immediately). Since limits are per-account, two logged-in Claude accounts double your capacity before falling through to Codex:
python -m argo.cli pipeline --repo <url> --calibration \
--claude-accounts ~/.claude,~/.claude-b --fallback codex
# set up the 2nd account once: CLAUDE_CONFIG_DIR=~/.claude-b claude loginCodex multi-account works the same way (--codex-accounts ~/.codex,~/.codex-b, via CODEX_HOME).
So a long Opus run that used to wall on the Claude session limit mid-validate now self-heals to
the next account/backend instead of degrading or failing. When a session-limit error carries a
human-readable reset time, it's pulled out into the error message and the run's log, so you know
exactly when it's safe to retry.
Every RunnerError carries a failure_kind, classified from the real error text against confirmed-
live signatures rather than treating every failure the same way:
| Kind | Real confirmed signature | Response |
|---|---|---|
moderation_flagged |
Codex: "flagged for possible cybersecurity risk". Claude: "...safeguards flagged this message..."
|
same-backend retry with a neutral-register prompt variant (below), short delay |
credits_exhausted |
Codex: "out of credits"
|
30-minute cooldown on that backend — retrying every few minutes against a dead account is pointless but harmless; a longer bench lets the run spend that time elsewhere |
rate_limited |
a 429 / session-limit response | falls through to the next backend/account in the chain immediately |
unknown_retryable |
anything else recoverable (timeout, empty output, transient infra) | default cooldown, then retried |
A same-backend retry after a moderation_flagged or credits_exhausted classification waits
first — back-to-back identical retries of a flagged prompt reliably got flagged again every time, a
short spaced-out delay measurably didn't. A genuinely different backend in the fallback chain shares
no such cooldown and fires immediately.
A moderation flag is a different problem from a rate limit: the same prompt, resent unchanged, tends
to get flagged again. On a moderation_flagged failure, AgentRunner.run() retries once, on the
same backend, with a caller-supplied neutral-register variant of the prompt — reworded narrative
framing (e.g. "independently determine whether the report is correct" instead of "skeptical triager
whose job is to reject... prove this one is wrong"; "an untrusted caller" instead of "an attacker"),
same technical content, same requested output, same PROHIBITED TECHNIQUES block byte-for-byte.
This is a reactive retry, not a preemptive rewrite: the normal prompt goes out by default
everywhere, and the neutral variant is only ever generated and used after an actual flag. Covers
validate, deep_verify, audit, and the ASan PoC harness-authoring session —
each stage supplies its own neutral variant matching how it already builds its own prompt.
This sits underneath the cross-backend FallbackRunner above, not instead of it: if the neutral
retry also fails, the failure still propagates normally into the fallback chain. Three independent
resilience layers — prompt variant, backend, whole stage (below) — with no interaction risk, since
each only ever sees the layer below it's final outcome.
Beyond a single call's retry/fallback, the orchestrator itself retries a whole stage in place
(bounded, a couple of attempts) when a failure is retryable and not credits_exhausted — either
after a short pause, or honoring a specific reset-time hint if the backend provided one, capped so an
unattended run doesn't silently hang for hours waiting one out. A stopped run is never silently lost:
every stage write is atomic (temp file + replace), and argo resume <run_id> picks a run back up
from exactly where it stopped — printed automatically on any interruption, including Ctrl+C.
python -m argo.cli pipeline --smoke # Claude
python -m argo.cli pipeline --smoke --runner codex # Codex/OpenAI
python -m argo.cli pipeline --smoke --runner codex --codex-oss --codex-local-provider ollamaArgo deliberately keeps the model behind the AgentRunner interface, because detection quality
tracks the model, and the frontier is moving fast toward security specifically. As
security-specialized models become accessible, the swappable backend means Argo gets better by
pointing at a stronger engine — no pipeline changes needed.
-
Architecture — the
AgentRunnerabstraction and per-stage model defaults. - Benchmarks & Costs — where cross-model comparisons get measured.
- ASan PoC Generation — a concrete stage whose harness-authoring sessions rely on the moderation-flag classification and neutral-register retry above.
Argo
Features
- Threat-Informed Audit
- Archetype-Driven Prompts
- Adversarial Validation
- Docs & History Corroboration
- Second Opinion
- Deep Verify
- Design-Aware Impact Discipline
- Multi-Backend
- Remediation & Fixes
- Interrogation Chat
- Runtime Verification
- Live Verification
- ASan PoC Generation
- Benchmarks & Costs
- Web UI
Reference