Containerized agent harnesses #
This document owns the boundary between thought stream and long-running or tool-using agent harnesses. It does not widen the existing model observer cell by changing what that cell is allowed to do. The observer cell and a workspace harness are different security profiles with different protocols and proof obligations.
Terms #
- Trusted parent: the thought stream consumer process. It resolves declarations, reserves accounting capacity, provisions bounded resources, starts provider brokers, validates results, and writes lifecycle evidence.
- Harness adapter: code inside an isolated execution environment that translates the generic run packet into one concrete agent runtime. Pi coding-agent is the first adapter.
- Isolation profile: a named, versioned set of mounts, network access, process limits, and broker limits. Profiles are trusted configuration, not prompt-controlled values.
- Workspace lease: one already-provisioned directory that the harness may mutate for the duration of a run. It is not an arbitrary host path supplied by an agent declaration. Every file in the lease is deliberately disclosed to the harness; workspace provisioning must exclude credentials and unrelated private material.
- State lease: one separate private directory for adapter-owned persistent state, such as Pi session JSONL. It never contains provider credentials, but it can contain prompts, model text, tool calls, and other conversation state. It is excluded from ordinary traces, notifications, inspection surfaces, and training export.
- Provider lease: a capability-scoped Unix-socket broker authorizing a bounded number of requests and cumulative bytes for one run, profile, model, route, deadline, and token ceiling.
Profiles #
observer-v1 #
The existing Bubblewrap worker is an inference cell:
- no project workspace;
- no shell, child process, extension, or file-mutation capability;
- scratch storage only;
- one provider request through a single-use broker capability;
- one typed final value returned to the trusted parent.
This profile remains the mandatory path for ordinary observation and repair consumers. Its current Pi worker uses tools: []. Passing its tests proves only this profile.
workspace-v1 #
The workspace profile is for a full coding harness:
- one read-write workspace lease mounted at
/workspace; - one read-write state lease mounted at
/state; - a read-only container root filesystem;
- bounded in-memory
/tmpand home directories; - no inherited environment, host home, host repository root, credential file, device, Docker socket, or additional host mount;
- no IP network interface capable of external traffic;
- provider access only through
/broker/provider.sock; - an unprivileged uid/gid, all Linux capabilities dropped,
no-new-privileges, a default seccomp profile, and explicit process, memory, CPU, descriptor, output, and wall-clock limits; - a provider lease with explicit request-count and cumulative request/response-byte budgets;
- no external action capability. A shell inside the workspace container is authority over the leased workspace, not authority to send, publish, deploy, or mutate thought stream.
The container image is resolved to an immutable image id before launch and included in the run receipt. If the configured runtime, image, broker, workspace lease, state lease, or required kernel isolation is unavailable, the run fails closed. There is no trusted-host fallback.
letta-cloud-v1 #
This profile delegates agent execution to a Letta Agent SDK managed Cloud sandbox:
- the trusted thought stream parent holds
LETTA_API_KEYand creates the SDK client; - the declaration supplies only a resolved Cloud agent id and bounded session policy;
- Letta owns sandbox creation, refresh, and TTL cleanup;
- the agent's main conversation and memory persist outside Jazz;
- Cloud reasoning, tool calls, tool results, and assistant messages stream back through the SDK;
- the adapter closes the SDK session after each thought stream turn and does not terminate a shared sandbox eagerly by default;
- thought stream channel credentials, Jazz credentials, host environment, live root, repository, and local files are never attached as resources or forwarded as SDK tools.
This profile permits the Letta harness tools and skills selected by trusted declaration policy. Their effects occur inside the managed sandbox unless the Cloud agent has separately provisioned external credentials or server-side tools. Such credentials and tools are outside thought stream's authority and require explicit operator provisioning. A Cloud sandbox claim is provider-managed containment, not a locally reproduced workspace-v1 proof.
Bind mounts also require trusted lease-level byte and inode quotas. The per-process file-size limit is only a backstop; it is not a total disk-usage boundary. Activation therefore requires quota receipts from the workspace/state lease provisioner and adversarial disk-fill tests. A host or lease backend without enforceable total quotas is not eligible for workspace-v1.
Generic run contract #
The trusted parent selects an adapter and profile from trusted configuration. A declaration may name an allowlisted adapter/profile pair but cannot provide:
- a container image or entrypoint;
- a host path or arbitrary mount;
- a provider URL, route, credential reference, or broker budget;
- container runtime flags, environment values, uid/gid, capabilities, devices, or network mode;
- executable extension paths.
The parent validates every host path by realpath against the configured lease root before invoking the container runtime. The run packet contains container-internal paths only. It includes:
- protocol version, run id, adapter id/revision, and isolation profile id;
- bounded prompt and system instructions;
- model descriptor and provider capability;
- tool allowlist owned by the adapter/profile pair;
neworresumesession intent and an opaque session id when resuming;- output and trace byte ceilings.
Input and output use one length-prefixed JSON frame on stdin/stdout. Stderr is bounded diagnostic transport and is never treated as a result. The parent rejects duplicate frames, trailing bytes, oversized frames, run-id mismatch, adapter mismatch, invalid schemas, timeout, nonzero exit, and any result that exceeds the declared output contract.
The result reports only:
- run id and terminal status;
- adapter and session identity;
- the final assistant artifact allowed by the caller's output policy;
- bounded tool-execution receipts containing tool name, status, and counts rather than shell output or arguments;
- usage and provider revision when trustworthy;
- container image id and isolation profile in the parent-owned launch receipt.
Raw provider bodies, reasoning, tool arguments, shell output, environment values, credentials, and arbitrary exception strings do not enter durable thought stream evidence. Pi's private state lease is a distinct persistence surface and is governed by the retention and access rules above rather than being mislabeled as metadata-only evidence.
Pi coding-agent adapter #
pi-coding@1 is the first workspace-v1 adapter. It uses the pinned @earendil-works/pi-coding-agent SDK and its built-in coding tools inside the container. The adapter:
- uses in-memory settings and credential storage;
- supplies only a broker placeholder key;
- disables automatic extension, skill, prompt-template, and theme discovery;
- does not load executable code from
.pi/extensions, global Pi configuration, or package sources named by the workspace; - may load bounded project context files as data only when the profile explicitly allows it;
- stores session state only under
/stateand operates only under/workspace; - performs every model turn through the provider lease;
- cannot change the selected model, route, token ceiling, request budget, or isolation profile.
Third-party Pi extensions are executable code. They are not accepted by path or package name merely because Pi supports extensions. A future extension-capable profile requires a reviewed, content-addressed extension bundle in the container image plus its own adversarial proof.
Lifecycle and authority #
A harness run begins only after the normal inference reservation and a parent-owned launch receipt are ready. started does not mean a useful artifact exists. The parent settles accounting and writes terminal evidence using the same recovery rules as other model-backed consumers.
Workspace mutations are artifacts inside the lease. They are not automatically commits, pushes, deployments, messages, or accepted thought stream outputs. Any future promotion step is a separate trusted action with separate authorization and receipts.
Persistent session state does not make the container durable. Each invocation is a new disposable container that receives only the selected workspace and state leases. A resumed session must match its adapter, profile, exact image id, workspace identity, and model policy. Mismatch fails closed rather than silently creating or selecting a nearby session.
Implementation status #
The Bubblewrap observer-v1 path is already used by model-backed observation and repair consumers. The Docker workspace-v1 launcher and pi-coding@1 adapter are a source-level reference implementation and test target until separately activated by trusted configuration. Their presence in the repository is not deployment evidence. Activation remains blocked until the target runtime passes memory-controller admission and the lease provisioner supplies enforceable total byte and inode quotas.
The letta-agent-sdk / letta-cloud-v1 adapter is independently activatable after its declaration, recovery, privacy, and live Cloud canary gates pass. Its managed Cloud sandbox does not remove the remaining activation blockers from local workspace-v1; the profiles have different operators and evidence.