plimsoll

module
v0.11.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 29, 2026 License: Apache-2.0

README

plimsoll

A sandbox service for running untrusted, agent-authored code that reports the isolation boundary each run executed behind, and refuses the run when it is weaker than the caller demanded.

audit gvisor Go Reference Go version release license

A Plimsoll line is the load limit painted on a ship's hull. It is mandatory, and it is on the outside where anyone can check it. That is the idea here: the isolation tier is a value the caller reads, asserts a floor against, and re-checks on the response, not a sentence in a datasheet.

See one real run

An agent wrote a controller. A cart-pole, compiled to WebAssembly and baked into the sandbox image, judged it. The controller was the only file the caller sent, through the ordinary project API, on the container tier.

A cart-pole is a cart on a rail with a pole hinged on top of it, the standard teaching problem in control engineering: push the cart left and right to keep the pole upright. Run the accepted controller twice and the fingerprints of the two trajectories match to the last bit. The agent's first draft, with two gains of the wrong sign, drops the pole at 5.96 seconds and fingerprints differently.

Pole angle and cart position over twenty seconds, for the accepted controller and for the draft that fell

Open the live run report ↗ to replay both runs in the browser, read the controller the agent wrote, and see what the page deliberately does not claim. One execution of the example makes three sandbox runs: the accepted controller twice and the draft once. Reproduce them with make docker-images && go run ./examples/oracle.

More to look at What it is
Simulation replay pages, all eight simulators ↗ Every simulator in the sim image (shower, buck converter, ship heading, black hole orbit, relativistic rocket, satellite clock, double slit, cart-pole swing-up), each with a page that runs a failing and a passing hand-written controller through the sandbox and replays both trajectories with their fingerprints.
A controller in C, compiled in the sandbox ↗ The same judge and cart-pole, with a swing-up controller written in C and compiled to WebAssembly by the run's own first step, so simulator and controller are both WebAssembly. The run report replays the swing-up and compares it with the JavaScript version tick by tick: the two differ in two forces, by a few representable doubles, and the fingerprint catches it while the motion stays bit-identical. Source and caveats in its README; reproduce with make docker-images && go run ./examples/wasm-controller.
A buck converter controller in C ↗ A power supply's control law written in C, the language converter firmware ships in, compiled to WebAssembly in the sandbox and judged holding 5 V through a load step. It calls no library function, so its trajectory is its JavaScript version's byte for byte in all four scenarios, and the page charts one of them tick by tick. Source and caveats in its README; reproduce with make docker-images && go run ./examples/wasm-buck.
Same run, different sandboxes ↗ The oracle's run under local runc and gVisor, an OpenShell gateway, E2B Firecracker and Docker Cloud Sandboxes: three isolation tiers, two Node versions, one fingerprint, the one the oracle page published. Reproduce the configured rows with go run ./examples/providers; the cloud rows are billed.
One sandbox, five calls ↗ A session on an NVIDIA OpenShell sandbox: a failing test, a patch, the test passing without the files being sent again, and a leftover process that is gone by the next call. Every call's record is signed and chained; the verifier accepts the bundle and refuses it with a call dropped or a byte changed. Reproduce with go run ./examples/sessions and a gateway.
The efficiency advisor's report ↗ One measured run, rendered: the same question asked as 13 calls and then as 1, and the finding that names the route to batch on.
Twelve interactive lessons ↗ The execution model, the providers, the API broker, and integrating with an agent. Static pages: no network calls, no analytics, no third-party scripts.

The two things it does

It reports the boundary. Every result carries the isolation tier the run actually executed behind, and every request can carry a floor. A request below the floor is refused before dispatch, so ErrInsufficientIsolation means no submitted code ran.

res, err := provider.Sandbox.RunJavaScript(ctx, sandbox.Request{
    Code:             "console.log(6 * 7)",
    MinimumIsolation: sandbox.IsolationVM, // ErrInsufficientIsolation means nothing ran
})
// res.Isolation reports the boundary that actually ran.

Every refusal that ran nothing says so, with a reason (request, permission, protocol, unsupported, isolation, capacity): sandbox.NotDispatchedReason(err) works the same on a local provider and through the client. An error without it may have followed execution and is never a safe automatic retry (what comes back, and what it means).

Read the tier as evidence this daemon collected, not as a remote attestation: no provider here cryptographically attests the runtime implementation underneath it. What each tier rests on is spelled out in docs/isolation-tiers.md.

