Add a coherent set of long-running-agent capabilities, each as a spec section + reference implementation + conformance class, every one metered, attested, and receipt-chained. Sandbox: - §13 Durable run records (C6): the receipt chain IS the resumable run; execute/suspend/resume segments hash-chained; idle energy metered across parks. (sandbox-attest::runrecord) - §14 Environment manifest (C7): devcontainer.json declarative-subset ingestion -> canonical, content-addressed, signed manifest; command/widening and unknown fields refused. (sandbox-attest::manifest) - §5.5 Content-addressed process control (C8): exec allow/deny by BLAKE3 of the binary; denylist absolute, survives rename/move/wrapper. - §15 Warm pools (C9): a claim attributes accrued idle energy to the run (a fast start has a visible joule price); evictions record overhead, not zero. (sandbox-attest::warmpool) - §16 Fleet records (C10): merkle aggregate receipt over per-item runs; log-size membership proofs. (sandbox-attest::fleet) - durable.json cross-impl wire vectors + file-backed verify. JCP: - §4.6 Standing grants (C20): a signed mint policy turns a held grant into bounded, rate-limited, event-triggered children via the attenuation path. (jcp-grant::standing) - §4.7 Checkpoints + amendments (C21): mid-run steering under separation of duties — the agent checkpoints its own state, only the issuer (a distinct principal) may amend, and only to tighten. (jcp-grant::checkpoint) - standing.json cross-impl vectors. Both workspaces green; conformance harnesses pass with no skips; clippy clean. Co-Authored-By: Claude Opus 4.8 <[email protected]>
61 lines
3 KiB
Markdown
61 lines
3 KiB
Markdown
# The environment manifest
|
|
|
|
A receipt says what a unit cost; an attestation says who ran it, where, at
|
|
what tier. Neither says **in what environment** — which base image, which
|
|
tool features, which variables and mounts. For short runs that gap is
|
|
tolerable. For durable runs (§13) it is not: a run suspended on one host and
|
|
resumed on another is only the *same run* if it resumes into the *same
|
|
toolchain*, and "same" must be checkable by hash, not asserted by trust.
|
|
|
|
The **environment manifest** closes the gap: one canonical object whose
|
|
BLAKE3 content address stands for the whole declared environment.
|
|
|
|
## Ingestion: the devcontainer format
|
|
|
|
Environments are declared in the open Development Containers specification
|
|
(`devcontainer.json`) — already the common declaration format across the
|
|
industry. This standard ingests its **declarative subset**:
|
|
|
|
| accepted | meaning |
|
|
|---|---|
|
|
| `image` | base image reference; a `@sha256:` digest marks the manifest **pinned** |
|
|
| `features` | tool features, normalized to (id, JCS-canonical options), sorted |
|
|
| `containerEnv` | environment variables, sorted |
|
|
| `mounts` | string or object form, normalized to (source, target, kind), sorted by target |
|
|
| `remoteUser` | the user the unit runs as |
|
|
|
|
Cosmetic and editor-facing fields (`name`, `customizations`, …) are accepted
|
|
and excluded from identity. Networking fields (`forwardPorts`, `appPort`, …)
|
|
are likewise excluded: the network surface is governed by the capability
|
|
grant (§5), never by the environment declaration.
|
|
|
|
**Refused fields.** Anything that executes commands or widens the sandbox is
|
|
refused with an error, not skipped: `build`, `dockerFile`,
|
|
`dockerComposeFile`, the five lifecycle `*Command` hooks, `runArgs`,
|
|
`privileged`, `capAdd`, `securityOpt`. Lifecycle automation belongs to the
|
|
unit and its grants, where it is metered and attested — not smuggled into an
|
|
identity object. **Unknown fields are also refused**: silently dropping a
|
|
field a future devcontainer revision makes execution-relevant would mint a
|
|
false identity.
|
|
|
|
## Canonical form, address, signature
|
|
|
|
The manifest core (`schema: "sandbox.env-manifest/1"`) is JCS-canonicalized;
|
|
its BLAKE3 address is the environment's identity; it is signed Ed25519 over
|
|
the canonical bytes, mirroring the attestation convention (§7.3). Key order
|
|
and whitespace in the source document do not affect the address.
|
|
|
|
A manifest without an image digest is **unpinned**: its address identifies a
|
|
declaration, not bytes. Hosts SHOULD treat unpinned manifests the way the
|
|
energy receipt treats estimates — usable, but labelled, and never the basis
|
|
for a "same environment" claim across hosts.
|
|
|
|
## Use in durable runs
|
|
|
|
`SnapshotRef.manifest` (§13) records the manifest address at suspension.
|
|
Resumption MUST be refused when the offered environment's manifest address
|
|
differs — same filesystem plus a drifted toolchain is a different snapshot.
|
|
Conformance class **C7** exercises ingestion determinism, the refusals, and
|
|
this linkage.
|
|
|
|
The reference implementation is `sandbox_attest::manifest`.
|