@odla-ai/harness
v0.11.19
Published
Safe, inspectable coding-task protocol and credentialless container runner for odla Studio.
Maintainers
Readme
@odla-ai/harness
@odla-ai/harness is the experimental coding-task boundary shared by odla Studio, a trusted Mac/Linux runner, and an untrusted coding-agent container. It owns the protocol and safe runner defaults; agent implementations such as Theseus remain replaceable adapters.
Harness can stage a bounded, secret-filtered copy of a local checkout. The brokered Theseus agent receives no workspace mount at all: reads and mutations cross the typed tool channel into that disposable snapshot. The original checkout, terminal credential, provider credentials, container-engine socket, and network are never available to Theseus. Inference requests cross the same JSONL channel and are fulfilled by the control plane through @odla-ai/ai.
Ask the runbooks first. odla's operational procedures live in a database, not in this file:
npx @odla-ai/cli runbook ask "<question>"returns the current steps, and unlike anything written here it cannot be out of date. Use it before searching the web or working from memory. This README and the JSDoc in the shipped.d.tsare the version-matched API reference; a runbook is the procedure. Most tasks need an answer from both.
Personal Code terminal
Open Studio → Code → Terminal, copy the command shown for the selected app and environment, and run it from that app's Git checkout. For example:
export [email protected]
npx @odla-ai/cli code connect \
--platform https://odla.ai \
--app-id my-app \
--env devThe terminal verifies the checkout and isolation engine, builds the Theseus adapter bundled with the exact CLI release into a content-addressed local image, prepares each digest-pinned recipe image, and sends the connection request outbound to odla. The signed-in app owner approves it; no bearer is copied from the browser. The process stays in the foreground, opens no listener, and keeps its collected host credential in memory only.
At connection time it freezes tracked and non-ignored untracked source into a
staged snapshot, omitting .git, .odla, .wrangler, node_modules, build
output, .env files, .dev.vars, credential JSON, unsafe paths, and symlinks.
Each session binds an explicitly selected primary repository/ref plus any named
read-only repository/ref references to exact commits and tree digests. A
matching local snapshot remains an optimization with explicit provenance;
otherwise Harness receives the immutable sources from the Registry. References
are materialized under .odla-references/<alias> and the broker rejects every
attempt to patch them. A checkpoint patch is computed against the selected
primary Git base, so local developer changes remain explicit provenance
alongside Theseus's changes.
On Apple Silicon with macOS 26, install Apple's lightweight runtime once with
brew install container; code connect selects it and starts its user service.
On Linux, auto requires rootless Podman. Podman Machine is the macOS fallback;
Docker is an explicit compatibility adapter only. Recipe images must be
digest-pinned; the Theseus adapter's local tag contains the SHA-256 of its CLI bundle
and requires no registry credential. All adapters run Theseus networkless and
non-root with bounded CPU/memory; Theseus has no
checkout or engine-socket mount.
Experimental task runner
The older generic task queue is separate from the personal Theseus terminal flow. It lives under Code → Task runners · advanced. To exercise it, register a workspace and keep its runner token outside shell history:
export ODLA_HARNESS_TOKEN=odla_hrn_...
npx @odla-ai/harness runner \
--endpoint https://odla.ai \
--workspace my-repo=/absolute/path/to/repo \
--image registry.example/coding-agent@sha256:<digest> \
--engine autoThe runner adds network=none, a read-only root, dropped capabilities, non-root uid/gid, and CPU/memory limits across adapters. Docker and Podman additionally receive no-new-privileges plus PID and bounded-tmpfs limits. A legacy image's only writable mount is the disposable workspace copy; a broker-only image has no source mount.
The runner skips .git, .odla, .wrangler, node_modules, build output, .env files, .dev.vars, credential JSON, and symlinks while staging. Completed attempts return a bounded binary-capable Git patch to Studio.
Studio can branch the attempt ledger from an inspected event checkpoint. In this first release the branch records immutable lineage and starts from a fresh copy of the registered workspace; it does not replay the parent patch into the new copy.
Build recipes
The Code terminal advertises a closed recipe catalog. The content-addressed, CLI-embedded Theseus adapter and every registry-digest-pinned recipe are prepared before approval:
{
"recipeAuthorization": "registered_recipe",
"recipes": [{
"id": "test",
"image": "registry.example/app-build@sha256:<digest>",
"command": ["npm", "test"],
"timeoutMs": 600000,
"maxOutputBytes": 1048576
}]
}A repository can replace that release-owned list with its own. Code reads
odla.recipes.json from the root of the trusted base (the default-branch
snapshot it staged, never the candidate's working tree) when a session starts:
{
"version": 1,
"recipes": [
{ "id": "engine-tests", "command": ["node", "--test", "test/"] },
{ "id": "gates", "command": ["node", "scripts/gates.mjs"], "timeoutMs": 60000 }
]
}The repository chooses each recipe's id, argv command, and optional
timeoutMs (default 120000, at most 900000, up to 16 recipes); the host
supplies the digest-pinned image and the resource limits, and a declaration that
names an image or any other field is refused. A malformed file fails the
session start with the fault named rather than falling back, and the session
thread's first system message says which list gates it and where that list came
from. Every declared recipe runs in the same fresh, networkless container as the
release list, so a repository whose tests need node_modules still cannot run
them here.
The runtime validates HTTPS, never places its credential in a request body, never opens a listener, and rejects malformed or cross-host binding responses. Theseus reads, patches, and runs only registered build recipes through the typed CaMeL broker. Checkpoint-stop captures a bounded combined patch; resume verifies it against the same selected Git base and exact local source descriptor.
--once is diagnostic-only and refuses pending commands so a one-heartbeat
probe cannot acknowledge a session as running and then immediately tear it
down.
Agent protocol
The image reads one JSON object per line on stdin and writes protocol messages on stdout. Version 1 supports task.start, typed event messages, inference.request/inference.response, tool.request/tool.response, attempt.cancel, and attempt.complete.
Registry-brokered collaboration
createCodeRuntimeSessionSkillLoader(control) loads PM and Discussion tool
manifests for each accepted Code command and turns them into ordinary agent
skills. Every handler proxies the exact commandId and provider-issued
toolCallId back through the authenticated host control plane. The Registry
executes the effect and returns only bounded tool output, so neither Theseus nor
its networkless container receives an app key, tenant credential, or direct
database client. Initial work waits for the Registry's persisted running ACK
before manifests are requested.
CaMeL tool and build boundary
createCodeToolBroker is the trusted implementation for the three Theseus tools:
registered staged-file reads, confined unified patches, and app-registered
build recipes. Each request is labelled and evaluated by @odla-ai/camel before
an effect. Patch data remains Prompt-Unsafe payload; file and recipe selectors
must pass closed conversions; recipe execution is either explicitly
pre-authorized by app policy or bound to an exact approval digest.
Recipes contain a fixed command and digest-pinned image. They run without a shell in a second networkless, non-root container over a newly staged copy. Build output and mutations are discarded after the bounded result returns. The decision binds a digest of the exact source copy, and the broker refuses to run if that copy changes after authorization. No repository code executes in the host runner process.
verifyCodeCandidate is the independent landing verifier. It reconstructs the
candidate from the registered trusted-base digest and patch, gives each fixed
recipe a fresh source copy, and emits a digest-authenticated closed receipt.
Raw stdout, stderr, and changed-test paths remain separate quarantined evidence
for coding, review, and owner display. Only the prose-free receipt of registered
recipe outcomes, digests, and changed-test counts can be promoted to planning
Safe through createTrustedCodeVerificationReceipt; changed tests always set a
separate review requirement.
Portable checkpoint and resume
createCodeWorkspaceCheckpoint captures the staged candidate as a bounded,
validated text patch plus closed resume state: plan and conversation cursors,
build-policy and dependency-layer digests, completed effect receipts,
unresolved approvals, and trust status. Patch, state, and total checkpoint have
independent SHA-256 digests. The Registry verifies the complete payload before
storing it and keeps only its digest in the command ledger.
restoreCodeWorkspaceCheckpoint verifies every digest, requires the exact base
commit, and applies the patch to a fresh staged copy on the currently bound
host. isCheckpointEffectCompleted skips an exact prior effect and rejects an
effect ID rebound to another action digest, preventing resume from replaying a
database write, publication, or deployment.
Use @odla-ai/harness for protocol types and validation, @odla-ai/harness/node for runner/container primitives, and @odla-ai/harness/testing for deterministic test doubles.
Local fixture image
The included fixture proves the transport without running an autonomous coding agent:
docker build -t odla-harness-fixture:local packages/harness/fixtures
ODLA_HARNESS_CONTAINER_TEST=1 npm test -w @odla-ai/harnessUnpinned images are accepted only when both the explicit test flag and ODLA_HARNESS_UNSAFE_TESTING=1 are present. That escape hatch is not intended for a connected Studio runner.