It lets agent-written code use your API without ever receiving your credential, your base URL, or general network access. The bearer is minted per run, stays in Go, and is attached host-side only after the caller and the exact route have been authorized. Code that ignores the injected client and calls out by hand does not get further, because the broker rather than the client is what enforces the policy. See docs/capability-grants.md.

Run something in one minute

Cloning and fetching Go dependencies may use the network. The example itself needs no daemon, docker, credentials or outbound network access: it selects the in-process WASM provider.

git clone https://github.com/plimsollmark/plimsoll && cd plimsoll
go run ./examples/minimal
provider   wasm
isolation  process
exit code  0
timed out  false
truncated  stdout=false stderr=false
duration   304ms
stdout     {"Engineering":59000000,"Sales":20300000,"Operations":9800000}

That isolation line is the run's own evidence, not a claim by the example. process is not an OS boundary and is not a production posture for hostile code. The same snippet runs behind a real kernel boundary once gVisor is installed, and nothing else about the program changes:

SANDBOX_PROVIDER=docker SANDBOX_DOCKER_RUNTIME=runsc go run ./examples/minimal

With SANDBOX_PROVIDER unset, the factory selects the Disabled provider and runs nothing. Execution is opt-in and cannot be switched on by accident.

Next: docs/getting-started.md takes the same pieces in order on one machine, from an in-process daemon to a kernel-tier one, with a caller credential, your own client program, and a floor refusing a run before it starts. It also covers embedding the package instead of running the daemon.

Where the pieces sit

flowchart LR
  A["Agent or MCP gateway"] -->|"Run: one payload, a protocol number, minimum_isolation"| AU

  subgraph D["plimsolld"]
    AU["authenticate the caller"] --> FL["compare the floor with current provider evidence"]
    FL --> DI["dispatch"]
    BR["broker: holds the minted credential, matches the exact route, counts every call"]
  end

  DI --> W["wasm: QuickJS on wazero (process tier)"]
  DI --> K["docker with runsc (kernel tier)"]
  DI --> V["e2b Firecracker (VM tier)"]

  W -. "host.get / host.post" .-> BR
  K -. "per-run Unix socket" .-> BR
  V -. "authenticated guard" .-> BR
  BR ==> |"your credential, attached host-side"| API["Your API"]

The guest never holds the credential and never reaches the network directly. A run with no grant reaches nothing at all.

Isolation tiers

Provider Boundary Tier reported Use
wasm QuickJS on wazero, inside plimsolld itself process The inner loop. An engine escape lands in your daemon.
docker with runc container, sharing the host kernel container Self-hosting where the kernel boundary is not the threat model.
docker with runsc gVisor, after a verified preflight kernel Hostile code, self-hosted.
e2b Firecracker microVM vm Hostile code, on runners off your host.
dockercloud Docker Cloud Sandboxes microVM vm Hostile code, on Docker-managed runners. Implemented against Docker's published API contract; the live suite passed against the real service on 2026-09-24. Requires the account's cloud network policy to default to deny-all, which every run verifies. Host-API grants through the same guard as E2B when SANDBOX_DOCKERCLOUD_GUARD_URL is set; unlike E2B, the guest holds its own run's short-lived, guard-only credential, and the one network rule is applied through a Docker call outside its published contract.
openshell an NVIDIA OpenShell sandbox on the gateway's docker driver container Agent platforms that already run an OpenShell gateway. Each run gets its own sandbox with no network, read back and refused on any difference, and deleted afterwards. Verified against a v0.1.2 gateway on 2026-09-28. Grants reach the broker through a relay plimsoll dials into, so the sandbox keeps no network rules; sessions keep one sandbox for many calls.
unset nothing runs n/a The default.

Every tier is configuration plus provider evidence plus a behavioural startup smoke test, never runtime attestation. The full evidence chain, and how a caller demands a floor per request, are in docs/isolation-tiers.md.

