Skip to content

The PAC specification

PAC is an open standard for portable agent context: the agent’s durable self (task, plan state, history pointers, provenance, identity references) round-tripping through any coding-agent harness. It defines a canonical Portable Context format and a per-harness adapter contract that materializes that context INTO a harness’s native session format and captures new context OUT, so the same agent runs under any harness or model without losing its accumulated state. It complements existing standards: ACP, MCP, and A2A handle steering and transport; PAC handles the one layer none of them touch: owned, portable, round-trip state.

Every coding harness (Claude Code, Codex, pi, Aider, OpenHands, Gemini CLI, Goose, OpenCode, Cursor) stores the agent’s session in its own bespoke format (tree-JSONL, flat JSONL, SQLite, rollouts, opaque chat IDs). No harness can read another’s state, and the major agent SDKs each ship vendor-internal session models with no cross-vendor portability. The result: an agent’s accumulated self is hostage to whichever harness produced it. PAC closes that gap.

A PAC adapter for a harness implements six operations, split into two layers.

Steering (rides the de-facto CLI/JSONL contract every harness speaks):

  1. spawn: launch the harness with an agent identity, a model designation, and a bound session.
  2. model: designate the brain (flag/env/config varies per harness; the adapter normalizes).
  3. lifecycle: run, suspend, resume, fork, cancel, exit (where the harness supports it).

Portability (PAC’s novel contribution):

  1. materialize IN: translate the canonical Portable Context into the harness’s native session format and write it to the harness’s session store, so the harness resumes the same agent under a different brain.
  2. capture OUT: read the harness’s native session after a run and extract the new context back into the canonical Portable Context.
  3. identity bind: bind the session to a DID and seed-derived key (the agent’s owned self), without the seed ever leaving the client.

The steering layer may delegate to ACP where the harness is ACP-native, or to the native CLI where it is not. The portability layer is always PAC-specific: it touches the native store, which is exactly the bespoke-per-harness work PAC normalizes.

In this CLI: the launch verbs (continue / start / run) implement steering for the verified built-in adapters; session export implements capture OUT; session materialize implements materialize IN; the encrypted, hash-chained log plus the seat DID implement identity bind. Community (manifest) adapters implement the portability layer only.

The architecture: canonical format + adapters

Section titled “The architecture: canonical format + adapters”

PAC defines a canonical Portable Context (a normalized intermediate representation) and per-harness adapters that round-trip through it:

+------------------+ materialize +----------------+
| Portable | ---------------> | harness A |
| Context | (PAC->native) | native store |
| (canonical) | <--------------- | |
| | capture +----------------+
| encrypted, | (native->PAC)
| user-owned | +----------------+
| log | ---------------> | harness B |
+------------------+ materialize | native store |
+----------------+

One canonical format, N adapters, never N x N bilateral translators. Add a harness = write one adapter. The canonical format IS the portable log.

The context is an orientation pointer, not a state transplant: it carries the task, concrete acceptance criteria, the plan with done/pending status, and a which-files-changed pointer. The receiving harness re-grounds in the actual repository with its own tools before acting. Exact runtime-state resumption is deliberately out of scope.

Fields (v1, JSON):

Field What it carries
v payload schema version
task the task in the user’s own words
acceptance[] acceptance criteria (text, optional machine check_cmd)
plan[] plan steps with done / in_progress / pending status
files[] repo-relative paths touched so far (pointers, never content)
repo re-grounding hints: HEAD commit, dirty flag
provenance source harness id, source session id, export time, owner DID
redaction visibility boundary (v1: private)

Each context is stored as an encrypted, hash-chained event in the agent’s own log, so capture is verifiable and tamper-evident, and the log syncs operator-blind (the relay only ever sees ciphertext).

  • Level 1 (declarative): a JSONL-session harness is described by an adapter.toml manifest (session root, glob, JSON pointers, materialize line templates). A generic engine interprets it; no code is shipped. See Building adapters and the adapter.toml reference.
  • Level 2 (native): an exotic format gets a hand-written adapter implementing find / extract / materialize directly. The three in-tree adapters (claude-code, pi, codex) are the reference implementations.

A conforming PAC adapter must demonstrate:

  1. Round-trip integrity: materialize a context, then capture it back; the task must be recovered verbatim and every declared field must survive or be explicitly declared as dropped. tally adapter validate runs this smoke for Level-1 manifests (materialize a marker context into a temp root, extract it back, assert recovery).
  2. Identity isolation: the seed never appears in the Portable Context or the native store; only DID and key references.
  3. No silent state: every dimension the harness’s native format carries is either captured into the canonical format or explicitly declared as dropped (Level 1 declares plan/files as honest-empty).
  • Not a harness launcher (commodity; rides the de-facto CLI contract).
  • Not a runtime (PAC does not execute anything).
  • Not a meta-harness (PAC is the layer beneath, not above).
  • Not a memory SaaS (PAC is a portable format, not a hosted service).
  • Not a task-handoff protocol (PAC carries state, not tasks).

PAC is exactly one thing: the owned, portable, round-trip state layer for AI agents.