Cotal
DocsAPI Reference
Build integrationsConnector reference

pi connector reference

@cotal-ai/pi loads Cotal into the operator's pi process. The connector does not include a pi runtime. Connect pi contains installation and launch procedures.

Host integration

One standalone artifact supports three Pi-hosted surfaces:

  1. cotal spawn --harness pi --detach launches the installed pi binary in the manager's PTY. --prompt is delivered as Pi's initial message (its first turn); a prompt that is empty or starts with - or @ refuses the launch, since Pi would read it as an option or a file reference.
  2. Interactive Pi discovers a copied ~/.pi/agent/extensions/cotal.js.
  3. Pi SDK applications using the default resource loader discover that same copy. SDK applications must bind Pi's extension lifecycle when they expect an idle session to be driven proactively.

This release pins Pi 0.79.10. The Cotal package requires Node 22.10; the separately installed Pi host requires Node 22.19 or newer.

Project trust

A managed seat cannot ask a user to answer Pi's Trust project folder? prompt. The connector therefore reads Pi's saved trust decision for the launch directory. A saved approval keeps project resources enabled, and a saved denial remains denied and prints that project resources were skipped. With project resources but no saved decision, the seat chooses untrusted for that run only. Pi skips the directory's .pi resources and any ancestor .agents/skills; Cotal does not write Pi's trust store or approve project code.

The seat prints [cotal-pi/trust] Project resources in <directory> were skipped... and tells the operator to run pi once in that directory in a foreground terminal to review and save trust. A foreground cotal spawn keeps Pi's native interactive choice. If Pi still stops at that native prompt before its session starts, the launch failure names Trust project folder? and the directory instead of reporting only a missing session-state file.

Delivery confirmation

The adapter sends peer traffic as Pi custom messages with triggerTurn: true and deliverAs: "steer". This removes an idle/streaming race while preserving structured batch details. Reliability uses three distinct points:

  1. The matching custom message_start proves Pi dequeued the batch locally.
  2. A context event containing that exact batch proves it entered one provider request.
  3. A successful after_provider_response proves acceptance early when the transport exposes an HTTP response. Some transports, including the Codex subscription, omit that hook; their following clean terminal assistant boundary proves acceptance for the exact context instead.

Only provider-confirmed IDs become eligible for acknowledgement, and only at a terminal agent boundary. The Pi-local ledger commits those IDs through MeshAgent.drainInboxIds(), which removes only exact matches even when quiet ambient is physically interleaved or older IDs were overflow- evicted. Missing confirmed IDs are marked handled and tombstoned so late copies cannot resurface.

A dispatched batch stays in flight from dispatch until that commit, including while the driver holds it for a continuation. The mesh agent renews its durable ack wait, so a long turn keeps a role request and the broker never hands it to another holder of the role. The overflow valve also never evicts a batch in flight. At the in-flight ceiling, a new batch waits for a commit instead of going out unprotected.

A run turn rides the batch that carries it and counts as shown once the provider takes that batch's request: at a successful after_provider_response, or, on a transport without that hook, when Pi runs a tool from the answer or reaches the clean terminal boundary. The seat can therefore cotal_yield it during the Pi turn that carries it. A batch the provider never takes leaves the run turn unshown, and a later batch carries it again.

Pi emits agent_end to extensions without exposing whether it will retry. Error and unknown reasons, and zero/missing-output length, therefore retain the delivery association in waiting while the driver itself attempts the continuation: it re-dispatches the retained batch through the same send path, with a fixed 50 ms backoff and at most two attempts, and each attempt's agent_start proves continuation the same way an externally-triggered one does. A clean terminal boundary on any attempt commits the retained work as usual. Once the attempts are spent, the driver holds with a presence that names the state as needing intervention, states the attempt count, and says what the intervention is: start a new turn in the session, or replace the seat. User abort never retries; it is identified from the AbortSignal captured while the turn is active and stays a plain hold, since the person who aborted is the party who continues. Non-aborted stop, toolUse, and positive-output length are locally provable terminal boundaries and may commit confirmed work.

session_before_compact { reason: "overflow", willRetry: true } identifies the overflow path but is not itself a terminal decision. An abort or dispatch watchdog blocks automatic replay. In managed headless use, restart is the safe recovery because it terminates any possibly-live provider call before durable redelivery.

reload, new, resume, and fork tear down Pi's extension runtime. The adapter keeps its mesh, control listener, delivery association, and ordered presence chain in a process-global identity map, then binds the replacement runtime on its next session_start. It also atomically records the new Pi session id. Only session_shutdown { reason: "quit" } stops the mesh.

For managed PTY seats, cotal spawn --harness pi --detach --resume <pi-session-id> forks that transcript into a new meshed Pi session (pi --fork; the source is untouched). After readiness, the manager binds the exact current Pi session through the token-authenticated local control socket. An unexpected Pi process exit reopens that session with the same Cotal identity, lifecycle UID, credentials and durable inbox. Three restarts are allowed in a rolling two-minute window; a fourth is a crash loop and retires the seat loud. A deliberate stop/despawn/maintenance cut never restarts it.

A manifest agent declared continuity: exact is reopened with pi --session <id>, which fails when Pi no longer has that session instead of creating an empty one under the same id.

Event plane

A managed Pi seat publishes AG-UI runs, completed assistant text messages, and tool start/end boundaries to events.<owner>.<actor>. The thread id is Pi's native session id. Pi's native session JSONL is the durable source; extension hooks only wake the reader after persistence. The event plane is enabled by default. --no-events opts out only on unrestricted spaces. A registration that requires events arms the plane independently of the environment flag, and the seat must hold the channel's publish grant. An event-enabled launch needs a stable workspace root for its write-ahead log. If the event plane stops, the seat keeps running on every space, and Pi's log records AG-UI emitter stopped with the reason and the delay before the extension re-establishes the plane. The re-establish is a fresh start of the same session: it settles any frame the outage left pending and rebuilds the mapper from the run and tool calls that frame opened, so a tool result written after the outage closes the call the plane came back with.

Text is published at completed-message granularity, not as live token deltas. Pi emits live text updates before writing the assistant record, so those deltas cannot be recovered after a crash. Tool arguments and results, reasoning, usage, branch and compaction entries are not published. User text is never published: Pi's native user record cannot separate peer-authored content from human-authored content. A reload keeps the same native session and event frontier. A new, resumed or forked session gets its own thread and log on the same principal channel.

Launch restrictions

  • With no mesh identity the extension is inert, even if COTAL_HOME or COTAL_DEFAULT_AGENT exists.
  • A partial managed control endpoint fails loudly; cooperative stop uses connector-core's existing authenticated control server and Pi's active ctx.shutdown().
  • Peer traffic bypasses Pi's human input transformations, but provider, tool, permission, and sandbox hooks remain on the normal agent path.
  • cotal_inbox destructively pulls quiet ambient while the driver retains ownership of automatic traffic; normal focus recall shown alongside it remains read-only.
  • Pi model variants, MCP sharing, and raw launch options fail loudly until implemented.

Run turns

See Host integration for the current connector contract.

Continuation rules

See Host integration for the current connector contract.

Session lifecycle

See Host integration for the current connector contract.

Managed recovery

See Host integration for the current connector contract.

On this page