Status, plainly

  • Pre-1.0, single author, no external users yet. Breaking changes land without a deprecation path, on purpose.
  • No third-party security audit has ever been performed, and the author's own self-review ledgers are not published either. SECURITY.md says what exists, what it is worth, and what you can check yourself instead.
  • CI runs the gate, in the open, and each check means what it ran. The audit workflow has two jobs. audit runs plain make audit on every push and pull request: build, vet, race tests, lint, buf lint, a generated-code drift check, and govulncheck. audit-docker then runs make docker-suite with the images prepared, in required mode: a missing daemon, a missing image or a skipped test fails the job. A green audit-docker therefore means the docker suite ran under runc with the shipped seccomp profile and proved a read-only root, sized noexec writable mounts, and the broker's refusals. The gvisor workflow runs the same suite under runsc, the kernel tier, from the pinned installer. The race detector runs in the plain audit job; the two provider jobs run their isolation tests without it. No check exercises E2B or Docker Cloud Sandboxes: those suites drive live paid services and are deliberately never wired to a runner. See CONTRIBUTING.md.

Learn how it works

The interactive lessons are the fastest way in if you would rather read than clone. Start with Plain English if you want the idea before the API, or Quick start if you want to run something. They live in docs/trainers/ and work offline: open any file from a clone in a browser. GitHub shows .html files as source rather than rendering them, which is why the links above point at the published copy.

Documentation

Each of these answers one question, end to end.

Document Answers
docs/getting-started.md How do I build it, embed it, start it as an authenticated service, and watch a floor be refused?
docs/example-programs.md What do the nine runnable examples prove, and which should I read first?
docs/isolation-tiers.md What does each tier rest on, and how do I demand one per request?
docs/capability-grants.md How does agent code call my API without ever holding my credential?
docs/run-results.md What comes back, and when is a failure an error rather than a result?
docs/run-records.md What does each run's record state, how do I recompute it in another language, and how does a harness sign, verify and replay records?
docs/sessions.md How do I keep one sandbox for many calls, and what holds between the calls?
docs/placement.md I run several daemons: how do I pick one per request, and when is a refusal safe to retry elsewhere?
docs/inner-loop-workflow.md How do I iterate fast locally without shipping a weak sandbox to production?
docs/efficiency-advisor.md What does the advisor see, why can its telemetry not carry guest content, and how do I configure what it emits?
docs/hardened-mode.md How do I turn the production posture into an enforced startup policy?
docs/dependencies.md What is in the trusted surface, and who checks the checkers?
docs/limitations.md What does this deliberately not do?
docs/dockercloud.md What does the Docker Cloud Sandboxes provider need from the operator, and what does each run check?
docs/openshell.md What does the OpenShell provider need from the operator, and what does each run check?
docs/releasing.md Why is the module path public, why do releases start at v0.2.0, and why is there no checksum exemption?
docs/callers.md How do I create, rotate and revoke caller credentials?
docs/seccomp.md and docs/gvisor.md What do the syscall filter and the kernel-tier boundary enforce?
docs/guest-dependencies.md How do guest packages get in when a run has no network?
docs/architecture/credential-minting.md Where does a per-run credential come from, and where does it stay?
docs/seams.md Where are the deliberate extension points?
AGENTS.md The architecture reference: providers, invariants, the full environment list.

License

Apache-2.0.

Directories

