mu-agent 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (280) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/LICENSE +21 -0
  3. package/README.md +62 -0
  4. package/dist/bundle/chunks/anthropic-messages-MYU5ZMRF.js +6 -0
  5. package/dist/bundle/chunks/anthropic.js +75 -0
  6. package/dist/bundle/chunks/azure-openai-responses-HUSQ3GP2.js +2 -0
  7. package/dist/bundle/chunks/bedrock-converse-stream.js +83 -0
  8. package/dist/bundle/chunks/chunk-4L3WN2XY.js +2 -0
  9. package/dist/bundle/chunks/chunk-6CYCI3EJ.js +12 -0
  10. package/dist/bundle/chunks/chunk-6R7UI4IY.js +2 -0
  11. package/dist/bundle/chunks/chunk-7ZC4UXSL.js +2 -0
  12. package/dist/bundle/chunks/chunk-A3JYRWB6.js +2 -0
  13. package/dist/bundle/chunks/chunk-DRQDKNXA.js +2 -0
  14. package/dist/bundle/chunks/chunk-DTD7JQ7Y.js +42 -0
  15. package/dist/bundle/chunks/chunk-FUXEF6JQ.js +44 -0
  16. package/dist/bundle/chunks/chunk-L2ZPNLYD.js +2 -0
  17. package/dist/bundle/chunks/chunk-NUHFSC37.js +25 -0
  18. package/dist/bundle/chunks/chunk-PGXDEOVV.js +2 -0
  19. package/dist/bundle/chunks/chunk-PJACZCIR.js +2 -0
  20. package/dist/bundle/chunks/chunk-PRRNXB7S.js +2 -0
  21. package/dist/bundle/chunks/chunk-QB4HYZZE.js +1561 -0
  22. package/dist/bundle/chunks/chunk-RCZIEVGO.js +11 -0
  23. package/dist/bundle/chunks/chunk-S7SZN6Z3.js +2 -0
  24. package/dist/bundle/chunks/chunk-TEPMHNKQ.js +2 -0
  25. package/dist/bundle/chunks/chunk-TRDNDS6A.js +4 -0
  26. package/dist/bundle/chunks/chunk-USJZMAIR.js +2 -0
  27. package/dist/bundle/chunks/chunk-WIUZI2CJ.js +11 -0
  28. package/dist/bundle/chunks/chunk-XDUWOHPL.js +6 -0
  29. package/dist/bundle/chunks/chunk-XNGRGP62.js +2 -0
  30. package/dist/bundle/chunks/chunk-Z2DUOAN4.js +2 -0
  31. package/dist/bundle/chunks/github-copilot.js +2 -0
  32. package/dist/bundle/chunks/google-generative-ai-IMS5EK2Y.js +2 -0
  33. package/dist/bundle/chunks/google-vertex-O4YJEQUW.js +2 -0
  34. package/dist/bundle/chunks/https-proxy-agent-2VXB7436.js +13 -0
  35. package/dist/bundle/chunks/image-resize-worker.js +2 -0
  36. package/dist/bundle/chunks/jiti-loader-C3NU2SDH.js +21 -0
  37. package/dist/bundle/chunks/jiti-static-loader-E6ANQD5T.js +2 -0
  38. package/dist/bundle/chunks/kimi-coding.js +2 -0
  39. package/dist/bundle/chunks/lib-HGQMNYVT.js +9 -0
  40. package/dist/bundle/chunks/mistral-conversations-NOSQHBEY.js +5 -0
  41. package/dist/bundle/chunks/multipart-parser-SQ6GDJL7.js +3 -0
  42. package/dist/bundle/chunks/node-O3RIBJRH.js +16 -0
  43. package/dist/bundle/chunks/node-TWVVAGPO.js +2 -0
  44. package/dist/bundle/chunks/openai-codex-responses-QDSOTBBO.js +10 -0
  45. package/dist/bundle/chunks/openai-codex.js +75 -0
  46. package/dist/bundle/chunks/openai-completions-KQPOPEVM.js +7 -0
  47. package/dist/bundle/chunks/openai-responses-HWEUZ6WZ.js +2 -0
  48. package/dist/bundle/chunks/openrouter-images-N4XVVFSD.js +2 -0
  49. package/dist/bundle/chunks/openrouter.js +75 -0
  50. package/dist/bundle/chunks/pi-messages-GFKBWJHZ.js +8 -0
  51. package/dist/bundle/chunks/radius.js +75 -0
  52. package/dist/bundle/chunks/src-UK77SYZE.js +4 -0
  53. package/dist/bundle/chunks/virtual-modules-ROULVYS3.js +2 -0
  54. package/dist/bundle/chunks/xai.js +2 -0
  55. package/dist/bundle/cli.js +3 -0
  56. package/dist/bundle/index.js +2 -0
  57. package/dist/bundle/native/darwin/prebuilds/darwin-arm64/darwin-platform.node +0 -0
  58. package/dist/bundle/native/darwin/prebuilds/darwin-x64/darwin-platform.node +0 -0
  59. package/dist/bundle/native/linux/prebuilds/linux-arm64/linux-platform-x11.node +0 -0
  60. package/dist/bundle/native/linux/prebuilds/linux-x64/linux-platform-x11.node +0 -0
  61. package/dist/bundle/native/win32/prebuilds/win32-arm64/win32-platform.node +0 -0
  62. package/dist/bundle/native/win32/prebuilds/win32-x64/win32-platform.node +0 -0
  63. package/dist/bundle/rpc-entry.js +3 -0
  64. package/dist/core/export-html/template.css +1066 -0
  65. package/dist/core/export-html/template.html +55 -0
  66. package/dist/core/export-html/template.js +1864 -0
  67. package/dist/core/export-html/vendor/highlight.min.js +1213 -0
  68. package/dist/core/export-html/vendor/marked.min.js +78 -0
  69. package/dist/modes/interactive/assets/clankolas.png +0 -0
  70. package/dist/modes/interactive/theme/dark.json +91 -0
  71. package/dist/modes/interactive/theme/light.json +90 -0
  72. package/dist/modes/interactive/theme/theme-controller.d.ts +41 -0
  73. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -0
  74. package/dist/modes/interactive/theme/theme-controller.js +130 -0
  75. package/dist/modes/interactive/theme/theme-controller.js.map +1 -0
  76. package/dist/modes/interactive/theme/theme-json.d.ts +84 -0
  77. package/dist/modes/interactive/theme/theme-json.d.ts.map +1 -0
  78. package/dist/modes/interactive/theme/theme-json.js +130 -0
  79. package/dist/modes/interactive/theme/theme-json.js.map +1 -0
  80. package/dist/modes/interactive/theme/theme-schema.json +356 -0
  81. package/dist/modes/interactive/theme/theme.d.ts +131 -0
  82. package/dist/modes/interactive/theme/theme.d.ts.map +1 -0
  83. package/dist/modes/interactive/theme/theme.js +991 -0
  84. package/dist/modes/interactive/theme/theme.js.map +1 -0
  85. package/dist/native/darwin/prebuilds/darwin-arm64/darwin-platform.node +0 -0
  86. package/dist/native/darwin/prebuilds/darwin-x64/darwin-platform.node +0 -0
  87. package/dist/native/linux/prebuilds/linux-arm64/linux-platform-x11.node +0 -0
  88. package/dist/native/linux/prebuilds/linux-x64/linux-platform-x11.node +0 -0
  89. package/dist/native/win32/prebuilds/win32-arm64/win32-platform.node +0 -0
  90. package/dist/native/win32/prebuilds/win32-x64/win32-platform.node +0 -0
  91. package/docs/compaction.md +444 -0
  92. package/docs/containerization.md +156 -0
  93. package/docs/custom-provider.md +786 -0
  94. package/docs/development.md +90 -0
  95. package/docs/docs.json +160 -0
  96. package/docs/environment-variables.md +100 -0
  97. package/docs/extensions.md +3037 -0
  98. package/docs/images/doom-extension.png +0 -0
  99. package/docs/images/exy.png +0 -0
  100. package/docs/images/interactive-mode.png +0 -0
  101. package/docs/images/tree-view.png +0 -0
  102. package/docs/index.md +84 -0
  103. package/docs/json.md +98 -0
  104. package/docs/keybindings.md +239 -0
  105. package/docs/llama-cpp.md +101 -0
  106. package/docs/models.md +605 -0
  107. package/docs/packages.md +228 -0
  108. package/docs/prompt-templates.md +96 -0
  109. package/docs/providers.md +317 -0
  110. package/docs/quickstart.md +167 -0
  111. package/docs/rpc.md +1618 -0
  112. package/docs/sdk.md +1226 -0
  113. package/docs/security.md +59 -0
  114. package/docs/session-format.md +480 -0
  115. package/docs/sessions.md +172 -0
  116. package/docs/settings.md +428 -0
  117. package/docs/shell-aliases.md +13 -0
  118. package/docs/skills.md +232 -0
  119. package/docs/terminal-setup.md +192 -0
  120. package/docs/termux.md +126 -0
  121. package/docs/themes.md +322 -0
  122. package/docs/tmux.md +63 -0
  123. package/docs/tui.md +961 -0
  124. package/docs/usage.md +312 -0
  125. package/docs/windows.md +39 -0
  126. package/examples/README.md +28 -0
  127. package/examples/extensions/README.md +212 -0
  128. package/examples/extensions/auto-commit-on-exit.ts +49 -0
  129. package/examples/extensions/bash-spawn-hook.ts +30 -0
  130. package/examples/extensions/bookmark.ts +50 -0
  131. package/examples/extensions/border-status-editor.ts +150 -0
  132. package/examples/extensions/built-in-tool-renderer.ts +249 -0
  133. package/examples/extensions/claude-rules.ts +86 -0
  134. package/examples/extensions/commands.ts +72 -0
  135. package/examples/extensions/confirm-destructive.ts +59 -0
  136. package/examples/extensions/custom-compaction.ts +117 -0
  137. package/examples/extensions/custom-footer.ts +64 -0
  138. package/examples/extensions/custom-header.ts +73 -0
  139. package/examples/extensions/custom-provider-anthropic/index.ts +617 -0
  140. package/examples/extensions/custom-provider-anthropic/package-lock.json +24 -0
  141. package/examples/extensions/custom-provider-anthropic/package.json +19 -0
  142. package/examples/extensions/custom-provider-gitlab-duo/index.ts +405 -0
  143. package/examples/extensions/custom-provider-gitlab-duo/package.json +16 -0
  144. package/examples/extensions/custom-provider-gitlab-duo/test.ts +82 -0
  145. package/examples/extensions/dirty-repo-guard.ts +56 -0
  146. package/examples/extensions/doom-overlay/README.md +46 -0
  147. package/examples/extensions/doom-overlay/doom/build/doom.js +21 -0
  148. package/examples/extensions/doom-overlay/doom/build/doom.wasm +0 -0
  149. package/examples/extensions/doom-overlay/doom/build.sh +152 -0
  150. package/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +72 -0
  151. package/examples/extensions/doom-overlay/doom-component.ts +132 -0
  152. package/examples/extensions/doom-overlay/doom-engine.ts +173 -0
  153. package/examples/extensions/doom-overlay/doom-keys.ts +104 -0
  154. package/examples/extensions/doom-overlay/index.ts +74 -0
  155. package/examples/extensions/doom-overlay/wad-finder.ts +55 -0
  156. package/examples/extensions/dynamic-resources/SKILL.md +8 -0
  157. package/examples/extensions/dynamic-resources/dynamic.json +81 -0
  158. package/examples/extensions/dynamic-resources/dynamic.md +5 -0
  159. package/examples/extensions/dynamic-resources/index.ts +15 -0
  160. package/examples/extensions/dynamic-tools.ts +74 -0
  161. package/examples/extensions/entry-renderer.ts +41 -0
  162. package/examples/extensions/event-bus.ts +43 -0
  163. package/examples/extensions/file-trigger.ts +41 -0
  164. package/examples/extensions/git-checkpoint.ts +53 -0
  165. package/examples/extensions/git-merge-and-resolve.ts +115 -0
  166. package/examples/extensions/github-issue-autocomplete.ts +185 -0
  167. package/examples/extensions/gondolin/index.ts +531 -0
  168. package/examples/extensions/gondolin/package-lock.json +185 -0
  169. package/examples/extensions/gondolin/package.json +19 -0
  170. package/examples/extensions/handoff.ts +190 -0
  171. package/examples/extensions/hello.ts +26 -0
  172. package/examples/extensions/hidden-thinking-label.ts +53 -0
  173. package/examples/extensions/inline-bash.ts +94 -0
  174. package/examples/extensions/input-transform-streaming.ts +39 -0
  175. package/examples/extensions/input-transform.ts +43 -0
  176. package/examples/extensions/interactive-shell.ts +196 -0
  177. package/examples/extensions/mac-system-theme.ts +47 -0
  178. package/examples/extensions/message-renderer.ts +59 -0
  179. package/examples/extensions/minimal-mode.ts +426 -0
  180. package/examples/extensions/modal-editor.ts +85 -0
  181. package/examples/extensions/model-status.ts +31 -0
  182. package/examples/extensions/notify.ts +57 -0
  183. package/examples/extensions/overlay-qa-tests.ts +1450 -0
  184. package/examples/extensions/overlay-test.ts +153 -0
  185. package/examples/extensions/permission-gate.ts +34 -0
  186. package/examples/extensions/pirate.ts +47 -0
  187. package/examples/extensions/plan-mode/README.md +66 -0
  188. package/examples/extensions/plan-mode/index.ts +390 -0
  189. package/examples/extensions/plan-mode/utils.ts +168 -0
  190. package/examples/extensions/preset.ts +436 -0
  191. package/examples/extensions/project-trust.ts +64 -0
  192. package/examples/extensions/prompt-customizer.ts +49 -0
  193. package/examples/extensions/protected-paths.ts +30 -0
  194. package/examples/extensions/provider-payload.ts +18 -0
  195. package/examples/extensions/qna.ts +118 -0
  196. package/examples/extensions/question.ts +286 -0
  197. package/examples/extensions/questionnaire.ts +448 -0
  198. package/examples/extensions/rainbow-editor.ts +88 -0
  199. package/examples/extensions/reload-runtime.ts +37 -0
  200. package/examples/extensions/rpc-demo.ts +118 -0
  201. package/examples/extensions/sandbox/index.ts +321 -0
  202. package/examples/extensions/sandbox/package-lock.json +92 -0
  203. package/examples/extensions/sandbox/package.json +19 -0
  204. package/examples/extensions/send-user-message.ts +97 -0
  205. package/examples/extensions/session-name.ts +27 -0
  206. package/examples/extensions/shutdown-command.ts +63 -0
  207. package/examples/extensions/snake.ts +343 -0
  208. package/examples/extensions/space-invaders.ts +560 -0
  209. package/examples/extensions/ssh.ts +220 -0
  210. package/examples/extensions/status-line.ts +32 -0
  211. package/examples/extensions/structured-output.ts +65 -0
  212. package/examples/extensions/subagent/README.md +177 -0
  213. package/examples/extensions/subagent/agents/planner.md +37 -0
  214. package/examples/extensions/subagent/agents/reviewer.md +35 -0
  215. package/examples/extensions/subagent/agents/scout.md +50 -0
  216. package/examples/extensions/subagent/agents/worker.md +24 -0
  217. package/examples/extensions/subagent/agents.ts +157 -0
  218. package/examples/extensions/subagent/index.ts +1038 -0
  219. package/examples/extensions/subagent/prompts/implement-and-review.md +10 -0
  220. package/examples/extensions/subagent/prompts/implement.md +10 -0
  221. package/examples/extensions/subagent/prompts/scout-and-plan.md +9 -0
  222. package/examples/extensions/summarize.ts +199 -0
  223. package/examples/extensions/system-prompt-header.ts +17 -0
  224. package/examples/extensions/tic-tac-toe.ts +1008 -0
  225. package/examples/extensions/timed-confirm.ts +70 -0
  226. package/examples/extensions/titlebar-spinner.ts +58 -0
  227. package/examples/extensions/todo.ts +297 -0
  228. package/examples/extensions/tool-override.ts +144 -0
  229. package/examples/extensions/tools.ts +146 -0
  230. package/examples/extensions/trigger-compact.ts +50 -0
  231. package/examples/extensions/truncated-tool.ts +195 -0
  232. package/examples/extensions/widget-placement.ts +9 -0
  233. package/examples/extensions/with-deps/index.ts +32 -0
  234. package/examples/extensions/with-deps/package-lock.json +31 -0
  235. package/examples/extensions/with-deps/package.json +22 -0
  236. package/examples/extensions/working-indicator.ts +123 -0
  237. package/examples/extensions/working-message-test.ts +25 -0
  238. package/examples/plugins/pi-example-plugin/README.md +38 -0
  239. package/examples/plugins/pi-example-plugin/package.json +10 -0
  240. package/examples/plugins/pi-example-plugin/src/contract.ts +13 -0
  241. package/examples/plugins/pi-example-plugin/src/session.ts +23 -0
  242. package/examples/plugins/pi-example-plugin/src/tui.ts +31 -0
  243. package/examples/rpc-extension-ui.ts +641 -0
  244. package/examples/sdk/01-minimal.ts +26 -0
  245. package/examples/sdk/02-custom-model.ts +49 -0
  246. package/examples/sdk/03-custom-prompt.ts +75 -0
  247. package/examples/sdk/04-skills.ts +55 -0
  248. package/examples/sdk/05-tools.ts +48 -0
  249. package/examples/sdk/06-extensions.ts +99 -0
  250. package/examples/sdk/07-context-files.ts +47 -0
  251. package/examples/sdk/08-prompt-templates.ts +51 -0
  252. package/examples/sdk/09-api-keys-and-oauth.ts +34 -0
  253. package/examples/sdk/10-settings.ts +53 -0
  254. package/examples/sdk/11-sessions.ts +52 -0
  255. package/examples/sdk/12-full-control.ts +74 -0
  256. package/examples/sdk/13-session-runtime.ts +67 -0
  257. package/examples/sdk/README.md +140 -0
  258. package/judge/THIRD_PARTY_NOTICES.md +35 -0
  259. package/judge/agents/browser.md +17 -0
  260. package/judge/agents/investigator.md +16 -0
  261. package/judge/agents/planner.md +15 -0
  262. package/judge/agents/reviewer.md +17 -0
  263. package/judge/agents/scout.md +19 -0
  264. package/judge/agents/worker.md +15 -0
  265. package/judge/dist/chrome.js +326 -0
  266. package/judge/dist/kyrn-judge.js +52542 -0
  267. package/judge/package.json +6 -0
  268. package/judge/prompts/implement-and-review.md +14 -0
  269. package/judge/prompts/implement.md +15 -0
  270. package/judge/prompts/init.md +18 -0
  271. package/judge/prompts/scout-and-plan.md +12 -0
  272. package/judge/skills/mu-browser/SKILL.md +30 -0
  273. package/judge/skills/mu-github/SKILL.md +90 -0
  274. package/kyrn/bin/kyrn-doctor +202 -0
  275. package/kyrn/bin/kyrn-judge-local +131 -0
  276. package/kyrn/bin/kyrn-ledger +90 -0
  277. package/kyrn/bin/mu.mjs +1120 -0
  278. package/kyrn/local-judge/requirements.lock.txt +26 -0
  279. package/kyrn/local-judge/server.py +332 -0
  280. package/package.json +45 -0
