Sandboxing & permissions
An investigation is supposed to be read-only, but “supposed to” and “enforced”
are different guarantees. PrismaLens exposes that difference through two
independent dials on investigate:
--mode— what the harness is asked to do (its permission posture).--sandbox— what actually stops it if it tries something else anyway (its isolation boundary).
This page covers both, plus how to read the honest “here’s what you asked for vs. what you actually got” report every run produces.
Supported platforms
Section titled “Supported platforms”PrismaLens runs on Linux and macOS natively, and on Windows through WSL2 — but the enforced sandbox boundaries aren’t available everywhere:
| Platform | Runs the CLI | process floor | srt (enforced local) | e2b (enforced cloud) |
|---|---|---|---|---|
| Linux (native) | Yes | Yes | Yes (bwrap + seccomp) | Yes |
| macOS (native) | Yes | Yes | Yes (sandbox-exec) | Yes |
| Windows via WSL2 | Yes | Yes | Yes (Linux bwrap, inside WSL) — see the WSL caveat | Yes |
| Windows (native, no WSL) | Yes | Yes | No — srt is Linux/macOS-only | Yes |
srt depends on an OS-level mechanism (bwrap on Linux, sandbox-exec on
macOS), so a native-Windows user without WSL only has the cooperative
process floor locally, or the cloud e2b boundary for a hard guarantee. Run
under WSL2 to get the enforced local sandbox on Windows.
Permission modes (--mode)
Section titled “Permission modes (--mode)”| Value | What it does |
|---|---|
read-only (default) | The harness’s default read-only guarantee for whichever backend you’re renting — see the table below, since that guarantee isn’t the same for every harness. |
supervised | Same guarantee as read-only today — both defer to the harness’s own read-only mechanism. |
auto | Drops the read-only floor: writes are auto-accepted, with nothing programmatic stopping them. |
dangerous | Full access, no restrictions applied at all. |
--dangerously-skip-permissions is a shortcut for --mode dangerous — it wins
over --mode if both are passed.
read-only/supervised fidelity depends on the harness you rent, because
PrismaLens doesn’t build its own permission engine — it translates one dial
into each harness’s native mechanism and reports what actually resulted:
| Harness | Fidelity | Mechanism |
|---|---|---|
deepagents | cooperative | ACP session/request_permission is auto-approved — prompt-only, no programmatic block. The harness has to actually respect the read-only ask. |
claude-code | enforced | Agent SDK disallowedTools deny-list (Edit, Write, MultiEdit, NotebookEdit) plus permissionMode — a real block, not just a prompt. |
One caveat applies to every harness: read-only removes the edit tools,
but the shell is not one of them — an agent with Bash can still write with
echo >, sed -i, or git commit. Treat the permission mode as honest intent
signalling, and use an isolation boundary
(--sandbox srt or a container) when you need writes enforced away.
auto and dangerous don’t consult that table at all — they’re always
advisory, on every harness, because neither applies a read-only floor in
the first place.
Isolation boundaries (--sandbox)
Section titled “Isolation boundaries (--sandbox)”--sandbox controls where the harness process actually runs, independent of
what it was asked to do. Four values, auto by default:
| Value | Fidelity | Guarantee |
|---|---|---|
process | cooperative | The always-on floor. Not an OS boundary — no filesystem, network, or process isolation. |
srt | enforced | A real OS-level sandbox, via Anthropic’s @anthropic-ai/sandbox-runtime. |
e2b | enforced | A cloud microVM (Firecracker), via E2B. |
auto | either | Prefers srt, but only once a self-check confirms it will actually work — otherwise falls back to process and says why. |
process — the cooperative floor
Section titled “process — the cooperative floor”This is the fallback every mode can land on, and the only thing it actually
does is trim the harness’s environment down to a safe allowlist (PATH,
HOME, USER, LOGNAME, SHELL, LANG, LC_ALL, LC_CTYPE, TERM,
TMPDIR, TZ, PWD) plus whatever BYO-key credentials you’ve configured —
so PrismaLens’s own secrets never reach the harness. That’s it. There’s no
filesystem confinement and no network restriction: if the harness decides to
write outside your repo or call out to some other host, nothing here stops
it. The one thing every mode enforces, including this floor, is a wall-clock
deadline — set agent.limits.wall_clock_ms and the child gets SIGKILLed if
it runs past it.
srt — the enforced local boundary
Section titled “srt — the enforced local boundary”srt wraps the harness in a real OS sandbox (bwrap + seccomp on Linux,
sandbox-exec on macOS) with an egress proxy that only allows the domains
you’ve configured (your telemetry/logs URLs in prismalens.config.yaml
— configure nothing and the harness gets no network access at all).
It’s an opt-in install, not bundled with the CLI: run
npm install -g @anthropic-ai/sandbox-runtime (or make sure an srt binary
is on PATH). PrismaLens doesn’t depend on the package directly — it
resolves the binary lazily, only at the moment you actually select this
mode, so a normal install stays light.
Ask for --sandbox srt explicitly and it’s a hard requirement: if srt
can’t be resolved, the run fails immediately with an error telling you to
install it or pick a different mode. It never quietly substitutes the
process floor for you — that honest fallback behavior belongs to auto
alone.
e2b — the enforced cloud boundary
Section titled “e2b — the enforced cloud boundary”e2b runs the harness in a remote microVM instead of on your machine, with
its own egress allowlist enforced at the SDK level. It needs the e2b
npm package installed and an E2B_API_KEY set.
Because it’s a remote, billed service, e2b is explicit-only — auto
never reaches for it on its own. You have to ask for it by name.
auto — the default, and its egress self-check
Section titled “auto — the default, and its egress self-check”auto is the config default (agent.sandbox: auto). It wants to use srt,
but checking whether the srt binary exists isn’t enough to trust it: on
some hosts srt starts up cleanly, logs that its relay is ready, and then
silently drops every request the sandboxed harness makes.
So before trusting srt for a run, auto runs a real check: it stands up a
throwaway srt boundary and curls one of your actually-configured endpoints
(the first parseable URL among telemetry.prometheusUrl,
telemetry.alertmanagerUrl, telemetry.apiUrl, logs.url) through it. A
real HTTP status code back means the boundary carries traffic, and srt is
used for the run. A connection-refused response (or no configured URL to
probe at all) means auto falls back to the process floor instead — and
says so, both as a console warning during the run and as a degradeReason
in the run’s fidelity report. A healthy verdict is trusted for the rest of
the process’s life; an unhealthy one is re-checked after five minutes, so a
one-off network blip doesn’t disable srt for good.
Both hero harnesses run inside the boundary
Section titled “Both hero harnesses run inside the boundary”--sandbox applies to both hero harnesses — claude-code and deepagents.
Every investigation runs inside at least the always-on process floor, and
claude-code now spawns through the same isolation boundary the ACP path
(deepagents) already used, honoring your sandbox and limits config the
same way. Whichever harness ran, the run’s fidelity report records the sandbox
that was actually applied (see below).
So --sandbox srt (or auto landing on srt) wraps claude-code in the
enforced OS boundary just as it does deepagents. e2b remains the
explicit-only cloud boundary — auto never reaches for it on either harness.
Requested vs. actual: the fidelity report
Section titled “Requested vs. actual: the fidelity report”Every investigation report carries a fidelity block recording exactly
what was applied — not just what you asked for. It’s part of the
InvestigationReport (visible with --json or --output; the human
terminal renderer doesn’t print it today):
"fidelity": { "harness": "deepagents", "mode": "read-only", "fidelity": "cooperative", "mechanism": "ACP session/request_permission auto-approved (prompt-only); ...", "sandbox": { "requested": "auto", "actual": "process-floor", "fidelity": "cooperative" }}The sandbox.requested/sandbox.actual pair is what makes an auto
degrade visible after the fact, not just in the moment. During the run
itself, the CLI also prints a one-line warning whenever auto degrades
(naming the reason), or an info line confirming srt was actually used.
The WSL caveat: mirrored networking breaks srt
Section titled “The WSL caveat: mirrored networking breaks srt”This is exactly the failure --sandbox auto’s self-check exists to catch:
on a mirrored-networking WSL host it degrades to the process floor and
tells you why, instead of quietly running an investigation that can’t reach
anything. If you want the enforced boundary rather than the honest degrade,
switching the networking mode is the real fix — the self-check can only
detect the dead relay, not repair it.
Choosing in practice
Section titled “Choosing in practice”- Leave
--sandboxatautofor local use. It gets you the enforced boundary when one is actually available and working, and degrades honestly (with a stated reason) when it isn’t. - Force
--sandbox processwhen you know your setup and would rather skip the sandbox entirely than deal with installingsrt. - Force
--sandbox srtwhen you want a hard guarantee and would rather fail loudly than run unsandboxed — install@anthropic-ai/sandbox-runtimefirst. - Use
--sandbox e2bfor a cloud or CI placement where you don’t want the harness anywhere near your local machine at all. - Leave
--modeat the defaultread-only. Investigations are designed to be read-only, so most runs never need anything looser.
When auto / dangerous are legitimate
Section titled “When auto / dangerous are legitimate”The loosening modes exist for the case where the investigation genuinely needs a
write step the read-only floor would block — reproducing a failure by running
the test suite, or a diagnostic tool that has to write a scratch file to do its
job. Reach for them only when both are true: you need that write step, and
the run is inside an OS sandbox (srt or e2b) that contains the blast radius
anyway. Loosening the permission posture without a containing sandbox is just
an unconstrained agent writing on your machine — don’t. --dangerously-skip-permissions
means exactly what it says, on any harness.
Next steps
Section titled “Next steps”- Configuration — set
agent.sandbox,agent.permissions.mode, andagent.limitsinprismalens.config.yaml. - Commands — the full
investigateflag reference. - Providers & harnesses — what each harness needs installed.
- Troubleshooting — sandbox degrades, the WSL
srtsymptom, and other run failures.