Path Synopsis
Package attest is the harness's half of plimsoll's run records: it signs a checked record as a DSSE envelope around an in-toto Statement v1, verifies envelopes and whole bundles (signatures, digests, and each session's chain), and replays stored requests to compare results.
Package attest is the harness's half of plimsoll's run records: it signs a checked record as a DSSE envelope around an in-toto Statement v1, verifies envelopes and whole bundles (signatures, digests, and each session's chain), and replays stored requests to compare results.
Package client dials a remote plimsolld and adapts it to sandbox.Sandbox, so isolated calls can swap providers behind the same interface.
Package client dials a remote plimsolld and adapts it to sandbox.Sandbox, so isolated calls can swap providers behind the same interface.
cmd
plimsoll-attest command
Command plimsoll-attest is a harness for plimsoll's run records, run outside the daemon: it makes a signing key, runs a request and signs its checked record into a bundle, verifies a bundle (signatures, digests, session chains), and replays a bundle's single runs to compare results.
Command plimsoll-attest is a harness for plimsoll's run records, run outside the daemon: it makes a signing key, runs a request and signs its checked record into a bundle, verifies a bundle (signatures, digests, session chains), and replays a bundle's single runs to compare results.
plimsoll-clients command
Command plimsoll-clients manages caller credentials in an offline registry.
Command plimsoll-clients manages caller credentials in an offline registry.
plimsoll-specgen command
Command plimsoll-specgen derives a host-API grant description from an OpenAPI 3.x document (Sluice "spec-import").
Command plimsoll-specgen derives a host-API grant description from an OpenAPI 3.x document (Sluice "spec-import").
plimsolld command
Command plimsolld serves the plimsoll SandboxService over Connect (h2c, so Connect, gRPC, and gRPC-Web clients all work).
Command plimsolld serves the plimsoll SandboxService over Connect (h2c, so Connect, gRPC, and gRPC-Web clients all work).
prospector-report command
Command prospector-report renders plimsoll's exported audit stream into a single self-contained HTML report (Prospector Phase 4) — the no-Grafana companion to the dashboard.
Command prospector-report renders plimsoll's exported audit stream into a single self-contained HTML report (Prospector Phase 4) — the no-Grafana companion to the dashboard.
examples
advisor command
Command advisor shows the efficiency advisor end to end: the same question asked of a small inventory API twice, first the way an agent tends to write it (list the ids, then one call per item, then add the column up in its own code) and then the way the advice that came back suggests.
Command advisor shows the efficiency advisor end to end: the same question asked of a small inventory API twice, first the way an agent tends to write it (list the ids, then one call per item, then add the column up in its own code) and then the way the advice that came back suggests.
daemon command
Command daemon runs the whole service path end to end: it starts plimsolld with a real multi-client auth file, calls it with the official Go client, and shows what the server refuses.
Command daemon runs the whole service path end to end: it starts plimsolld with a real multi-client auth file, calls it with the official Go client, and shows what the server refuses.
grant command
Command grant demonstrates the capability model: agent-authored code reaching a real HTTP API through an injected client, over a route allowlist the code cannot widen, with a credential it never sees.
Command grant demonstrates the capability model: agent-authored code reaching a real HTTP API through an injected client, over a route allowlist the code cannot widen, with a credential it never sees.
internal/daemonproc
Package daemonproc builds plimsolld from source and runs it on a loopback port for the example programs, so an example exercises the real daemon, not a copy of its wiring.
Package daemonproc builds plimsolld from source and runs it on a loopback port for the example programs, so an example exercises the real daemon, not a copy of its wiring.
internal/wasmshim
Package wasmshim holds the Node shim that runs a controller compiled to WebAssembly under the judge: controller.js, sent as a project file beside controller.wasm.
Package wasmshim holds the Node shim that runs a controller compiled to WebAssembly under the judge: controller.js, sent as a project file beside controller.wasm.
minimal command
Command minimal runs one JavaScript snippet in a sandbox and prints what ran, where, and behind which isolation boundary.
Command minimal runs one JavaScript snippet in a sandbox and prints what ran, where, and behind which isolation boundary.
oracle command
Command oracle is the physics oracle demo: an agent writes a controller, plimsoll runs it against a compiled cart-pole plant, and the trajectory's fingerprint is the acceptance test.
Command oracle is the physics oracle demo: an agent writes a controller, plimsoll runs it against a compiled cart-pole plant, and the trajectory's fingerprint is the acceptance test.
providers command
Command providers runs the physics oracle's run on every provider this machine can reach and writes a page comparing them: the same controller, the same judge, the same plant, and the fingerprint of the trajectory from each provider.
Command providers runs the physics oracle's run on every provider this machine can reach and writes a page comparing them: the same controller, the same judge, the same plant, and the fingerprint of the trajectory from each provider.
sessions command
Command sessions runs one session on an NVIDIA OpenShell sandbox through the real daemon, with the harness signing every call, and writes a page that shows the calls, their chained records, and the verifier accepting the signed bundle and refusing it with one call dropped or one byte changed.
Command sessions runs one session on an NVIDIA OpenShell sandbox through the real daemon, with the harness signing every call, and writes a page that shows the calls, their chained records, and the verifier accepting the signed bundle and refusing it with one call dropped or one byte changed.
wasm-buck command
Command wasm-buck judges a buck converter controller written in C: the project run compiles it to WebAssembly inside the sandbox, then runs it against the buck plant, which is WebAssembly too, under the same shim as examples/wasm-controller.
Command wasm-buck judges a buck converter controller written in C: the project run compiles it to WebAssembly inside the sandbox, then runs it against the buck plant, which is WebAssembly too, under the same shim as examples/wasm-controller.
wasm-controller command
Command wasm-controller judges a controller written in C: the project run compiles it to WebAssembly inside the sandbox, then runs it against the cart-pole plant, which is WebAssembly too.
Command wasm-controller judges a controller written in C: the project run compiles it to WebAssembly inside the sandbox, then runs it against the cart-pole plant, which is WebAssembly too.
gen
go/plimsoll/v1/plimsollv1connect
Package plimsoll.v1 is the RPC surface of the standalone code-execution sandbox.
Package plimsoll.v1 is the RPC surface of the standalone code-execution sandbox.
internal
clientconfig
Package clientconfig defines the caller registry shared by the daemon and the offline operator CLI.
Package clientconfig defines the caller registry shared by the daemon and the offline operator CLI.
grants
Package grants resolves named host-API capability profiles for the RPC server.
Package grants resolves named host-API capability profiles for the RPC server.
insights
Package insights derives deterministic, metadata-only efficiency findings from a run's brokered host.* call trace (Prospector Phase 1).
Package insights derives deterministic, metadata-only efficiency findings from a run's brokered host.* call trace (Prospector Phase 1).
quantise
Package quantise reports the resolution at which a module run's swept parameter was actually resolved, which is not always the resolution the caller asked for.
Package quantise reports the resolution at which a module run's swept parameter was actually resolved, which is not always the resolution the caller asked for.
report
Package report renders plimsoll's exported audit stream into a single self-contained, dependency-free HTML report (Prospector Phase 4).
Package report renders plimsoll's exported audit stream into a single self-contained, dependency-free HTML report (Prospector Phase 4).
rpc
Package rpc serves the plimsoll SandboxService over Connect, wrapping the transport-agnostic sandbox package with auth, rate limiting, and request validation.
Package rpc serves the plimsoll SandboxService over Connect, wrapping the transport-agnostic sandbox package with auth, rate limiting, and request validation.
specgen
Package specgen derives a plimsoll host-API grant description from an OpenAPI 3.x document.
Package specgen derives a plimsoll host-API grant description from an OpenAPI 3.x document.
toolchain
Package toolchain exposes the single source of truth for the baked TypeScript toolchain versions (the repo-root toolchain.versions file), shared by the docker provider image and the e2b template so they cannot drift.
Package toolchain exposes the single source of truth for the baked TypeScript toolchain versions (the repo-root toolchain.versions file), shared by the docker provider image and the e2b template so they cannot drift.
Package placement chooses which plimsoll daemon runs a request, and sends it there.
Package placement chooses which plimsoll daemon runs a request, and sends it there.
Package protocol holds the one number the wire protocol is versioned by.
Package protocol holds the one number the wire protocol is versioned by.
Package record computes the digests in a plimsoll run record: what a caller sent, what came back, and the record that states both with the evidence the run executed under.
Package record computes the digests in a plimsoll run record: what a caller sent, what came back, and the record that states both with the evidence the run executed under.
Package sandbox runs untrusted, agent-authored code through an explicitly tiered execution provider.
Package sandbox runs untrusted, agent-authored code through an explicitly tiered execution provider.
internal/runnerwire
Package runnerwire is the host side of the in-sandbox project runner protocol (docker/runner.mjs): the JSON plan a provider writes to the runner's stdin, the authenticated frame that carries the runner's report on its stdout, and the decoding and classification of that report.
Package runnerwire is the host side of the in-sandbox project runner protocol (docker/runner.mjs): the JSON plan a provider writes to the runner's stdin, the authenticated frame that carries the runner's report on its stdout, and the decoding and classification of that report.
openshell
Package openshell runs plimsoll snippets and projects in NVIDIA OpenShell sandboxes, through an OpenShell gateway's gRPC API (openshell.v1, vendored at v0.1.2 under third_party/openshell and generated into gen/go/openshell).
Package openshell runs plimsoll snippets and projects in NVIDIA OpenShell sandboxes, through an OpenShell gateway's gRPC API (openshell.v1, vendored at v0.1.2 under third_party/openshell and generated into gen/go/openshell).
sessiontest
Package sessiontest is the session conformance suite: the behavior every sandbox.SessionProvider promises, checked with node snippets and project steps through the provider itself.
Package sessiontest is the session conformance suite: the behavior every sandbox.SessionProvider promises, checked with node snippets and project steps through the provider itself.
Package sandboxtest provides shared test helpers for projects that embed the plimsoll sandbox, so the cross-cutting guarantees are asserted by ONE implementation here instead of being copy-pasted into every consumer's tests.
Package sandboxtest provides shared test helpers for projects that embed the plimsoll sandbox, so the cross-cutting guarantees are asserted by ONE implementation here instead of being copy-pasted into every consumer's tests.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL