Skip to content
PrismaLens Docs

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.

PrismaLens runs on Linux and macOS natively, and on Windows through WSL2 — but the enforced sandbox boundaries aren’t available everywhere:

PlatformRuns the CLIprocess floorsrt (enforced local)e2b (enforced cloud)
Linux (native)YesYesYes (bwrap + seccomp)Yes
macOS (native)YesYesYes (sandbox-exec)Yes
Windows via WSL2YesYesYes (Linux bwrap, inside WSL) — see the WSL caveatYes
Windows (native, no WSL)YesYesNosrt is Linux/macOS-onlyYes

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.

ValueWhat 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.
supervisedSame guarantee as read-only today — both defer to the harness’s own read-only mechanism.
autoDrops the read-only floor: writes are auto-accepted, with nothing programmatic stopping them.
dangerousFull 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:

HarnessFidelityMechanism
deepagentscooperativeACP session/request_permission is auto-approved — prompt-only, no programmatic block. The harness has to actually respect the read-only ask.
claude-codeenforcedAgent 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.

--sandbox controls where the harness process actually runs, independent of what it was asked to do. Four values, auto by default:

ValueFidelityGuarantee
processcooperativeThe always-on floor. Not an OS boundary — no filesystem, network, or process isolation.
srtenforcedA real OS-level sandbox, via Anthropic’s @anthropic-ai/sandbox-runtime.
e2benforcedA cloud microVM (Firecracker), via E2B.
autoeitherPrefers srt, but only once a self-check confirms it will actually work — otherwise falls back to process and says why.

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 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 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-onlyauto 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.

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.

  • Leave --sandbox at auto for 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 process when you know your setup and would rather skip the sandbox entirely than deal with installing srt.
  • Force --sandbox srt when you want a hard guarantee and would rather fail loudly than run unsandboxed — install @anthropic-ai/sandbox-runtime first.
  • Use --sandbox e2b for a cloud or CI placement where you don’t want the harness anywhere near your local machine at all.
  • Leave --mode at the default read-only. Investigations are designed to be read-only, so most runs never need anything looser.

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.

  • Configuration — set agent.sandbox, agent.permissions.mode, and agent.limits in prismalens.config.yaml.
  • Commands — the full investigate flag reference.
  • Providers & harnesses — what each harness needs installed.
  • Troubleshooting — sandbox degrades, the WSL srt symptom, and other run failures.