@@ -0,0 +1,59 @@
1
+ # Security
2
+
3
+ Pi is a local coding agent. It runs with the permissions of the user account that starts it, and it treats files writable by that user as inside the same local trust boundary.
4
+
5
+ ## Project Trust
6
+
7
+ Project trust controls whether pi loads project-local settings, resources, packages, and extensions. It is not a sandbox and it does not restrict what the model can ask tools to do after you start working in a directory.
8
+
9
+ Pi considers a project to have resources that require trust when it finds any of these from the current working directory:
10
+
11
+ - `.pi/settings.json`
12
+ - `.pi/extensions`, `.pi/skills`, `.pi/prompts`, or `.pi/themes`
13
+ - `.pi/SYSTEM.md` or `.pi/APPEND_SYSTEM.md`
14
+ - project `.agents/skills` in the current directory or an ancestor directory
15
+
16
+ A bare `.pi` directory does not count as a project resource that requires trust.
17
+
18
+ When an interactive session starts in a project with resources that require trust and no saved decision for the current directory or a parent directory, pi follows `defaultProjectTrust` from global settings. The default value is `"ask"`, which asks whether to trust the project when UI is available. Saved decisions are stored by canonical directory in `~/.pi/agent/trust.json`, and the closest saved decision on the current or parent path applies before the global default.
19
+
20
+ Trusting a project allows pi to load project resources that require trust, including:
21
+
22
+ - `.pi/settings.json`
23
+ - `.pi` resources such as extensions, skills, prompt templates, themes, and system prompt files
24
+ - missing project packages configured through project settings
25
+ - project-local extensions and project package-managed extensions
26
+
27
+ Declining trust skips protected resources. Context files such as `AGENTS.override.md`, `AGENTS.md`, and `CLAUDE.md` are loaded regardless of project trust unless context loading is disabled. Before trust is resolved, pi only loads context files, user/global extensions, and CLI `-e` extensions. User/global and CLI extensions can handle the `project_trust` event; the first extension that returns a yes/no decision owns the decision.
28
+
29
+ Non-interactive modes (`-p`, `--mode json`, and `--mode rpc`) do not show a trust prompt. Without an applicable saved trust decision, `defaultProjectTrust: "ask"` and `"never"` ignore such resources, while `"always"` trusts them. Use `--approve`/`-a` or `--no-approve`/`-na` to override project trust for one run.
30
+
31
+ ## No Built-in Sandbox
32
+
33
+ Pi does not include a built-in sandbox. Built-in tools can read files, write files, edit files, and run shell commands with the permissions of the pi process. Extensions are TypeScript modules that run with the same permissions. Package installs, shell commands, language servers, test commands, and other developer tools behave as ordinary local processes.
34
+
35
+ This is intentional. Pi is designed to operate on local source trees, invoke project toolchains, and integrate with the user's existing development environment. A partial in-process sandbox would be easy to misunderstand as a security boundary while still depending on the host shell, filesystem, package managers, credentials, and extension code. Real isolation needs to come from the operating system or a virtualization/container boundary.
36
+
37
+ Project trust is only an input-loading guard. It prevents a repository from silently changing pi's settings or extensions before you approve it. It does not make untrusted code, untrusted prompts, or untrusted model output safe. Prompt injection from repository files, comments, documentation, context files, or build output is expected local-agent risk and cannot be reliably prevented by pi.
38
+
39
+ ## Running Untrusted or Unmonitored Work
40
+
41
+ For untrusted repositories, generated code you do not intend to monitor closely, or unattended automation, run pi in a contained environment. Use a container, VM, micro-VM, remote sandbox, or policy-controlled sandbox with only the files and credentials required for the task.
42
+
43
+ Common patterns are documented in [Containerization](containerization.md):
44
+
45
+ - run the whole `pi` process inside a container/sandbox
46
+ - run host pi while routing built-in tool execution into a Gondolin micro-VM
47
+ - mount only the workspace paths the agent should access
48
+ - avoid mounting host `~/.pi/agent` unless the container should access host sessions, settings, and credentials
49
+ - pass the minimum required API keys or use short-lived credentials
50
+ - restrict network access when the task does not need it
51
+ - review diffs and outputs before copying results back to trusted systems
52
+
53
+ If you bind-mount a host workspace read/write, writes from inside the container or VM can still modify host files. Use read-only mounts or copy files into and out of the sandbox when you need stronger protection from unintended writes.
54
+
55
+ ## Reporting Security Issues
56
+
57
+ To report a security issue, follow the repository [Security Policy](https://github.com/earendil-works/pi/blob/main/SECURITY.md). Do not open a public issue for security-sensitive reports.
58
+
59
+ Expected local-agent behavior, lack of a built-in sandbox, prompt injection from untrusted content, and behavior of user-installed extensions or skills are generally outside the security boundary unless the report demonstrates a real privilege-boundary bypass or shows how pi grants access that the local user did not already have.
@@ -0,0 +1,480 @@
1
+ # Session File Format
2
+
3
+ Sessions are stored as JSONL (JSON Lines) files. Each line is a JSON object with a `type` field. Session entries form a tree structure via `id`/`parentId` fields, enabling in-place branching without creating new files.
4
+
5
+ ## File Location
6
+
7
+ ```
8
+ ~/.pi/agent/sessions/--<path>--/<timestamp>_<session-id>.jsonl
9
+ ```
10
+
11
+ By default, `<session-id>` is a UUID. Callers can supply a custom ID through the SDK or `--session-id`. For `<path>`, Pi removes the leading path separator and replaces `/`, `\\`, and `:` with `-`.
12
+
13
+ ## Deleting Sessions
14
+
15
+ Sessions can be removed by deleting their `.jsonl` files under `~/.pi/agent/sessions/`.
16
+
17
+ Pi also supports deleting sessions interactively from `/resume` (select a session and press `Ctrl+D`, then confirm). When available, pi uses the `trash` CLI to avoid permanent deletion.
18
+
19
+ ## Session Version
20
+
21
+ Sessions have a version field in the header:
22
+
23
+ - **Version 1**: Linear entry sequence (legacy, auto-migrated on load)
24
+ - **Version 2**: Tree structure with `id`/`parentId` linking
25
+ - **Version 3**: Renamed `hookMessage` role to `custom` (extensions unification)
26
+
27
+ Existing sessions are automatically migrated to the current version (v3) when loaded.
28
+
29
+ ## Source Files
30
+
31
+ Source on GitHub ([pi](https://github.com/earendil-works/pi)):
32
+ - [`packages/coding-agent/src/core/session-manager.ts`](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/core/session-manager.ts) - Session entry types and SessionManager
33
+ - [`packages/coding-agent/src/core/messages.ts`](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/core/messages.ts) - Extended message types (BashExecutionMessage, CustomMessage, etc.)
34
+ - [`packages/ai/src/types.ts`](https://github.com/earendil-works/pi/blob/main/packages/ai/src/types.ts) - Base message types (UserMessage, AssistantMessage, ToolResultMessage)
35
+ - [`packages/agent/src/types.ts`](https://github.com/earendil-works/pi/blob/main/packages/agent/src/types.ts) - AgentMessage union type
36
+
37
+ For TypeScript definitions in your project, inspect `node_modules/@earendil-works/pi-coding-agent/dist/` and `node_modules/@earendil-works/pi-ai/dist/`.
38
+
39
+ ## Message Types
40
+
41
+ Session entries contain `AgentMessage` objects. Understanding these types is essential for parsing sessions and writing extensions.
42
+
43
+ ### Content Blocks
44
+
45
+ Messages contain arrays of typed content blocks:
46
+
47
+ ```typescript
48
+ interface TextContent {
49
+ type: "text";
50
+ text: string;
51
+ textSignature?: string;
52
+ }
53
+
54
+ interface ImageContent {
55
+ type: "image";
56
+ data: string; // base64 encoded
57
+ mimeType: string; // e.g., "image/jpeg", "image/png"
58
+ }
59
+
60
+ interface ThinkingContent {
61
+ type: "thinking";
62
+ thinking: string;
63
+ thinkingSignature?: string;
64
+ redacted?: boolean;
65
+ }
66
+
67
+ interface ToolCall {
68
+ type: "toolCall";
69
+ id: string;
70
+ name: string;
71
+ arguments: Record<string, any>;
72
+ thoughtSignature?: string;
73
+ namespace?: string;
74
+ }
75
+ ```
76
+
77
+ ### Base Message Types (from pi-ai)
78
+
79
+ ```typescript
80
+ interface SystemMessage {
81
+ role: "system";
82
+ content: string | TextContent[];
83
+ toolsAdded?: Tool[];
84
+ toolsRemoved?: Array<{ name: string }>;
85
+ timestamp: number; // Unix ms
86
+ }
87
+
88
+ interface UserMessage {
89
+ role: "user";
90
+ content: string | (TextContent | ImageContent)[];
91
+ timestamp: number; // Unix ms
92
+ }
93
+
94
+ interface AssistantMessage {
95
+ role: "assistant";
96
+ content: (TextContent | ThinkingContent | ToolCall)[];
97
+ api: string;
98
+ provider: string;
99
+ model: string;
100
+ responseModel?: string;
101
+ responseId?: string;
102
+ providerThinkingLevel?: string;
103
+ diagnostics?: AssistantMessageDiagnostic[];
104
+ usage: Usage;
105
+ stopReason: "pending" | "stop" | "length" | "toolUse" | "error" | "aborted" | "deferred";
106
+ deferred?: DeferredHandle;
107
+ errorMessage?: string;
108
+ rawStopReason?: string;
109
+ endTurn?: boolean;
110
+ timestamp: number;
111
+ }
112
+
113
+ interface ToolResultMessage {
114
+ role: "toolResult";
115
+ toolCallId: string;
116
+ toolName: string;
117
+ content: (TextContent | ImageContent)[];
118
+ details?: any; // Tool-specific metadata
119
+ usage?: Usage; // Nested LLM work performed by the tool
120
+ isError: boolean;
121
+ timestamp: number;
122
+ }
123
+
124
+ interface Usage {
125
+ input: number;
126
+ output: number;
127
+ cacheRead: number;
128
+ cacheWrite: number;
129
+ cacheWrite1h?: number;
130
+ reasoning?: number;
131
+ totalTokens: number;
132
+ cost: {
133
+ input: number;
134
+ output: number;
135
+ cacheRead: number;
136
+ cacheWrite: number;
137
+ total: number;
138
+ };
139
+ }
140
+ ```
141
+
142
+ `"pending"` is reserved for partial messages in streaming events. Terminal events replace it with a completion reason before Pi persists the assistant message, so `"pending"` should never appear in session JSONL. `"deferred"` is a terminal reason for a provider response that will complete later; its `deferred` handle contains the provider data needed to retrieve that response.
143
+
144
+ ### Extended Message Types (from pi-coding-agent)
145
+
146
+ ```typescript
147
+ interface BashExecutionMessage {
148
+ role: "bashExecution";
149
+ command: string;
150
+ output: string;
151
+ exitCode: number | undefined;
152
+ cancelled: boolean;
153
+ truncated: boolean;
154
+ fullOutputPath?: string;
155
+ excludeFromContext?: boolean; // true for !! prefix commands
156
+ timestamp: number;
157
+ }
158
+
159
+ interface CustomMessage {
160
+ role: "custom";
161
+ customType: string; // Extension identifier
162
+ content: string | (TextContent | ImageContent)[];
163
+ display: boolean; // Show in TUI
164
+ details?: any; // Extension-specific metadata
165
+ timestamp: number;
166
+ }
167
+
168
+ interface BranchSummaryMessage {
169
+ role: "branchSummary";
170
+ summary: string;
171
+ fromId: string | null; // Previous leaf whose abandoned path was summarized
172
+ timestamp: number;
173
+ }
174
+
175
+ interface CompactionSummaryMessage {
176
+ role: "compactionSummary";
177
+ summary: string;
178
+ tokensBefore: number;
179
+ timestamp: number;
180
+ }
181
+ ```
182
+
183
+ ### AgentMessage Union
184
+
185
+ ```typescript
186
+ type AgentMessage =
187
+ | SystemMessage
188
+ | UserMessage
189
+ | AssistantMessage
190
+ | ToolResultMessage
191
+ | BashExecutionMessage
192
+ | CustomMessage
193
+ | BranchSummaryMessage
194
+ | CompactionSummaryMessage;
195
+ ```
196
+
197
+ ## Entry Base
198
+
199
+ All entries (except `SessionHeader`) extend `SessionEntryBase`:
200
+
201
+ ```typescript
202
+ interface SessionEntryBase {
203
+ type: string;
204
+ id: string; // Usually an 8-char hex ID; may fall back to a full UUID
205
+ parentId: string | null; // Parent entry ID (null for a root entry)
206
+ timestamp: string; // ISO timestamp
207
+ }
208
+ ```
209
+
210
+ ## Entry Types
211
+
212
+ ### SessionHeader
213
+
214
+ First line of the file. Metadata only, not part of the tree (no `id`/`parentId`).
215
+
216
+ ```json
217
+ {"type":"session","version":3,"id":"uuid","timestamp":"2024-12-03T14:00:00.000Z","cwd":"/path/to/project"}
218
+ ```
219
+
220
+ For sessions with a parent (created via `/fork`, `/clone`, or `newSession({ parentSession })`):
221
+
222
+ ```json
223
+ {"type":"session","version":3,"id":"uuid","timestamp":"2024-12-03T14:00:00.000Z","cwd":"/path/to/project","parentSession":"/path/to/original/session.jsonl"}
224
+ ```
225
+
226
+ ### SessionMessageEntry
227
+
228
+ A message in the conversation. The `message` field contains an `AgentMessage`. System messages carry the prompt and tool loadout: the first request of a session persists one with every prompt section and tool declaration, and later changes persist as system messages that patch `sections` by name (`null` removes one) and list `toolsAdded`/`toolsRemoved`. Replaying them in order yields the current prompt and tools; there is no separate prompt state entry.
229
+
230
+ ```json
231
+ {"type":"message","id":"a0b1c2d3","parentId":null,"timestamp":"2024-12-03T14:00:00.000Z","message":{"role":"system","content":"","sections":{"preamble":"You are an expert coding assistant...","tools":"<tools>\n- read: ...\n</tools>","cwd":"/project"},"toolsAdded":[{"name":"read","description":"...","parameters":{}}],"timestamp":1733234400000}}
232
+ {"type":"message","id":"d4e5f6g7","parentId":"c3d4e5f6","timestamp":"2024-12-03T14:04:00.000Z","message":{"role":"system","content":"","sections":{"skills":"<skills>...</skills>"},"toolsRemoved":[{"name":"write"}],"timestamp":1733234640000}}
233
+ ```
234
+
235
+ Sessions created before system messages existed have no leading system message; the first request declares the current prompt as a later system message, which replays the same way.
236
+
237
+ ```json
238
+ {"type":"message","id":"a1b2c3d4","parentId":"prev1234","timestamp":"2024-12-03T14:00:01.000Z","message":{"role":"user","content":"Hello","timestamp":1733234401000}}
239
+ {"type":"message","id":"b2c3d4e5","parentId":"a1b2c3d4","timestamp":"2024-12-03T14:00:02.000Z","message":{"role":"assistant","content":[{"type":"text","text":"Hi!"}],"api":"anthropic-messages","provider":"anthropic","model":"claude-sonnet-4-5","usage":{...},"stopReason":"stop","timestamp":1733234402000}}
240
+ {"type":"message","id":"c3d4e5f6","parentId":"b2c3d4e5","timestamp":"2024-12-03T14:00:03.000Z","message":{"role":"toolResult","toolCallId":"call_123","toolName":"bash","content":[{"type":"text","text":"output"}],"isError":false,"timestamp":1733234403000}}
241
+ ```
242
+
243
+ ### ModelChangeEntry
244
+
245
+ Emitted when the user switches models mid-session.
246
+
247
+ ```json
248
+ {"type":"model_change","id":"d4e5f6g7","parentId":"c3d4e5f6","timestamp":"2024-12-03T14:05:00.000Z","provider":"openai","modelId":"gpt-4o"}
249
+ ```
250
+
251
+ ### ThinkingLevelChangeEntry
252
+
253
+ Emitted when the user changes the thinking/reasoning level.
254
+
255
+ ```json
256
+ {"type":"thinking_level_change","id":"e5f6g7h8","parentId":"d4e5f6g7","timestamp":"2024-12-03T14:06:00.000Z","thinkingLevel":"high"}
257
+ ```
258
+
259
+ ### UsageEntry
260
+
261
+ Records model-attributed usage that is not an assistant message and does not participate in LLM context. `kind` is an arbitrary string identifying the operation; for example, cache warming uses `"cache_warm"`.
262
+
263
+ ```json
264
+ {"type":"usage","id":"f6g7h8i9","parentId":"e5f6g7h8","timestamp":"2024-12-03T14:08:00.000Z","kind":"cache_warm","provider":"anthropic","model":"claude-sonnet-4-5","usage":{"input":0,"output":0,"cacheRead":50000,"cacheWrite":0,"totalTokens":50000,"cost":{"input":0,"output":0,"cacheRead":0.015,"cacheWrite":0,"total":0.015}}}
265
+ ```
266
+
267
+ Usage entries contribute to session token and cost totals. Pi hides them from the conversation tree. Consumers should treat unknown `kind` values as normal usage rather than rejecting them.
268
+
269
+ ### CompactionEntry
270
+
271
+ Created when context is compacted. Stores a summary of earlier messages and a complete system prompt/tool checkpoint.
272
+
273
+ ```json
274
+ {"type":"compaction","id":"f6g7h8i9","parentId":"e5f6g7h8","timestamp":"2024-12-03T14:10:00.000Z","summary":"User discussed X, Y, Z...","firstKeptEntryId":"c3d4e5f6","tokensBefore":50000,"systemMessage":{"role":"system","content":"You are a coding assistant.","toolsAdded":[],"timestamp":1733235000000}}
275
+ ```
276
+
277
+ `firstKeptEntryId` is required. It identifies the first entry retained from before the compaction entry. When rebuilding context, Pi replaces older summarized entries with the compaction summary and keeps the range beginning at this entry.
278
+
279
+ Optional fields:
280
+ - `systemMessage`: The replayed prompt sections and tool declarations at the compaction boundary; it becomes the leading system message of the compacted context, and system messages among the kept entries are dropped in its favor. It is absent on older session entries.
281
+ - `usage`: LLM usage from generating the summary; included in session token and cost totals
282
+ - `details`: Implementation-specific data (e.g., `{ readFiles: string[], modifiedFiles: string[] }` for default, or custom data for extensions)
283
+ - `fromHook`: `true` if generated by an extension, `false`/`undefined` if pi-generated (legacy field name)
284
+
285
+ ### BranchSummaryEntry
286
+
287
+ Created when switching branches via `/tree` with an LLM generated summary of the left branch up to the common ancestor. Captures context from the abandoned path.
288
+
289
+ ```json
290
+ {"type":"branch_summary","id":"g7h8i9j0","parentId":"a1b2c3d4","timestamp":"2024-12-03T14:15:00.000Z","fromId":"f6g7h8i9","summary":"Branch explored approach A..."}
291
+ ```
292
+
293
+ `parentId` is the entry from which the new branch continues. `fromId` is the previous leaf whose abandoned path was summarized.
294
+
295
+ Optional fields:
296
+ - `usage`: LLM usage from generating the summary; included in session token and cost totals
297
+ - `details`: File tracking data (`{ readFiles: string[], modifiedFiles: string[] }`) for default, or custom data for extensions
298
+ - `fromHook`: `true` if generated by an extension, `false`/`undefined` if pi-generated (legacy field name)
299
+
300
+ ### CustomEntry
301
+
302
+ Extension state persistence. Does NOT participate in LLM context.
303
+
304
+ ```json
305
+ {"type":"custom","id":"h8i9j0k1","parentId":"g7h8i9j0","timestamp":"2024-12-03T14:20:00.000Z","customType":"my-extension","data":{"count":42}}
306
+ ```
307
+
308
+ Use `customType` to identify your extension's entries on reload. Interactive mode can render custom entries via `pi.registerEntryRenderer(customType, renderer)`, but they still do not participate in LLM context.
309
+
310
+ ### CustomMessageEntry
311
+
312
+ Extension-injected messages that DO participate in LLM context.
313
+
314
+ ```json
315
+ {"type":"custom_message","id":"i9j0k1l2","parentId":"h8i9j0k1","timestamp":"2024-12-03T14:25:00.000Z","customType":"my-extension","content":"Injected context...","display":true}
316
+ ```
317
+
318
+ Fields:
319
+ - `content`: String or `(TextContent | ImageContent)[]` (same as UserMessage)
320
+ - `display`: `true` = show in TUI with distinct styling, `false` = hidden
321
+ - `details`: Optional extension-specific metadata (not sent to LLM)
322
+
323
+ ### LabelEntry
324
+
325
+ User-defined bookmark/marker on an entry.
326
+
327
+ ```json
328
+ {"type":"label","id":"j0k1l2m3","parentId":"i9j0k1l2","timestamp":"2024-12-03T14:30:00.000Z","targetId":"a1b2c3d4","label":"checkpoint-1"}
329
+ ```
330
+
331
+ Set `label` to `undefined` to clear a label.
332
+
333
+ ### SessionInfoEntry
334
+
335
+ Session metadata (e.g., user-defined display name). Set via `/name`, `--name` / `-n`, or `pi.setSessionName()` in extensions.
336
+
337
+ ```json
338
+ {"type":"session_info","id":"k1l2m3n4","parentId":"j0k1l2m3","timestamp":"2024-12-03T14:35:00.000Z","name":"Refactor auth module"}
339
+ ```
340
+
341
+ The session name is displayed in the session selector (`/resume`) instead of the first message when set.
342
+
343
+ ## Tree Structure
344
+
345
+ Entries normally form one tree, but navigation APIs can create multiple roots:
346
+ - A root entry has `parentId: null`; the first entry is initially the root
347
+ - Each non-root entry points to its parent via `parentId`
348
+ - Branching creates new children from an earlier entry
349
+ - The "leaf" is the current position in the tree
350
+ - Calling `resetLeaf()` or `branchWithSummary(null, ...)` allows a later entry to become another root
351
+
352
+ ```
353
+ [user msg] ─── [assistant] ─── [user msg] ─── [assistant] ─┬─ [user msg] ← current leaf
354
+ │
355
+ └─ [branch_summary] ─── [user msg] ← alternate branch
356
+ ```
357
+
358
+ ## Context Building
359
+
360
+ `buildContextEntries()` walks from the current leaf to the root, producing the active entry list while honoring compaction:
361
+
362
+ 1. Collects all entries on the path
363
+ 2. If one or more `CompactionEntry` values are on the path, uses the latest one:
364
+ - Includes the compaction entry first
365
+ - Includes non-system entries from `firstKeptEntryId` up to, but not including, the compaction entry
366
+ - Includes entries after the compaction entry
367
+ 3. Preserves non-message entries in the selected range so interactive mode can render them
368
+
369
+ `buildSessionContext()` builds on that entry list to produce the message list for the LLM:
370
+
371
+ 1. Extracts current model and thinking level settings from the full path
372
+ 2. Converts selected entries to messages:
373
+ - `message` -> stored `AgentMessage`
374
+ - `compaction` -> complete system checkpoint followed by `compactionSummary`
375
+ - `branch_summary` -> `branchSummary`
376
+ - `custom_message` -> `CustomMessage`
377
+ - `usage` and `custom` -> no context message
378
+
379
+ The compaction summary replaces entries before `firstKeptEntryId`. Pre-compaction system messages are folded into the complete checkpoint rather than replayed from the retained range. Retained non-system entries and all entries after the compaction remain available to the LLM.
380
+
381
+ ## Parsing Example
382
+
383
+ ```typescript
384
+ import { readFileSync } from "fs";
385
+
386
+ const lines = readFileSync("session.jsonl", "utf8").trim().split("\n");
387
+
388
+ for (const line of lines) {
389
+ const entry = JSON.parse(line);
390
+
391
+ switch (entry.type) {
392
+ case "session":
393
+ console.log(`Session v${entry.version ?? 1}: ${entry.id}`);
394
+ break;
395
+ case "message":
396
+ console.log(`[${entry.id}] ${entry.message.role}: ${JSON.stringify(entry.message.content)}`);
397
+ break;
398
+ case "compaction":
399
+ console.log(`[${entry.id}] Compaction: ${entry.tokensBefore} tokens summarized`);
400
+ break;
401
+ case "branch_summary":
402
+ console.log(`[${entry.id}] Branch from ${entry.fromId}`);
403
+ break;
404
+ case "usage":
405
+ console.log(`[${entry.id}] Usage (${entry.kind}): ${entry.usage.totalTokens} tokens`);
406
+ break;
407
+ case "custom":
408
+ console.log(`[${entry.id}] Custom (${entry.customType}): ${JSON.stringify(entry.data)}`);
409
+ break;
410
+ case "custom_message":
411
+ console.log(`[${entry.id}] Extension message (${entry.customType}): ${entry.content}`);
412
+ break;
413
+ case "label":
414
+ console.log(`[${entry.id}] Label "${entry.label}" on ${entry.targetId}`);
415
+ break;
416
+ case "model_change":
417
+ console.log(`[${entry.id}] Model: ${entry.provider}/${entry.modelId}`);
418
+ break;
419
+ case "thinking_level_change":
420
+ console.log(`[${entry.id}] Thinking: ${entry.thinkingLevel}`);
421
+ break;
422
+ }
423
+ }
424
+ ```
425
+
426
+ ## SessionManager API
427
+
428
+ Key methods for working with sessions programmatically.
429
+
430
+ ### Static Creation Methods
431
+ - `SessionManager.create(cwd, sessionDir?, options?)` - New session; `options` can set `id` and `parentSession`
432
+ - `SessionManager.open(path, sessionDir?, cwdOverride?)` - Open existing session file
433
+ - `SessionManager.continueRecent(cwd, sessionDir?)` - Continue most recent or create new
434
+ - `SessionManager.inMemory(cwd?, options?, entries?)` - No file persistence, optionally initialized from entries
435
+ - `SessionManager.forkFrom(sourcePath, targetCwd, sessionDir?, options?)` - Fork session from another project
436
+
437
+ ### Static Listing Methods
438
+ - `SessionManager.list(cwd, sessionDir?, onProgress?)` - List sessions for a directory
439
+ - `SessionManager.listAll(onProgress?)` - List all sessions across all projects
440
+ - `SessionManager.listAll(sessionDir?, onProgress?)` - List sessions from a custom session root
441
+
442
+ ### Instance Methods - Session Management
443
+ - `newSession(options?)` - Start a new session (options: `{ id?: string, parentSession?: string }`)
444
+ - `setSessionFile(path)` - Switch to a different session file
445
+ - `createBranchedSession(leafId)` - Extract branch to new session file
446
+
447
+ ### Instance Methods - Appending (all return entry ID)
448
+ - `appendMessage(message)` - Add message
449
+ - `appendThinkingLevelChange(level)` - Record thinking change
450
+ - `appendModelChange(provider, modelId)` - Record model change
451
+ - `appendUsage(kind, provider, model, usage)` - Record model-attributed usage outside the conversation
452
+ - `appendCompaction(summary, firstKeptEntryId, tokensBefore, details?, fromHook?, usage?)` - Add compaction
453
+ - `appendCustomEntry(customType, data?)` - Extension state (not in context)
454
+ - `appendSessionInfo(name)` - Set session display name
455
+ - `appendCustomMessageEntry(customType, content, display, details?)` - Extension message (in context)
456
+ - `appendLabelChange(targetId, label)` - Set/clear label
457
+
458
+ ### Instance Methods - Tree Navigation
459
+ - `getLeafId()` - Current position
460
+ - `getLeafEntry()` - Get current leaf entry
461
+ - `getEntry(id)` - Get entry by ID
462
+ - `getBranch(fromId?)` - Walk from entry to root
463
+ - `getTree()` - Get full tree structure
464
+ - `getChildren(parentId)` - Get direct children
465
+ - `getLabel(id)` - Get label for entry
466
+ - `branch(entryId)` - Move leaf to earlier entry
467
+ - `resetLeaf()` - Reset leaf to null (before any entries)
468
+ - `branchWithSummary(entryId, summary, details?, fromHook?, usage?)` - Branch with context summary; `entryId` may be `null` to branch from the root
469
+
470
+ ### Instance Methods - Context & Info
471
+ - `buildContextEntries()` - Get active branch entries with compaction applied
472
+ - `buildSessionContext()` - Get messages, thinkingLevel, and model for LLM
473
+ - `getEntries()` - All entries (excluding header)
474
+ - `getHeader()` - Session header metadata
475
+ - `getSessionName()` - Get display name from latest session_info entry
476
+ - `getCwd()` - Working directory
477
+ - `getSessionDir()` - Session storage directory
478
+ - `getSessionId()` - Session UUID
479
+ - `getSessionFile()` - Session file path (undefined for in-memory)
480
+ - `isPersisted()` - Whether session is saved to disk