pi (pi.dev coding agent)

FieldValue
FormatJSONL transcript
Default store path~/.pi/agent/sessions/<encoded-project>/<timestamp>_<uuid>.jsonl
Env overrideDEJA_PI_ROOT
deja parserinternal/sources/pi.go
Last verified2026-09-06

Discovery

pi stores session transcripts under ~/.pi/agent/sessions/. Each project directory uses the same ---encoded path scheme as Claude Code, e.g. --Users-max-code-deja-vu-- for /Users/max/code/deja-vu. Within each project directory, session files are named <ISO-timestamp>_<UUID>.jsonl. The encoding is lossy (my-app and my/app give the same name), so the header's cwd names the project and the directory is the fallback for a header without one (#4427).

File layout

Each .jsonl file is a single session. The first line is always a session header:

{"type":"session","version":3,"id":"<uuid>","timestamp":"<ISO-8601>","cwd":"<absolute-path>"}

Subsequent lines are typed events:

typeDescription
sessionSession header (first line only)
model_changeModel/provider switch
thinking_level_changeThinking level adjustment
messageUser prompt, assistant response, or tool result

Message records

Messages use a wrapper envelope:

{
  "type": "message",
  "id": "<hex>",
  "parentId": "<hex-or-null>",
  "timestamp": "<ISO-8601>",
  "message": {
    "role": "user|assistant|toolResult",
    "content": [{"type": "text", "text": "..."}],
    "timestamp": 1784448616190
  }
}

Roles

message.roledeja maps to
useruser
assistantassistant
toolResulttool output (RoleToolOutput)

Content

message.content is an array of typed blocks. deja extracts text from blocks where "type": "text". Blocks with "type": "thinking" are skipped.

Tool calls

A toolCall block carries name and arguments. deja reads them for pi and every harness built on it (omp, OpenClaw, gjc, prime, senpi, Kimchi), so deja files, how, restore and blame have something to go on (#4113):

nameArgumentsdeja records
readpaththe file
editpath, edits[].oldText / newText (older pi: one oldText / newText pair)the file, the replaced span, the written lines
writepath, contentthe file and the written lines
apply_patch (OpenClaw)input, a *** Begin Patch bodyeach file the patch names, its removed lines, its added lines
bash (OpenClaw: exec; the pi-coding-agent under Senpi and Kimchi also powershell)commandthe command, and → exit N from the matching toolResult (details.exitCode when there is one, else the "Command exited with code N" line that ends a failed result, exit 0 for a result that is not an error)

A relative path resolves against the header's cwd. gjc's edit takes one input string in its hashline form instead; see the gjc entry. omp and gjc also edit in a replace mode, omp's {path, old_string, new_string} (or edits of those) and gjc's {path, edits:[{old_text, new_text}]}, and a patch mode, {path, edits:[{op, diff}]}: those give the same records, a patch's - lines per hunk the replaced span and its + lines, or a created file's whole diff, the written lines (#4524).

Timestamps

Both ISO-8601 strings ("timestamp" in the envelope) and Unix milliseconds ("timestamp" inside message) are observed. The parser uses the envelope timestamp.

Session identity

The id field from the session header line is used as the session ID. The UUID also appears in the filename.

Package

pi install npm:@vshulcz/pi-deja installs the recall extension as a pi package (pi-package keyword, pi.extensions); it wires the same four handlers the installer writes — session start, prompt, tool_result and session_compact — and stands down when deja install pi-auto already wrote ~/.pi/agent/extensions/deja.ts, or when the omp counterpart is in place.

MCP

pi does not include built-in MCP but supports it via the pi-mcp-adapter package (pi install npm:pi-mcp-adapter). The adapter reads ~/.pi/agent/mcp.json with the standard mcpServers shape. deja install pi writes to that file and says when the adapter is not in pi's packages; deja doctor then reports the row as no adapter (#4583).

Skill, auto-recall, command

The skill is the shared ~/.agents/skills/deja-history/SKILL.md; pi scans that directory, and a second copy in ~/.pi/agent/skills makes it report a collision, so install removes one an older deja left there.

deja install pi-auto writes the MCP entry and ~/.pi/agent/extensions/deja.ts. The extension returns the session digest on the first turn and per-prompt recall after that at before_agent_start, adds to a tool_result a file's history after a read or the earlier fix after a failed bash or powershell command, runs deja hook-precompact at session_compact, and registers /deja <query>, which runs deja search.

deja resume prints pi --session <id>, run in the cwd the session header records; the folder name folds / into -, so my-app and my/app share it. With that directory gone the cd is left out and deja notes that pi, run from another project, offers to fork the session (#4456).

Known quirks and drift

  • Project directory encoding uses -- prefix and suffix (e.g. --Users-max-code-foo--) compared to Claude Code's single - prefix. The resolveEncodedPath function handles both.
  • Version field observed: 3. No version migration behavior is known.
  • The parentId chain forms a tree, not a flat list; deja ignores the tree structure and processes messages in file order.

Last verified: 2026-09-06


deja reads this format and thirty-seven others, and turns what it finds into memory your agents can search. See the harness matrix for what is wired where, or install it and search your own history.

Found this useful? Star deja-vu on GitHub.