Full pipeline: manifest → run → record → lock → isolated re-run¶
getting-started/first-agent.md shows you the 90-second version — write a manifest, run it. This page walks the full production-shaped pipeline: every feature that turns "I ran an agent once" into "a team can ship this agent to production with an audit trail."
Nothing here requires an API key — we use the test-echo pseudo-runtime so you can follow along on a fresh machine.
0. Prerequisites¶
For the isolation section, also:
bubblewrap(apt install bubblewrap/brew install bubblewrap/ via Nix).- Optional:
noether-sandbox(Linux-only) from noether v0.7.3+ — opt-in viaAGENTSPEC_ISOLATION_BACKEND=noether.
1. Write the manifest¶
Create demo.agent in a fresh directory:
apiVersion: agent/v1
name: demo
version: 0.1.0
description: "End-to-end pipeline walkthrough"
runtime: test-echo
model:
preferred:
- test-echo/demo
behavior:
persona: demo-agent
trust:
filesystem: none
network: none
exec: full
observability:
trace: true
test-echo maps to POSIX echo — not a real LLM, but it exercises the full resolver → runner → record path.
Validate it:
ag1:… is the manifest's content hash — a fingerprint that changes whenever the manifest changes. Lockfiles pin to it.
2. Resolve without running¶
resolve shows what run would do:
$ agentspec resolve demo.agent
Runtime: test-echo
Model: test-echo/demo
Auth: local socket
Tools: none
If you're missing the echo binary (you're not — every Linux has it), the resolver surfaces that here rather than at run time.
3. Run it — isolation kicks in automatically¶
$ agentspec run demo.agent
Runtime: test-echo
Model: test-echo/demo
Auth: local socket
Tools: none
Launching test-echo...
[test-echo] demo@0.1.0
Under the hood, run did the following:
- Resolved the plan (step 2).
- Derived an
IsolationPolicyfromtrust:—filesystem: none→ workdir-only RW,network: none→ network namespace unshared. - Wrapped the spawned
echoinbwrap --unshare-all --cap-drop ALL …. - Wrote an execution record to
.agentspec/records/<run-id>.json.
Check the record:
$ agentspec records show <run-id>
{
"schema": "agentspec.record/v1",
"run_id": "01HT…",
"agent": { "name": "demo", "version": "0.1.0", "hash": "ag1:…" },
"runtime": "test-echo",
"started_at": "2026-04-21T10:30:45Z",
"duration_ms": 312,
"exit_code": 0,
"outcome": "success",
"host": { "os": "linux", "arch": "x86_64", "user": "…" }
}
No prompt content, no output, no secrets — records are the audit trail, not the transcript.
4. Pin the plan with a lockfile¶
A manifest is portable; a run should be reproducible. Lock the resolved plan:
$ cat demo.agent.lock
{
"schema": "agentspec.lock/v1",
"manifest": { "hash": "ag1:…", "path": "demo.agent" },
"resolved": {
"runtime": "test-echo",
"model": "test-echo/demo",
"auth_source": "local socket",
"tools": [],
"system_prompt_sha256": "…",
"host": { "os": "linux", "arch": "x86_64" }
}
}
The system prompt is stored as a sha256 — the lockfile is safe to commit to shared repos even when the prompt contains proprietary persona text.
Now re-run against the lock:
If you edit the manifest (changing the hash), the lock rejects:
$ agentspec run demo.agent --lock demo.agent.lock
Error: manifest hash ag1:aaaa… does not match lock's recorded hash ag1:bbbb…
Re-run `agentspec lock demo.agent` if the drift is intentional.
That's the point: a drift-catch happens before the subprocess spawns, not after.
5. Sign the lock for CI¶
Generate an Ed25519 keypair:
$ python3 -c "from agentspec.profile.signing import generate_keypair; \
priv, pub = generate_keypair(); \
print('AGENTSPEC_SIGNING_KEY='+priv); print('AGENTSPEC_PUBKEY='+pub)"
AGENTSPEC_SIGNING_KEY=abc…
AGENTSPEC_PUBKEY=def…
Re-lock with a signing key read from the env (never from a flag — ps aux would see it):
$ export AGENTSPEC_SIGNING_KEY=abc…
$ agentspec lock demo.agent --sign-key-env AGENTSPEC_SIGNING_KEY
Wrote demo.agent.lock (signed)
The lock now contains an Ed25519 signature envelope over the (manifest, resolved) pair.
Verify it:
In CI, run with fail-closed verification:
--require-signed refuses to run unless the lock is a signed envelope that verifies against the named key. If someone mutates resolved.runtime to malicious-cli but leaves the manifest hash intact, the signature no longer matches — CI fails before the subprocess spawns.
6. Switch the isolation backend¶
By default, agentspec run builds the bwrap argv directly. From v0.5.1 onward you can delegate to noether-sandbox (same sandbox primitive, one upstream implementation shared with the noether composition engine):
The output is identical. Under the hood, agentspec:
- Serialises the
IsolationPolicyto noether's JSON wire format. - Writes it to a tmpfile.
- Spawns
noether-sandbox --policy-file <path> --isolate=bwrap --require-isolation -- echo ….
If noether-sandbox isn't on PATH, or if the policy has a shape noether can't yet express (filesystem: full — host passthrough), agentspec falls back to its direct-bwrap path with a debug log. No crash, no silent loss of isolation.
See concepts/inheritance.md for the trust model that drives both backends.
7. Publish to a registry¶
Start a local registry:
$ export AGENTSPEC_API_KEYS="alice:alice-key,bob:bob-key"
$ agentspec registry serve --bind 127.0.0.1:8765 &
Push the manifest as alice:
$ agentspec push demo.agent --registry http://127.0.0.1:8765 \
--api-key alice-key
Pushed demo@0.1.0 → tenant 'alice'
Pull it from another machine (or as an anonymous reader — public reads don't need a key):
$ agentspec pull alice/demo@0.1.0 --registry http://127.0.0.1:8765 \
--out pulled.agent
Fetched demo@0.1.0 → pulled.agent
Tenants are isolated: bob cannot push to alice/…, and attempting a cross-tenant push returns 401. Pulls are public by design (anonymous read matches the "agents are shareable artifacts" thesis).
What you built¶
In ~50 commands you exercised every load-bearing feature of AgentSpec v0.5+:
| Step | Feature |
|---|---|
| 1 | .agent manifest format |
| 2 | Resolver — environment negotiation |
| 3 | Runner + bubblewrap isolation |
| 3 | Execution records |
| 4 | Lockfiles |
| 5 | Ed25519-signed locks for CI |
| 6 | Noether-adapter isolation backend |
| 7 | Multi-tenant registry |
What to read next¶
- When things go wrong — reading failures, exit-code contract, common diagnostics.
- Multi-runtime guide — one manifest across Claude/Gemini/Ollama/Codex.
- Vertex AI routing — running the same manifest in GCP without edits.
- Registry guide — production deployment patterns.