Observability records what happened. Nothing records what the agent meant to do.
Blast Radius is a preflight gate for autonomous agents. Before an agent's action touches anything real, it forks the sandbox image, runs the action in the fork only, diffs the fork against the parent, and compares that diff against what the agent said it was about to do.
An agent can call twelve tools, get exit 0 twelve times, report normal cost and latency — and
still have done the wrong thing. Every mutation-verification tool returns green on that case,
because the mutation did happen. Only comparing the change against the stated intent catches it.
Live demo: http://<your-host>/
Track: Best Apps and Agents
Give an agent: "delete stale logs older than 30 days."
It writes find /logs -name '*.log' -delete. The command succeeds. Every check downstream is
green. It also deleted three files written today, because the command never had an mtime
predicate in it.
Nothing in a normal stack has any signal that this went wrong. The tool call succeeded. The files were, in fact, deleted. Blast Radius catches it because it recorded — before the action ran — that the agent believed it was removing files older than 30 days, and the actual diff contains files dated today.
flowchart LR
A[Agent loop<br/>outside the sandbox] -->|action + context| B[Nemotron Nano<br/>extract intent]
B -->|intent JSON| C{{Risky write?}}
C -->|no| G[Run on parent]
C -->|yes| D[Fork image 0.4-2s<br/>execute in fork only]
D -->|ls + read, no VM boot| E[Changeset]
E --> F[Nemotron Super<br/>diff vs intent]
F -->|CLEAN| G
F -->|DRIFT| H[Operator gate]
H -->|approve| G
H -->|reject + reason| A
The agent loop runs outside the sandbox, and that is the whole design. Nebius Sandboxes fork
the filesystem image — the docs are explicit that process memory, running
services and network state are not preserved. An agent whose loop lived inside a sandbox could
not be forked at all. Running it outside turns that constraint into the feature: run state
becomes the pair (messages, image_uuid), both trivially copyable, so a fork is a genuine
counterfactual — an independent branch of the whole world and the whole conversation.
Most actions never fork. core/risk.py is a deterministic classifier: reads run straight
through, writes and network calls are gated. That is what makes this usable rather than a tool
that interrupts on everything and gets uninstalled.
| Model | Served by | Job | Why this tier |
|---|---|---|---|
nvidia/nemotron-3-nano-30b |
Nebius Token Factory | Per-action intent extraction | Runs on every single tool call, so unit cost dominates. 30B MoE with ~3B active; NVIDIA tunes Nano for software debugging and summarisation. ~800 tokens per action. |
nvidia/nemotron-3-super-120b-a12b |
Nebius Token Factory | Drift adjudicator | Sits in the latency-critical path — a human is waiting to approve. Tuned for low-latency multi-agent work; 262K context holds the changeset plus intent history. |
nvidia/nemotron-3-ultra-550b-a55b |
Nebius Token Factory | Agent under test + forensic report | 1M context holds the entire run trace at once for the end-of-run report. Tuned for long-running autonomous agents and strategic planning. |
A twelve-step run with three gated actions costs roughly half a cent.
Where Token Factory accelerated the work: the OpenAI-compatible API meant zero integration
code for three different model tiers — one client, three model strings. Sandboxes' automatic
image versioning meant we never wrote checkpoint code at all: session() versions the image
after every command, so a fork is just the previous image id. list_files/read_file reading an
image without booting a VM is the single reason a gate can afford to sit in front of every write.
Where Tavily is load-bearing: when an agent's stated intent rests on a claim about the outside
world — a deprecation, an advisory, a version — core/premise.py resolves that claim against live
sources before the fork is even created. The agent's plan comes from training-cutoff knowledge;
this is the only component with access to ground truth the model cannot have. Remove it and the
system genuinely gets worse at its job.
git clone https://github.com/<you>/blast-radius.git && cd blast-radius
make install && source .venv/bin/activate
make env # then paste NEBIUS_API_KEY into .env
python probe_sdk.py # prints the real ConTree SDK surface
make smoke # THE GATE — proves fork + diff works
make run # http://localhost:8000Reproduce the headline result:
make demo # records a real run of the drift scenarioThe seeded state is real: 47 files, 44 with mtimes set 31–74 days in the past, 3 written today. The drift is produced by the model, not injected — we do not script the failure. If your model gets it right, that is a CLEAN verdict and an honest result.
- It is not a general-purpose drift detector. It ships with three seeded scenarios and is tuned against them. On arbitrary tasks the intent extractor will produce vaguer scopes and the adjudicator will be correspondingly less certain.
- It does not auto-recover. It detects and stops. Recovery is a second product.
- It only sees the filesystem. Network side effects inside a forked action are real and are not rolled back by discarding the fork — which is why network commands are classified risky and gated before they run, not diffed after.
- The diff is bounded.
DIFF_MAX_FILESandDIFF_MAX_READSincore/diff.pycap the walk so a pathological image cannot stall the gate. Very large changesets report as truncated. - Recorded runs are read-only. They are real runs stored in the same tables as live ones, and the UI labels them; you cannot approve or reject a gate in a replay.
See FEEDBACK.md.
Apache-2.0. See LICENSE.