Skip to content

The driver wire ​

Every sepia-driver-* binary speaks ndjson JSON-RPC 2.0 over stdin/stdout — one JSON object per line, requests and responses interleaved. The driver binary is the server; sepia-host (inside sepia serve or the sepia CLI) is the client. sepia serve itself answers the same framing on its own method surface — see serve-wire.

json
{"jsonrpc":"2.0","id":1,"method":"driver.manifest","params":{}}
{"jsonrpc":"2.0","id":1,"result":{"id":"cline","version":"0.0.0","protocol":1,"capabilities":["sessionStore","sessionWrite","agentConfig"],"agentCommand":"cline --acp","configSchema":{}}}

Params and results are camelCase JSON. Notifications have no id; drivers currently emit none — every outbound line answers an inbound request or is a protocol error.

Manifest ​

driver.manifest is the handshake every host issues first:

fieldmeaning
iddriver id — cline, claude, cursor, devin, …
versiondriver build version
protocoldriver-wire version; the host refuses a mismatch
capabilitieswhich method families the driver serves (below)
agentCommandthe agent CLI argv the host resolves on PATH — an agent only appears when the driver and its command resolve
configSchemaJSON Schema for driver-specific config
CapabilityMethods it unlocks
sessionStoresession.list/get/summary/history/checkpoints — reads
sessionWritesession.save/rename/delete — writes; save is the install path (the driver writes its full store layout, e.g. cline's manifest + transcript + index row)
checkpointssession.checkpoints — workspace snapshot refs
restorefile.restore — file restore from recorded diffs/checkpoints
rewindsession.rewind — transcript truncation
convertcross-store conversion between two backends
agentConfigconfig.read/config.write — the agent-config IR

Methods ​

MethodParams → Result
session.list{} → session summaries
session.get{id, agentId?} → full session IR
session.summary{id, agentId?} → metadata-only session
session.history{id, limit?, before?, agentId?} → a message page
session.save{session} → {} — write the IR into the store (the import/install path)
session.rename{id, title}
session.delete{id}
session.checkpoints{id} → snapshot refs
session.rewind{session, plan, truncated} — the plane ships the full pre-rewind IR, the computed cut, and the already-truncated IR; the driver picks its store mechanism
file.restore{id, path, toolCallId?, confirm} — confirm is the mandatory destructive-op gate → {restored, skipped:[{path,reason}]}
config.read{dir?} → AgentConfig IR — dir is the config root the driver's adapter expects (a .claude/.cursor/devin dir, or a Cline workspace root); absent, the driver resolves its default (SEPIA_*_DIR, user dir, or its own cwd)
config.write{dir?, config} → {actions:[{path,action,detail?}]} — config takes the config export payload or a serialized AgentConfig; items the format can't express come back skipped honestly

Session ids are the agent store's own; agentId params disambiguate colliding ids across backends in multi-store compositions.

Errors ​

Standard JSON-RPC codes plus sepia's application range (-320xx):

codenamemeaning
-32700parse errormalformed line
-32601method not foundunknown or un-capable method
-32602invalid paramsbad shape / missing confirm
-32001session not foundunknown id
-32002session busya turn is in flight
-32003session lockedheld by a live agent process
-32004capability unsupportedmethod needs a capability the driver lacks
-32005store errorbackend I/O failure — message carries the cause

Discovery and lifecycle ​

sepia-host finds drivers in order: $SEPIA_DRIVER_DIR → ~/.local/share/sepia/drivers → /usr/local/lib/sepia/drivers → PATH scan for sepia-driver-*. A <name>.driver.toml sibling can supply the manifest without spawning; otherwise the host spawns, handshakes, and supervises the process (kill-on-drop, stderr ring buffer). Drivers are spawned per call-site as needed and reused; a dead child is respawned on the next call.

Store dir envs per driver (SEPIA_CLINE_DIR, SEPIA_CLAUDE_DIR, SEPIA_CURSOR_DIR, SEPIA_DEVIN_DB, SEPIA_DEVIN_DIR) resolve inside the driver process — set them in the environment of whatever spawns it.

Conventions for new drivers ​

  • Blocking I/O (SQLite, file walks) runs on spawn_blocking.
  • Items a store can't express report skipped/degraded in the action list rather than failing or silently dropping — loss is reported, never hidden.
  • sepia-testkit contract suites exercise the invariants every driver must satisfy; golden fixtures freeze the wire shape.