Overview
Pi is harness-centric: the whole of Pi is one agent. There is no per-agent profile file the way Kiro or OpenCode have one. Instead, Observal writes the agent’s rules intoAGENTS.md, which becomes Pi’s system prompt, and writes
MCP servers and skills next to it.
To let several registry agents coexist, a user-scope observal agent pull
writes each agent into its own profile directory under
~/.pi/agent/agents/{agent}/. The Observal extension’s /agent command swaps a
profile into the live ~/.pi/agent/ location. A project-scope pull writes the
rules straight to the project’s AGENTS.md, which Pi reads directly.
Pi session telemetry uses an in-process TypeScript extension,
~/.pi/agent/extensions/observal.ts. It is installed by observal doctor patch
and is shared by every agent; agent pulls do not embed telemetry hooks.
Supported capabilities
Setup
1. Install the Observal CLI
2. Authenticate
~/.observal/config.json. Unless you pass
--no-setup or --output json, login then installs the bundled Observal skills
into every detected harness (Pi counts once ~/.pi/ exists) and runs
observal doctor, which warns if the Pi telemetry extension is missing or
stale. A healthy install prints no Pi warning.
3. Pull an agent into Pi
~/.pi/agent/agents/{agent-name}/.
To install into the current project:
AGENTS.md in the project root, which Pi
reads directly, and the agent’s MCP servers and skills to
.pi/agents/{agent-name}/. Pi loads project MCP servers from .pi/mcp.json
and project skills from .pi/skills/{name}/SKILL.md, and /agent handles only
user-scope profiles, so activate them by hand:
.pi/mcp.json already lists other servers.
4. Install or refresh the telemetry extension
~/.pi/agent/extensions/observal.ts when
it is missing, and refreshes a copy Observal recognises as its own when that
copy has fallen behind or been edited, recording the CLI version it came from
in an adjacent .observal-extension.json. A file Observal did not write is
reported and left alone.
If npm:observal-pi is registered in ~/.pi/agent/settings.json, that takes
precedence: nothing is installed locally, and a local copy Observal recognises
as its own is removed (kept as observal.ts.bak) so Pi does not load the
extension twice. A local file Observal did not write is left alone. Restart Pi
or run /reload afterwards.
doctor patch refuses to run until observal auth login has written a server
URL, although it does not contact the server.
5. Activate the agent inside Pi
Inside a Pi session, run/agent and pick the pulled agent. See
Agent profiles and swapping.
6. Check what is installed
Config paths
Pi MCP configs use the
mcpServers key.
Agent profiles and swapping
Because Pi reads a singleAGENTS.md, mcp.json, and skills/ directory,
only one Observal agent can be active at a time. In user scope,
observal agent pull does not touch the active files. It writes into the
per-agent profile directory, and the extension’s /agent command makes a
profile active:
- On first use,
/agentbacks up the currentAGENTS.md,SYSTEM.md,mcp.json,skills/, andsandboxes/into~/.pi/agent/agents/default/. - It removes the active
AGENTS.md,SYSTEM.md,mcp.json,skills/, andsandboxes/, then copies in whichever of those the chosen profile contains. Items the profile lacks stay absent until you swap back todefault. - When Observal credentials are configured, it records the chosen agent as
active_agentin~/.observal/config.jsonand refreshes the layer snapshot. - It offers to reload the session so the new system prompt takes effect.
/agent with no argument to pick from installed profiles, or
/agent <name> to swap directly. Choose default to restore the backed-up
configuration and clear the active agent. /agent lists only user-scope
profiles under ~/.pi/agent/agents/.
Extension spec
Observal installs a TypeScript extension namedobserval.ts. It has no
runtime dependencies beyond node:* built-ins and is fail-open: telemetry
failures never interrupt Pi. Ingest and checkpoint calls time out after five
seconds, and the layer-snapshot upload after ten.
The extension also registers two commands,
/agent and /obs-sync:
doctor patch compares the installed file with the bundled source and replaces
stale copies.
Attribution
Pi does not expose an Observal agent id in its session file. The extension resolves attribution from Observal’s own state:observal agent pullrecords the agent name, id, version, scope, pull time, and directory under thepiharness in~/.observal/lockfile.json.- The pull also records that agent as
active_agentin~/.observal/config.json, and/agentupdates the entry whenever you swap profiles. - On
session_start, the extension readsactive_agentand looks it up in the lockfile entry for the configured server URL, matching by id first and then by name. - The session payload is sent with the resolved
agent_idandagent_version. - If there is no
active_agent, or it has noid, the session is sent with a null agent id. If there is anactive_agentbut no lockfile match, the stored id is sent as-is; no directory-based guessing takes place.
Session push behavior
The Pi extension implements the same acknowledged delivery contract as the Python harnesses:- Resolve the session JSONL file and id from Pi’s session manager.
- Read complete records after the acknowledged byte and line cursor in
~/.observal/sync_state.json. - Persist each pending batch under
~/.observal/pi_session_outbox/before network delivery, in chunks of at most 500 lines. - Retry the batch idempotently until the server returns a contiguous acknowledgement covering it.
- Advance the local cursor only to that acknowledged checkpoint.
- On
session_shutdown, send a SHA-256 audit manifest and replay any range the server asks to repair. - On the next startup, retry every pending outbox batch, then re-push unfinished sessions from the current project that changed within the last seven days until five have been finalized. Attempts that fail do not count toward the five. A missing or corrupt cursor is rebuilt from the server checkpoint on the next push.
~/.observal/pi_session_outbox/.
observal ops telemetry status reports server ingest health and the Python
exporters’ outbox; it does not count this directory.
Agent profile format
Observal writes the agent’s rules as plain Markdown intoAGENTS.md. Pi loads
that file as the system prompt, so the whole file is the agent:
observal agent pull does not
write a model into Pi’s configuration; the model is chosen inside Pi.
Skill file format
Pi skills live at:
Example:
~/.agents/skills/{name}/SKILL.md location, which both harnesses
read, instead of being duplicated under ~/.pi/agent/skills/.
Caveats
One active agent at a time. A user-scope pull does not activate the agent. Run/agent inside Pi, or copy the profile into ~/.pi/agent/ by hand.
/agent does not see project-scope profiles under .pi/agents/; copy their
mcp.json and skills/ into .pi/ as shown in Setup step 3.
/agent replaces the active files. The first swap backs up your existing
AGENTS.md, SYSTEM.md, mcp.json, skills/, and sandboxes/ into the
default profile. Later swaps remove those five items and install only what
the chosen profile contains, so a profile without SYSTEM.md leaves Pi with no
SYSTEM.md. Edit the profile directory, not the active files, if you want
changes to survive a swap.
The extension is shared per Pi install. It is installed by doctor patch,
not by each agent pull, and lives only in user scope.
Guidance files are scanned, with two exceptions. Observal layers
AGENTS.md, .pi/SYSTEM.md, and .pi/APPEND_SYSTEM.md as context. Scanning
and observal agent pull never rewrite the project’s .pi/SYSTEM.md or
.pi/APPEND_SYSTEM.md. A project-scope pull does write the project’s
AGENTS.md, because that file is the agent’s rules in Pi, and /agent swaps
do replace the user-scope ~/.pi/agent/SYSTEM.md as described above.
Attribution depends on the lockfile and /agent. A profile copied by hand
does not update active_agent, so its sessions keep whatever binding
~/.observal/config.json already holds, or carry no agent id if it has none.
MCP config is Pi-specific. Pi uses mcp.json with the mcpServers key
under .pi/ or ~/.pi/agent/, not Claude Code or Kiro MCP paths.
