@christofilojohn/argus
flwr new @christofilojohn/argusArgus
Many eyes. One verdict.
Narrow scout agents review a public GitHub repository, each hunting one class of defect with its own playbook. A synthesizer ranks what they found, drops the noise, and writes a review anchored to file:line. A remediation pass proposes the smallest fix for each surviving finding.
The playbooks are the product. A curator edits them after every review, so the scouts get sharper each time they run.
Built for the Collaborative Agent Hackathon, Cambridge 2026.
GitHub repo
|
v
+---------------------------------------------------+
| scouts - one lens each, its own playbook |
| network ingestion crypto supplychain memory |
+---------------------------------------------------+
|
v
synthesizer ranks findings, drops noise
|
v
review + score each finding tied to file:line
|
v
remediation smallest fix per finding
|
v
curator one new rule per scout
|
+--------> back into the playbooks
How it works
Whole-repo coverage at constant context. Growing a tool loop until it has seen a large repository exhausts the model's context and it stops answering. Argus separates discovery from judgement instead:
- Each scout's playbook yields literal search patterns — the backticked terms already written in it, so no model call is needed to produce them.
- Python greps every source file in the repository. No tokens, full coverage.
- The model judges the matched lines in independent batches, each with a fresh context. A 40-file repo and a 4000-file repo cost the same per call.
Line numbers therefore come from reading files, not from a model counting lines — every finding is anchored to code that was actually read.
Self-improving playbooks. Each scout has a Mission it may never change and a Learned section the curator appends to. After each review the curator compares what the scouts reported against what survived, and writes one rule per scout. Because patterns are extracted from the playbook text, a learned rule naming torch.load becomes a search pattern on the very next run.
A score that is arithmetic, not an opinion. Severity counts with diminishing returns, so the same findings always produce the same number. Crucially, a clean result on thin coverage reports as inconclusive rather than as a pass — finding nothing in 9% of a repository is not a clean bill of health, and neither is a lens whose patterns never matched the language.
Results
Run against public repositories, at the coverage shown:
| Repository | Coverage | Findings | Score |
|---|---|---|---|
| ARM-software/kleidiai | 1617/1617 files | 1 | 9.0 / 10 |
| ROCm/legacy-rocm-build | 115/115 files | 5 | 7.8 / 10 |
| parasecurity/FLASH | full | 5 | 5.0 / 10 |
Representative findings:
- parasecurity/FLASH — dill.load applied to bytes received from a network peer at four call sites, giving remote code execution during parameter exchange.
- ARM-software/kleidiai — alloca sized from a caller-supplied matrix dimension, so a large N can overflow the thread stack.
- ROCm/legacy-rocm-build — an upstream tarball fetched over the network and compiled as root with no checksum or signature check.
Where a review does not finish, it says so: a scout that never ran, or candidates left unjudged at the deadline, are reported alongside the score rather than being quietly folded into a pass.
Usage
Ask it in a sentence — the repository is parsed out of your message:
Review github.com/owner/repo for security issues.
Argus runs against a Flower SuperLink pointed at any endpoint that speaks the OpenAI Responses API:
export FLWR_MODEL_API_ENDPOINT='http://<host>:<port>/v1/responses' uv run flower-superlink --insecure
Add the connection to ~/.flwr/config.toml:
[superlink.local-agent] address = "127.0.0.1:9093" insecure = true
Then review a repository:
uv sync uv run flwr run . local-agent \ --run-config 'agent.input="Review github.com/owner/repo for security issues."' \ --stream
Reviews are written to ~/.argus/reviews/<owner>__<repo>__<stamp>.json with a standalone HTML report beside them. Learned playbooks live in ~/.argus/playbooks/.
Model. The results above were produced with Kimi-K2.7-Code, served on AMD Instinct MI300X accelerators. Every role — the five scouts, the synthesizer, the remediation pass and the curator — runs on that one model; they differ by playbook and brief, not by weights. Set scout_model and synth_model to whatever model ID your endpoint serves.
A SuperLink is bound to exactly one endpoint, so reaching a second model in the same run means calling it directly: set synth_endpoint to that model's /v1/responses URL and the synthesizer alone will use it.
Choosing a model. The scout loop needs a model that emits tool calls and then stops to answer. Reasoning-heavy models tend to spend their whole output budget thinking and return a response with no message at all, which Argus reports as a failed synthesis rather than inventing a result. If findings come back empty on a repository that clearly has candidates, that is the first thing to check.
Configuration
Every knob lives in [tool.flwr.app.config.argus] and can be overridden per run with --run-config.
| Key | Default | Purpose |
|---|---|---|
| scouts | five threat lenses | Which playbooks to run. |
| mode | sweep | sweep for whole-repo coverage; explore for a model-driven tool loop. |
| max_files | 1200 | Files to read. Bounds time, not context. |
| scout_model / synth_model | — | Model per role. |
| synth_endpoint | empty | Point synthesis at a second, larger model. |
| budget_seconds | 210 | Deadline for the scout phase. |
Adding a scout needs no code: drop a Markdown playbook in argus/playbooks/ with a Mission, Rules, and an empty Learned section, then name it in scouts.
Deliberate limits
- No automatic pull requests. Findings are model-generated, so publishing them stays a human action. scripts/post_review.py posts a review to GitHub as inline comments carrying GitHub suggestion blocks, so a maintainer can apply or dismiss each fix in the review UI. It refuses to send anything without --confirm.
- Fixes stay one or two edits deep. Where a real fix is larger, the report says what to investigate instead of inventing a redesign.
- Findings without a real file:line are dropped before they reach the synthesizer.
- The curator may only append to ## Learned. A scout's mission cannot drift.
- Coverage is always reported, and a clean result on partial coverage is never presented as a pass.
Authors
Amar SaiTeja Chityala · Ioannis Christofilogiannis · Ayomide Lambe · Hanaa Babrakar
Licensed under Apache-2.0.