Skip to main content

Pi Agent Workspace ABI

The container workspace (/workspace/) is shared across all Pi-based agent variants — the one-shot practice runner today, the long-lived mentor runner soon. Reserving the directory names below is a no-cost commitment that prevents a second rename when the mentor runtime lands (#1071) and beyond.

Layout

The workspace is partitioned by lifecycle, expressed as location (ADR 0020): read-only vs writable is decided by where a file lives, not by convention. Three top-level regions — inputs/ (read-only; the path-guard whitelists exactly this subtree), work/ (agent + precompute scratch; never collected), and out/ (the only directory collected back into SQL).

/workspace/
├── inputs/ # READ-ONLY. The path-guard whitelists exactly this subtree.
│ ├── manifest.json # Telescope: the integration-agnostic index (path/connector/
│ │ # sha256 per file). Sits above the per-connector context it indexes.
│ ├── sources/ # Integration-namespaced source materialisations (ADR 0020). One namespace
│ │ └── scm/repo/ # per connector — the SCM git working tree (READ-ONLY mount) lives
│ │ # here; a future export would be sources/slack/…, sources/outline/…
│ ├── context/ # System-written, AI-readable. Populated by the ContentSource SPI.
│ │ # Files: metadata.json, comments.json, diff.patch, diff_summary.md,
│ │ # contributor_history.json, linked_work_items.json, …
│ └── practices/ # Practice catalog (index.json, {slug}.md, all-criteria.md).
├── work/ # AGENT + PRECOMPUTE SCRATCH. Never collected back into SQL.
│ ├── precompute/ # Per-practice precompute scripts injected by the server.
│ ├── precompute-out/ # Precompute runtime output (logs, structured hints).
│ └── analysis/ # Per-practice analysis output (.gitkeep markers).
├── out/ # THE ONLY collected directory — result.json, review-state.json,
│ # usage.json, runner-debug.json, watchdog-killed.json
├── task.json # TaskEnvelope<…> — runtime contract between handler and runner.
├── .pi/ # Pi SDK agent dir — $PI_CODING_AGENT_DIR resolves here.
│ ├── AGENTS.md # Orchestrator instructions
│ ├── settings.json # Pi SDK config (provider, model, compaction)
│ └── extensions/ # Custom provider extensions (auto-discovered)
└── .run-pi.mjs # Runner script entry point.

The long-lived mentor interactive sandbox (#1071) is a separate runtime with its own layout (context/target/, context/user/, scratch/) driven by DockerInteractiveSandboxAdapter, not by this ABI. It is documented there, not here.

Path conventions

  • inputs/ — the entire read-only region. The sandbox path-guard whitelists exactly this subtree; an agent write attempt anywhere under inputs/ is rejected.
  • inputs/context/ — written by ContentSource implementations under agent.context.providers.*. Path prefix is enforced by WorkspaceContextBuilder.
  • inputs/manifest.json — the telescope index, written by ContextManifestBuilder above inputs/context/ (it indexes the context files but is not itself one of them).
  • inputs/sources/scm/repo/ — the read-only SCM checkout, bind-mounted from the host Context Fabric ({fabric.root}/sources/scm/{repositoryId}).
  • work/ — agent + precompute scratch. The Pi agent may write here; the server never collects it.
  • out/ — the only directory the sandbox collects after the run.
  • task.jsonTaskEnvelope<T extends Task>. Schema version 1. The runner asserts schemaVersion and task.kind, exiting 42 on mismatch (envelope/image drift signal).
  • .pi* / inputs/practices/ / work/precompute* / work/analysis/ / out/ — internal control surfaces. AI-readable as configured by the orchestrator, but not part of the public agent ABI; subject to change without a schemaVersion bump.

Exit codes

CodeMeaning
0Success
1Agent runtime failure (Pi SDK or runner error)
3Watchdog hard-kill (budget + grace exceeded)
42Envelope mismatch (unsupported schemaVersion or unknown kind) — image/server drift

Versioning policy

task.json.schemaVersion is per-envelope, not per-task variant. Add a new permitted Task subtype (a new kind discriminator) without bumping the version. Add a required field to an existing kind, and the version bumps. The Pi runner and the Java server ship in the same Docker-image rebuild, so version drift is bounded by deploy cadence; there is no cross-version contract.