Skip to content

Latest commit

 

History

History
61 lines (51 loc) · 12 KB

example-programs.md

File metadata and controls

61 lines (51 loc) · 12 KB

The example programs

Go programs, a shell recipe and a TypeScript example: what each shows, what it needs, and the one to read if you only read one. Part of the plimsoll README.

minimal, grant, daemon and advisor need no docker, credentials or daemon you start yourself. oracle, wasm-controller, wasm-buck and adapter need docker and the images make docker-images builds. providers additionally uses any hosted or gateway provider, a backend that runs the code, it has settings for, including paid services. sessions needs an OpenShell gateway, NVIDIA's server for creating sandboxes.

agentsandbox, capsule and sbom rebuild pages from recorded evidence offline. Run Go examples from the repository root; capsule (Go 1.27) and sbom have their own modules, so their commands change directory first. The pull-request receipt (INTERNAL · glossary →) recipe needs docker, gVisor (INTERNAL · glossary →) and the containerd image store, which stores the exact image descriptions it records. The TypeScript example uses npm from its own directory.

Command What it shows
go run ./examples/minimal One snippet, its result, and the isolation tier the run reports: how strong the wall around it was.
go run ./examples/grant How a grant, one run's permission to call listed routes of an API, works: a permitted route, a refused one, the same refusal when the guest (the code in the sandbox) skips the client plimsoll gave it and calls out by hand, the same request succeeding in a separate run whose grant lists it, and a search for the credential that finds nothing.
go run ./examples/daemon The service: plimsolld, the plimsoll server, started with a real file of callers, called by the Go client, refusing a floor (a minimum tier) it cannot meet and refusing a wrong token. Each refusal is checked for its specific error: ErrInsufficientIsolation, and unauthenticated from Connect, the RPC library plimsolld speaks. A request that merely failed is not proof the protection fired.
go run ./examples/advisor The efficiency advisor, which reads the API calls a run made: one question asked twice of a fake inventory API. First as a loop with one request per item (13 requests, and a fan_out finding naming the route, already allowed by the grant, that returns the whole list), then as the advice suggests (1 request, no findings). Same answer both times.
go run ./examples/oracle The physics oracle, which tests code by what it makes a simulation do. An agent-written controller (a program that decides at every tick, one 10 ms step of the simulation, how to push the cart) is the only file of a project run. It runs against a cart-pole simulator (a cart on a rail with a pole hinged on top, to be kept upright), compiled to WebAssembly (a portable bytecode) and built into the module image. The runner, a program also built into the image, runs the controller as a separate process, records its trajectory (every state at every tick), and hashes that into a fingerprint: a SHA-256 hash, so equal fingerprints mean identical numbers. The accepted controller runs twice (one fingerprint), the agent's draft once (another, and it drops the pole at 5.96 s). The page it writes, live: the physics oracle, which replays the recorded runs (source: docs/examples/oracle/index.html).
go run ./examples/providers The oracle's run on every provider the machine can reach, each built the way plimsolld builds it: the same accepted controller, runner and cart-pole simulator, sent as ordinary project files so no special image is needed, and each provider proven ready before its run counts. The page it writes, live: same run, different sandboxes, shows each provider's isolation tier, Node version and fingerprint beside the one the oracle page published (source: docs/examples/providers/index.html). The rows for E2B and Docker Cloud Sandboxes, two hosted services that run each request in its own small virtual machine, need their credentials and are billed; the OpenShell row needs a gateway.
go run ./examples/wasm-controller A controller in a compiled language. A cart-pole swing-up controller (it swings the pole up from hanging, then balances it) is written in C and sent as a file of a project run, whose first step compiles it to WebAssembly inside the sandbox (plimsoll/sandbox-wasm-cc). The image's generic trial runner runs it against the same simulator on four scenarios, through a small Node adapter that gives the compiled module no outside functions to call. Two runs give one hash of the compiled module and one fingerprint per scenario, with the pole up within 2.5 s in each. Two more runs compare it with the same control law (the formula the controller applies at each tick) in JavaScript, and with the same C built against Node's Math.cos. The page it writes, live: a controller in C, checked by its trajectory, replays the swing-up and shows, tick by tick, that the C and JavaScript records differ only in the last bits of a few force values, while the motion is bit-identical (source: docs/examples/wasm-controller/index.html). Its README says why the fingerprints differ from the JavaScript version's (the last bit of cos) and what the example does not prove.
go run ./examples/wasm-buck A controller in C for a buck converter, a power supply that steps a voltage down by switching it on and off many times a second. It uses the same adapter, runner and compile step, and holds 5 V out from 10 to 16 V in through a load that halves at an unknown moment. Two C runs and one JavaScript run of the same control law give one module hash, and in every scenario the C trajectory equals the JavaScript one byte for byte: the law calls no library function, and the compiler is told not to merge a multiply and an add into one step (which would round differently). The page it writes, live: a buck converter controller in C, charts, tick by tick, the output voltage, the current through the converter's coil (inductor current) and the share of each cycle its switch is on (duty cycle) (source: docs/examples/wasm-buck/index.html). Its README says what it does not prove.
go run ./examples/sessions A session, one sandbox kept for many calls (sessions.md), on an OpenShell sandbox through plimsolld. A harness, a program outside the daemon, signs every call's run record, the daemon's statement of what was sent, what came back and where it ran (run-records.md). The calls: a project whose test fails, a snippet that patches the file in place, the test passing without the files being sent again, a snippet that leaves a background process running, and a snippet that finds it gone. The signed set of records is verified, then refused once with one call dropped and once with one byte of output changed. The page it writes, live: one sandbox, five calls, with the signed set and the harness's public key beside it (source: docs/examples/sessions/). Needs a gateway and the five SANDBOX_OPENSHELL_* settings; spends nothing.
cd examples/capsule && go run . Each call of the sessions example's signed bundle, once the attest verifier accepted it, stated as an Agent Action Capsule and checked by that project's Go and Python verifiers. Its own Go module, because the capsule code needs Go 1.27 and dependencies plimsoll does not take on.
go run ./examples/adapter An AI-written adapter, code that connects a platform to a device vendor's API, tried against a simulated robot fleet. The host checks its reported answers against the vendor's ledger under faults, lost answers and refusals, and signs the qualification verdict, the result of those checks. Needs docker. INTERNAL · adapter contract →; INTERNAL · recorded fleet replay →.
cd examples/sbom && go run . Signed run records converted to CycloneDX 1.6 software bills of materials, ingredients labels carrying the run's evidence. Offline conversion and checking; no new sandbox. INTERNAL · converter guide →; INTERNAL · interactive receipt checks →.
go run ./examples/agentsandbox Rebuilds the evidence page from recorded Kubernetes agent-sandbox runs, the Kubernetes component that lends ready pods from a pool. It checks the signed records and refuses altered evidence; it starts no cluster. INTERNAL · recorded runs, comparison and refusals →; INTERNAL · live deployment guide →.
make receipt-suite Exercises the pull-request receipt recipe locally: tracked project files and their test command run under gVisor, then a signed record and a bill of materials are checked. Needs docker, gVisor and the containerd image store. This command posts no comment. INTERNAL · recipe and workflow template →; INTERNAL · recorded receipt →.
examples/trigger-chat (npm) A Trigger.dev (a hosted job runner for TypeScript) chat agent with an executeCode tool (one named action the agent's model can call), written on Trigger.dev's own code-sandbox recipe with plimsoll as the sandbox, through the TypeScript client in clients/typescript. The tool runs Python or JavaScript and takes files, so the model hands the code another tool's output by path. On a daemon with sessions the run keeps one sandbox, warmed when a turn starts and closed right before the run sleeps, and every call runs in an interpreter that stays alive, so data loaded in one call is still in memory in the next; elsewhere each call runs fresh and the tool says nothing was kept. Its test drives two turns through Trigger.dev's offline harness and checks that one interpreter served every call, that a file reached it, and that the suspend closed the sandbox. Needs a plimsolld, a Trigger.dev project and a model key; its README says how.

examples/grant is the one to read if you only read one. After each step it prints the run's CallTrace: the list of API calls the broker made for the code (the broker is the part of plimsoll that makes those calls and holds the credential). The list records only the route, the status, the sizes and the time taken, never the data, and the efficiency advisor and the audit log are built from it:

1. a route the grant lists
   guest | ok: Engineering 46600000
   trace | #1 GET /v1/employees/*/comp -> 200, 0B in 39B out, 1ms

3. the same forbidden route, bypassing the client
   guest | broker answered: 403 forbidden by sandbox capability allowlist
   trace | 0 call(s), 1 denied by policy, 0 shed for backpressure, 0 dropped

4. the same request, in a run handed a separate grant that lists the route
   guest | ok: {"ssn":"000-00-0000"}
   trace | #1 GET /v1/employees/*/ssn -> 200, 0B in 21B out, 1ms

Scenes 3 and 4 send the identical request. The guest did not change and the API did not change; the run was handed a different grant, and the grant is what decides.

Note what the list holds: the route pattern the request matched, such as /v1/employees/*/comp, never the exact path that was requested. CallRow has no field for a path, query, body or credential, so none can be recorded by accident.