@earendil-works/pi-coding-agent 0.78.0 → 0.79.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 (203) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/README.md +26 -6
  3. package/dist/cli/args.d.ts +1 -0
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +15 -2
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/config.d.ts.map +1 -1
  8. package/dist/config.js +9 -1
  9. package/dist/config.js.map +1 -1
  10. package/dist/core/agent-session-runtime.d.ts +3 -1
  11. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  12. package/dist/core/agent-session-runtime.js +1 -0
  13. package/dist/core/agent-session-runtime.js.map +1 -1
  14. package/dist/core/agent-session-services.d.ts +2 -1
  15. package/dist/core/agent-session-services.d.ts.map +1 -1
  16. package/dist/core/agent-session-services.js +2 -2
  17. package/dist/core/agent-session-services.js.map +1 -1
  18. package/dist/core/agent-session.d.ts +3 -1
  19. package/dist/core/agent-session.d.ts.map +1 -1
  20. package/dist/core/agent-session.js +7 -1
  21. package/dist/core/agent-session.js.map +1 -1
  22. package/dist/core/auth-storage.d.ts.map +1 -1
  23. package/dist/core/auth-storage.js +4 -3
  24. package/dist/core/auth-storage.js.map +1 -1
  25. package/dist/core/compaction/branch-summarization.d.ts +3 -1
  26. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  27. package/dist/core/compaction/branch-summarization.js +9 -3
  28. package/dist/core/compaction/branch-summarization.js.map +1 -1
  29. package/dist/core/compaction/utils.d.ts +1 -1
  30. package/dist/core/compaction/utils.d.ts.map +1 -1
  31. package/dist/core/compaction/utils.js +1 -1
  32. package/dist/core/compaction/utils.js.map +1 -1
  33. package/dist/core/export-html/template.js +19 -6
  34. package/dist/core/extensions/index.d.ts +1 -1
  35. package/dist/core/extensions/index.d.ts.map +1 -1
  36. package/dist/core/extensions/index.js.map +1 -1
  37. package/dist/core/extensions/loader.d.ts +1 -1
  38. package/dist/core/extensions/loader.d.ts.map +1 -1
  39. package/dist/core/extensions/loader.js +4 -4
  40. package/dist/core/extensions/loader.js.map +1 -1
  41. package/dist/core/extensions/runner.d.ts +9 -3
  42. package/dist/core/extensions/runner.d.ts.map +1 -1
  43. package/dist/core/extensions/runner.js +41 -1
  44. package/dist/core/extensions/runner.js.map +1 -1
  45. package/dist/core/extensions/types.d.ts +25 -2
  46. package/dist/core/extensions/types.d.ts.map +1 -1
  47. package/dist/core/extensions/types.js.map +1 -1
  48. package/dist/core/footer-data-provider.d.ts +2 -0
  49. package/dist/core/footer-data-provider.d.ts.map +1 -1
  50. package/dist/core/footer-data-provider.js +29 -1
  51. package/dist/core/footer-data-provider.js.map +1 -1
  52. package/dist/core/model-registry.d.ts.map +1 -1
  53. package/dist/core/model-registry.js +1 -0
  54. package/dist/core/model-registry.js.map +1 -1
  55. package/dist/core/model-resolver.d.ts.map +1 -1
  56. package/dist/core/model-resolver.js +3 -0
  57. package/dist/core/model-resolver.js.map +1 -1
  58. package/dist/core/package-manager.d.ts +3 -0
  59. package/dist/core/package-manager.d.ts.map +1 -1
  60. package/dist/core/package-manager.js +47 -13
  61. package/dist/core/package-manager.js.map +1 -1
  62. package/dist/core/provider-attribution.d.ts +4 -0
  63. package/dist/core/provider-attribution.d.ts.map +1 -0
  64. package/dist/core/provider-attribution.js +72 -0
  65. package/dist/core/provider-attribution.js.map +1 -0
  66. package/dist/core/provider-display-names.d.ts.map +1 -1
  67. package/dist/core/provider-display-names.js +3 -0
  68. package/dist/core/provider-display-names.js.map +1 -1
  69. package/dist/core/resource-loader.d.ts +13 -2
  70. package/dist/core/resource-loader.d.ts.map +1 -1
  71. package/dist/core/resource-loader.js +129 -54
  72. package/dist/core/resource-loader.js.map +1 -1
  73. package/dist/core/sdk.d.ts.map +1 -1
  74. package/dist/core/sdk.js +7 -33
  75. package/dist/core/sdk.js.map +1 -1
  76. package/dist/core/session-manager.d.ts.map +1 -1
  77. package/dist/core/session-manager.js +92 -68
  78. package/dist/core/session-manager.js.map +1 -1
  79. package/dist/core/settings-manager.d.ts +10 -2
  80. package/dist/core/settings-manager.d.ts.map +1 -1
  81. package/dist/core/settings-manager.js +71 -30
  82. package/dist/core/settings-manager.js.map +1 -1
  83. package/dist/core/slash-commands.d.ts.map +1 -1
  84. package/dist/core/slash-commands.js +1 -0
  85. package/dist/core/slash-commands.js.map +1 -1
  86. package/dist/core/tools/bash.d.ts.map +1 -1
  87. package/dist/core/tools/bash.js +1 -1
  88. package/dist/core/tools/bash.js.map +1 -1
  89. package/dist/core/tools/find.d.ts.map +1 -1
  90. package/dist/core/tools/find.js +1 -1
  91. package/dist/core/tools/find.js.map +1 -1
  92. package/dist/core/tools/grep.d.ts.map +1 -1
  93. package/dist/core/tools/grep.js +1 -1
  94. package/dist/core/tools/grep.js.map +1 -1
  95. package/dist/core/tools/ls.d.ts.map +1 -1
  96. package/dist/core/tools/ls.js +1 -1
  97. package/dist/core/tools/ls.js.map +1 -1
  98. package/dist/core/tools/read.d.ts.map +1 -1
  99. package/dist/core/tools/read.js +1 -1
  100. package/dist/core/tools/read.js.map +1 -1
  101. package/dist/core/tools/write.d.ts.map +1 -1
  102. package/dist/core/tools/write.js +1 -1
  103. package/dist/core/tools/write.js.map +1 -1
  104. package/dist/core/trust-manager.d.ts +10 -0
  105. package/dist/core/trust-manager.d.ts.map +1 -0
  106. package/dist/core/trust-manager.js +133 -0
  107. package/dist/core/trust-manager.js.map +1 -0
  108. package/dist/index.d.ts +5 -4
  109. package/dist/index.d.ts.map +1 -1
  110. package/dist/index.js +2 -1
  111. package/dist/index.js.map +1 -1
  112. package/dist/main.d.ts.map +1 -1
  113. package/dist/main.js +195 -6
  114. package/dist/main.js.map +1 -1
  115. package/dist/modes/index.d.ts +1 -1
  116. package/dist/modes/index.d.ts.map +1 -1
  117. package/dist/modes/index.js.map +1 -1
  118. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  119. package/dist/modes/interactive/components/bash-execution.js +2 -2
  120. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  121. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  122. package/dist/modes/interactive/components/footer.js +7 -0
  123. package/dist/modes/interactive/components/footer.js.map +1 -1
  124. package/dist/modes/interactive/components/index.d.ts +1 -0
  125. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  126. package/dist/modes/interactive/components/index.js +1 -0
  127. package/dist/modes/interactive/components/index.js.map +1 -1
  128. package/dist/modes/interactive/components/login-dialog.d.ts +0 -1
  129. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  130. package/dist/modes/interactive/components/login-dialog.js +3 -12
  131. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  132. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  133. package/dist/modes/interactive/components/tool-execution.js +22 -0
  134. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  135. package/dist/modes/interactive/components/trust-selector.d.ts +20 -0
  136. package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -0
  137. package/dist/modes/interactive/components/trust-selector.js +86 -0
  138. package/dist/modes/interactive/components/trust-selector.js.map +1 -0
  139. package/dist/modes/interactive/interactive-mode.d.ts +7 -0
  140. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  141. package/dist/modes/interactive/interactive-mode.js +87 -1
  142. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  143. package/dist/modes/print-mode.d.ts.map +1 -1
  144. package/dist/modes/print-mode.js +1 -0
  145. package/dist/modes/print-mode.js.map +1 -1
  146. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  147. package/dist/modes/rpc/rpc-mode.js +1 -0
  148. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  149. package/dist/package-manager-cli.d.ts.map +1 -1
  150. package/dist/package-manager-cli.js +55 -8
  151. package/dist/package-manager-cli.js.map +1 -1
  152. package/dist/utils/git.d.ts.map +1 -1
  153. package/dist/utils/git.js +54 -22
  154. package/dist/utils/git.js.map +1 -1
  155. package/dist/utils/open-browser.d.ts +9 -0
  156. package/dist/utils/open-browser.d.ts.map +1 -0
  157. package/dist/utils/open-browser.js +22 -0
  158. package/dist/utils/open-browser.js.map +1 -0
  159. package/docs/containerization.md +111 -0
  160. package/docs/docs.json +8 -0
  161. package/docs/extensions.md +58 -12
  162. package/docs/index.md +2 -0
  163. package/docs/packages.md +3 -1
  164. package/docs/prompt-templates.md +1 -1
  165. package/docs/providers.md +5 -0
  166. package/docs/rpc.md +1 -1
  167. package/docs/sdk.md +5 -0
  168. package/docs/security.md +57 -0
  169. package/docs/settings.md +10 -0
  170. package/docs/skills.md +1 -1
  171. package/docs/terminal-setup.md +36 -2
  172. package/docs/themes.md +1 -1
  173. package/docs/tmux.md +4 -2
  174. package/docs/tui.md +10 -1
  175. package/docs/usage.md +16 -4
  176. package/examples/extensions/README.md +2 -0
  177. package/examples/extensions/custom-header.ts +1 -1
  178. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  179. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  180. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  181. package/examples/extensions/doom-overlay/index.ts +1 -1
  182. package/examples/extensions/gondolin/index.ts +531 -0
  183. package/examples/extensions/gondolin/package-lock.json +185 -0
  184. package/examples/extensions/gondolin/package.json +19 -0
  185. package/examples/extensions/handoff.ts +1 -1
  186. package/examples/extensions/interactive-shell.ts +1 -1
  187. package/examples/extensions/overlay-qa-tests.ts +152 -81
  188. package/examples/extensions/project-trust.ts +64 -0
  189. package/examples/extensions/qna.ts +1 -1
  190. package/examples/extensions/question.ts +1 -1
  191. package/examples/extensions/questionnaire.ts +1 -1
  192. package/examples/extensions/sandbox/package-lock.json +2 -2
  193. package/examples/extensions/sandbox/package.json +1 -1
  194. package/examples/extensions/snake.ts +1 -1
  195. package/examples/extensions/space-invaders.ts +1 -1
  196. package/examples/extensions/summarize.ts +1 -1
  197. package/examples/extensions/tic-tac-toe.ts +1 -1
  198. package/examples/extensions/todo.ts +1 -1
  199. package/examples/extensions/tools.ts +5 -0
  200. package/examples/extensions/with-deps/package-lock.json +2 -2
  201. package/examples/extensions/with-deps/package.json +1 -1
  202. package/npm-shrinkwrap.json +12 -12
  203. package/package.json +5 -8
@@ -0,0 +1,111 @@
1
+ # Containerization
2
+
3
+ Pi runs with all permissions by default, but in some cases, you will want to have more control over what directories Pi can write to and which accesses it has.
4
+
5
+ There are two general options. You can either
6
+ 1. run the whole `pi` process inside an isolated environment, or
7
+ 2. run `pi` on the host and route tool execution into an isolated environment.
8
+
9
+ ## Choose a pattern
10
+
11
+ | Pattern | What is isolated | Best for | Notes |
12
+ | --- | --- | --- | --- |
13
+ | OpenShell | Whole `pi` process in a policy-controlled sandbox | Local or remote managed sandbox | Requires an OpenShell gateway |
14
+ | Gondolin extension | Built-in tools and `!` commands | Local micro-VM isolation while keeping auth on host | See [`examples/extensions/gondolin/`](../examples/extensions/gondolin/). |
15
+ | Plain Docker | Whole `pi` process in a local container | Simple local isolation | Provider API keys enter the container. |
16
+
17
+ Extensions run wherever the `pi` process runs. If you run host `pi` with a tool-routing extension, other custom extension tools still run on the host unless they also delegate their operations.
18
+
19
+ ## OpenShell
20
+
21
+ Use [NVIDIA OpenShell](https://docs.nvidia.com/openshell/about/overview) when you want a policy-controlled sandbox with filesystem, process, network, credential, and inference controls.
22
+ OpenShell can run sandboxes through a local gateway backed by Docker, Podman, or a VM runtime, or through a remote Kubernetes gateway.
23
+
24
+ Every sandbox requires an active gateway.
25
+ Register and select one before creating a sandbox:
26
+
27
+ ```bash
28
+ openshell gateway add <gateway-url> --name <name>
29
+ openshell gateway select <name>
30
+ ```
31
+
32
+ Launch `pi` inside an OpenShell sandbox:
33
+
34
+ ```bash
35
+ openshell sandbox create --name pi-sandbox --from pi -- pi
36
+ ```
37
+
38
+ In this pattern, the whole `pi` process runs inside the sandbox.
39
+ Built-in tools, `!` commands, and extension tools execute inside the OpenShell boundary.
40
+
41
+ If the gateway is remote, project files are not bind-mounted from the host, meaning writes in the sandbox are not reflected on your machine.
42
+ Clone the repository inside the sandbox or use OpenShell file transfer commands:
43
+
44
+ ```bash
45
+ openshell sandbox upload pi-sandbox ./repo /workspace
46
+ openshell sandbox download pi-sandbox /workspace/repo ./repo-out
47
+ ```
48
+
49
+ OpenShell providers can keep raw model API keys outside the sandbox.
50
+ When inference routing is configured, code inside the sandbox can call `https://inference.local`, and the gateway injects the configured provider credentials upstream.
51
+ Configure Pi to use the corresponding OpenAI-compatible or Anthropic-compatible endpoint if you want model traffic to use this route.
52
+
53
+ ## Gondolin
54
+
55
+ [Gondolin](https://github.com/earendil-works/gondolin) is a local Linux micro-VM.
56
+ Use the [example extension](../examples/extensions/gondolin) when you want `pi` on the host but all built-in tools routed into the VM.
57
+
58
+ Setup:
59
+
60
+ ```bash
61
+ cp -R packages/coding-agent/examples/extensions/gondolin ~/.pi/agent/extensions/gondolin
62
+ cd ~/.pi/agent/extensions/gondolin
63
+ npm install --ignore-scripts
64
+ ```
65
+
66
+ Run from the project you want mounted:
67
+
68
+ ```bash
69
+ cd /path/to/project
70
+ pi -e ~/.pi/agent/extensions/gondolin
71
+ ```
72
+
73
+ The extension mounts the host cwd at `/workspace` in the VM and overrides `read`, `write`, `edit`, `bash`, `grep`, `find`, and `ls`.
74
+ User `!` commands are routed into the VM, as well.
75
+ File changes under `/workspace` write through to the host.
76
+
77
+ Requirements: Node.js >= 23.6.0 for `@earendil-works/gondolin`, plus QEMU (requires installation through your package manager).
78
+
79
+ ## Plain Docker
80
+
81
+ Run the whole `pi` process in Docker when you want the simplest local container boundary.
82
+
83
+ `Dockerfile.pi`:
84
+
85
+ ```dockerfile
86
+ FROM node:24-bookworm-slim
87
+
88
+ RUN apt-get update \
89
+ && apt-get install -y --no-install-recommends bash ca-certificates git ripgrep \
90
+ && rm -rf /var/lib/apt/lists/*
91
+ RUN npm install -g --ignore-scripts @earendil-works/pi-coding-agent
92
+
93
+ WORKDIR /workspace
94
+ ENTRYPOINT ["pi"]
95
+ ```
96
+
97
+ Build and run:
98
+
99
+ ```bash
100
+ docker build -t pi-sandbox -f Dockerfile.pi .
101
+
102
+ docker run --rm -it \
103
+ -e ANTHROPIC_API_KEY \
104
+ -v "$PWD:/workspace" \
105
+ -v pi-agent-home:/root/.pi/agent \
106
+ pi-sandbox
107
+ ```
108
+
109
+ The `-v "$PWD:/workspace"` mounts your current directory into the container at /workspace such that reads and writes in `/workspace` inside Docker directly affect your host files, like in the Gondolin example.
110
+
111
+ Use a named volume for `/root/.pi/agent` if you want container-local settings and sessions. Mounting your host `~/.pi/agent` exposes host auth and session files to the container.
package/docs/docs.json CHANGED
@@ -19,6 +19,14 @@
19
19
  "title": "Providers",
20
20
  "path": "providers.md"
21
21
  },
22
+ {
23
+ "title": "Security",
24
+ "path": "security.md"
25
+ },
26
+ {
27
+ "title": "Containerization",
28
+ "path": "containerization.md"
29
+ },
22
30
  {
23
31
  "title": "Settings",
24
32
  "path": "settings.md"
@@ -109,7 +109,7 @@ pi -e ./my-extension.ts
109
109
 
110
110
  > **Security:** Extensions run with your full system permissions and can execute arbitrary code. Only install from sources you trust.
111
111
 
112
- Extensions are auto-discovered from:
112
+ Extensions are auto-discovered from trusted locations. Project-local `.pi/extensions` entries load only after the project is trusted.
113
113
 
114
114
  | Location | Scope |
115
115
  |----------|-------|
@@ -270,6 +270,7 @@ Run `npm install` in the extension directory, then imports from `node_modules/`
270
270
  ```
271
271
  pi starts
272
272
 
273
+ ├─► project_trust (user/global and CLI extensions only, before project resources load)
273
274
  ├─► session_start { reason: "startup" }
274
275
  └─► resources_discover { reason: "startup" }
275
276
 
@@ -334,6 +335,25 @@ exit (Ctrl+C, Ctrl+D, SIGHUP, SIGTERM)
334
335
  └─► session_shutdown
335
336
  ```
336
337
 
338
+ ### Startup Events
339
+
340
+ #### project_trust
341
+
342
+ Fired before pi decides whether to trust a project with trust inputs (`.pi`, `AGENTS.md`/`CLAUDE.md`, or `.agents/skills`). It runs during startup and when session replacement (for example `/resume`) enters a cwd whose trust has not been resolved in the current process. Only user/global extensions and CLI `-e` extensions participate; project-local extensions are not loaded until after trust is resolved.
343
+
344
+ ```typescript
345
+ pi.on("project_trust", async (event, ctx) => {
346
+ // event.cwd - current working directory
347
+ // ctx has a limited trust context: cwd, mode, hasUI, and select/confirm/input/notify UI helpers
348
+ if (await ctx.ui.confirm("Trust project?", event.cwd)) {
349
+ return { trusted: "yes", remember: true };
350
+ }
351
+ return { trusted: "undecided" };
352
+ });
353
+ ```
354
+
355
+ A `project_trust` handler must return `{ trusted: "yes" | "no" | "undecided" }`. A user/global or CLI extension that returns `"yes"` or `"no"` owns the decision; the first yes/no decision wins and suppresses the built-in trust prompt. Use `remember: true` to persist a yes/no decision; otherwise it applies only to the current process. Return `"undecided"` to let later handlers or the built-in trust flow decide. Check `ctx.hasUI` before prompting. If no handler returns yes/no, normal trust resolution continues, including the built-in trust prompt when UI is available.
356
+
337
357
  ### Resource Events
338
358
 
339
359
  #### resources_discover
@@ -860,9 +880,13 @@ All handlers receive `ctx: ExtensionContext`.
860
880
 
861
881
  UI methods for user interaction. See [Custom UI](#custom-ui) for full details.
862
882
 
883
+ ### ctx.mode
884
+
885
+ Current run mode: `"tui"`, `"rpc"`, `"json"`, or `"print"`. Use `ctx.mode === "tui"` to guard terminal-only features such as `custom()`, component factories, terminal input, and direct TUI rendering.
886
+
863
887
  ### ctx.hasUI
864
888
 
865
- `false` in print mode (`-p`) and JSON mode. `true` in interactive and RPC mode. In RPC mode, dialog methods (`select`, `confirm`, `input`, `editor`) work via the extension UI sub-protocol, and fire-and-forget methods (`notify`, `setStatus`, `setWidget`, `setTitle`, `setEditorText`) emit requests to the client. Some TUI-specific methods are no-ops or return defaults (see [rpc.md](rpc.md#extension-ui-protocol)).
889
+ `true` in TUI and RPC modes. `false` in print mode (`-p`) and JSON mode. Use this to guard dialog methods (`select`, `confirm`, `input`, `editor`) and fire-and-forget methods (`notify`, `setStatus`, `setWidget`, `setTitle`, `setEditorText`) that work in both TUI and RPC modes. In RPC mode, some TUI-specific methods are no-ops or return defaults (see [rpc.md](rpc.md#extension-ui-protocol)).
866
890
 
867
891
  ### ctx.cwd
868
892
 
@@ -978,6 +1002,19 @@ pi.on("before_agent_start", (event, ctx) => {
978
1002
 
979
1003
  Command handlers receive `ExtensionCommandContext`, which extends `ExtensionContext` with session control methods. These are only available in commands because they can deadlock if called from event handlers.
980
1004
 
1005
+ ### ctx.getSystemPromptOptions()
1006
+
1007
+ Returns the base inputs Pi currently uses to build the system prompt.
1008
+
1009
+ ```typescript
1010
+ const options = ctx.getSystemPromptOptions();
1011
+ const contextPaths = options.contextFiles?.map((file) => file.path) ?? [];
1012
+ ```
1013
+
1014
+ This has the same shape and mutability as `before_agent_start` `event.systemPromptOptions`: custom prompt, active tools, tool snippets, prompt guidelines, appended system prompt text, cwd, loaded context files, and loaded skills. It may include full context file contents, so treat it as sensitive extension-local data and avoid exposing it through command lists, logs, or autocomplete metadata.
1015
+
1016
+ This reports the current base prompt inputs. It does not include per-turn `before_agent_start` chained system-prompt changes, later `context` event message mutations, or `before_provider_request` payload rewrites.
1017
+
981
1018
  ### ctx.waitForIdle()
982
1019
 
983
1020
  Wait for the agent to finish streaming:
@@ -2371,7 +2408,7 @@ const result = await ctx.ui.custom<string | null>(
2371
2408
  );
2372
2409
  ```
2373
2410
 
2374
- For advanced positioning (anchors, margins, percentages, responsive visibility), pass `overlayOptions`. Use `onHandle` to control visibility programmatically:
2411
+ For advanced positioning (anchors, margins, percentages, responsive visibility), pass `overlayOptions`. Use `onHandle` to control focus or visibility programmatically:
2375
2412
 
2376
2413
  ```typescript
2377
2414
  const result = await ctx.ui.custom<string | null>(
@@ -2379,12 +2416,19 @@ const result = await ctx.ui.custom<string | null>(
2379
2416
  {
2380
2417
  overlay: true,
2381
2418
  overlayOptions: { anchor: "top-right", width: "50%", margin: 2 },
2382
- onHandle: (handle) => { /* handle.setHidden(true/false) */ }
2419
+ onHandle: (handle) => {
2420
+ handle.focus(); // focus this overlay and bring it to the visual front
2421
+ // handle.unfocus({ target: editorComponent }); // release input to a specific component
2422
+ // handle.setHidden(true/false); // toggle visibility
2423
+ // handle.hide(); // permanently remove
2424
+ }
2383
2425
  }
2384
2426
  );
2385
2427
  ```
2386
2428
 
2387
- See [tui.md](tui.md) for the full `OverlayOptions` API and [overlay-qa-tests.ts](../examples/extensions/overlay-qa-tests.ts) for examples.
2429
+ A focused visible overlay can reclaim input after temporary non-overlay custom UI closes. If you intentionally want another component to keep input while the overlay stays visible, call `handle.unfocus({ target })`. Passing `{ target: null }` releases the overlay without focusing another component.
2430
+
2431
+ See [tui.md](tui.md) for the full `OverlayOptions` and `OverlayHandle` API and [overlay-qa-tests.ts](../examples/extensions/overlay-qa-tests.ts) for examples.
2388
2432
 
2389
2433
  ### Custom Editor
2390
2434
 
@@ -2509,14 +2553,14 @@ const highlighted = highlightCode(code, lang, theme);
2509
2553
 
2510
2554
  ## Mode Behavior
2511
2555
 
2512
- | Mode | UI Methods | Notes |
2513
- |------|-----------|-------|
2514
- | Interactive | Full TUI | Normal operation |
2515
- | RPC (`--mode rpc`) | JSON protocol | Host handles UI, see [rpc.md](rpc.md) |
2516
- | JSON (`--mode json`) | No-op | Event stream to stdout, see [json.md](json.md) |
2517
- | Print (`-p`) | No-op | Extensions run but can't prompt |
2556
+ | Mode | `ctx.mode` | `ctx.hasUI` | Notes |
2557
+ |------|------------|-------------|-------|
2558
+ | Interactive | `"tui"` | `true` | Full TUI with terminal rendering |
2559
+ | RPC (`--mode rpc`) | `"rpc"` | `true` | Dialogs and notifications via JSON protocol; `custom()` returns `undefined`. See [rpc.md](rpc.md) |
2560
+ | JSON (`--mode json`) | `"json"` | `false` | Event stream to stdout; UI methods are no-ops |
2561
+ | Print (`-p`) | `"print"` | `false` | Extensions run but can't prompt |
2518
2562
 
2519
- In non-interactive modes, check `ctx.hasUI` before using UI methods.
2563
+ Use `ctx.mode === "tui"` before TUI-specific features (`custom()`, component factories, terminal input). Use `ctx.hasUI` before dialog and notification methods that work in both TUI and RPC modes.
2520
2564
 
2521
2565
  ## Examples Reference
2522
2566
 
@@ -2543,6 +2587,7 @@ All examples in [examples/extensions/](../examples/extensions/).
2543
2587
  | `shutdown-command.ts` | Graceful shutdown command | `registerCommand`, `shutdown()` |
2544
2588
  | **Events & Gates** |||
2545
2589
  | `permission-gate.ts` | Block dangerous commands | `on("tool_call")`, `ui.confirm` |
2590
+ | `project-trust.ts` | Decide or defer project trust from a user/global or CLI extension | `on("project_trust")`, trust UI, required trust result |
2546
2591
  | `protected-paths.ts` | Block writes to specific paths | `on("tool_call")` |
2547
2592
  | `confirm-destructive.ts` | Confirm session changes | `on("session_before_switch")`, `on("session_before_fork")` |
2548
2593
  | `dirty-repo-guard.ts` | Warn on dirty git repo | `on("session_before_*")`, `exec` |
@@ -2582,6 +2627,7 @@ All examples in [examples/extensions/](../examples/extensions/).
2582
2627
  | `ssh.ts` | SSH remote execution | `registerFlag`, `on("user_bash")`, `on("before_agent_start")`, tool operations |
2583
2628
  | `interactive-shell.ts` | Persistent shell session | `on("user_bash")` |
2584
2629
  | `sandbox/` | Sandboxed tool execution | Tool operations |
2630
+ | `gondolin/` | Route built-in tools and `!` commands into a Gondolin micro-VM | Tool operations, built-in tool overrides, `on("user_bash")` |
2585
2631
  | `subagent/` | Spawn sub-agents | `registerTool`, `exec` |
2586
2632
  | **Games** |||
2587
2633
  | `snake.ts` | Snake game | `registerCommand`, `ui.custom`, keyboard handling |
package/docs/index.md CHANGED
@@ -41,6 +41,8 @@ For the full first-run flow, see [Quickstart](quickstart.md).
41
41
  - [Quickstart](quickstart.md) - install, authenticate, and run a first session.
42
42
  - [Using Pi](usage.md) - interactive mode, slash commands, context files, and CLI reference.
43
43
  - [Providers](providers.md) - subscription and API-key setup for built-in providers.
44
+ - [Security](security.md) - project trust, sandbox boundaries, and vulnerability reporting.
45
+ - [Containerization](containerization.md) - sandbox pi with OpenShell, Gondolin, or Docker.
44
46
  - [Settings](settings.md) - global and project settings.
45
47
  - [Keybindings](keybindings.md) - default shortcuts and custom keybindings.
46
48
  - [Sessions](sessions.md) - session management, branching, and tree navigation.
package/docs/packages.md CHANGED
@@ -38,7 +38,9 @@ pi update --extension npm:@foo/bar
38
38
 
39
39
  These commands manage pi packages, not the pi CLI installation. To uninstall pi itself, see [Quickstart](quickstart.md#uninstall).
40
40
 
41
- By default, `install` and `remove` write to user settings (`~/.pi/agent/settings.json`). Use `-l` to write to project settings (`.pi/settings.json`) instead. Project settings can be shared with your team, and pi installs any missing packages automatically on startup.
41
+ By default, `install` and `remove` write to user settings (`~/.pi/agent/settings.json`). Use `-l` to write to project settings (`.pi/settings.json`) instead. Project settings can be shared with your team, and pi installs any missing packages automatically on startup after the project is trusted.
42
+
43
+ Project package commands read project settings only when the project is trusted. Use `--approve` to trust project-local files for one command, or `--no-approve` to ignore them for one command.
42
44
 
43
45
  To try a package without installing it, use `--extension` or `-e`. This installs to a temporary directory for the current run only:
44
46
 
@@ -9,7 +9,7 @@ Prompt templates are Markdown snippets that expand into full prompts. Type `/nam
9
9
  Pi loads prompt templates from:
10
10
 
11
11
  - Global: `~/.pi/agent/prompts/*.md`
12
- - Project: `.pi/prompts/*.md`
12
+ - Project: `.pi/prompts/*.md` (only after the project is trusted)
13
13
  - Packages: `prompts/` directories or `pi.prompts` entries in `package.json`
14
14
  - Settings: `prompts` array with files or directories
15
15
  - CLI: `--prompt-template <path>` (repeatable)
package/docs/providers.md CHANGED
@@ -49,9 +49,11 @@ pi
49
49
  | Provider | Environment Variable | `auth.json` key |
50
50
  |----------|----------------------|------------------|
51
51
  | Anthropic | `ANTHROPIC_API_KEY` | `anthropic` |
52
+ | Ant Ling | `ANT_LING_API_KEY` | `ant-ling` |
52
53
  | Azure OpenAI Responses | `AZURE_OPENAI_API_KEY` | `azure-openai-responses` |
53
54
  | OpenAI | `OPENAI_API_KEY` | `openai` |
54
55
  | DeepSeek | `DEEPSEEK_API_KEY` | `deepseek` |
56
+ | NVIDIA NIM | `NVIDIA_API_KEY` | `nvidia` |
55
57
  | Google Gemini | `GEMINI_API_KEY` | `google` |
56
58
  | Mistral | `MISTRAL_API_KEY` | `mistral` |
57
59
  | Groq | `GROQ_API_KEY` | `groq` |
@@ -62,6 +64,7 @@ pi
62
64
  | OpenRouter | `OPENROUTER_API_KEY` | `openrouter` |
63
65
  | Vercel AI Gateway | `AI_GATEWAY_API_KEY` | `vercel-ai-gateway` |
64
66
  | ZAI | `ZAI_API_KEY` | `zai` |
67
+ | ZAI Coding Plan (China) | `ZAI_CODING_CN_API_KEY` | `zai-coding-cn` |
65
68
  | OpenCode Zen | `OPENCODE_API_KEY` | `opencode` |
66
69
  | OpenCode Go | `OPENCODE_API_KEY` | `opencode-go` |
67
70
  | Hugging Face | `HF_TOKEN` | `huggingface` |
@@ -84,8 +87,10 @@ Store credentials in `~/.pi/agent/auth.json`:
84
87
  ```json
85
88
  {
86
89
  "anthropic": { "type": "api_key", "key": "sk-ant-..." },
90
+ "ant-ling": { "type": "api_key", "key": "..." },
87
91
  "openai": { "type": "api_key", "key": "sk-..." },
88
92
  "deepseek": { "type": "api_key", "key": "sk-..." },
93
+ "nvidia": { "type": "api_key", "key": "nvapi-..." },
89
94
  "google": { "type": "api_key", "key": "..." },
90
95
  "opencode": { "type": "api_key", "key": "..." },
91
96
  "opencode-go": { "type": "api_key", "key": "..." },
package/docs/rpc.md CHANGED
@@ -1003,7 +1003,7 @@ Some `ExtensionUIContext` methods are not supported or degraded in RPC mode beca
1003
1003
  - `getTheme()` returns `undefined`
1004
1004
  - `setTheme()` returns `{ success: false, error: "..." }`
1005
1005
 
1006
- Note: `ctx.hasUI` is `true` in RPC mode because the dialog and fire-and-forget methods are functional via the extension UI sub-protocol.
1006
+ Note: `ctx.mode` is `"rpc"` and `ctx.hasUI` is `true` in RPC mode because the dialog and fire-and-forget methods are functional via the extension UI sub-protocol. Use `ctx.mode === "tui"` to guard TUI-specific features like `custom()` that require a real terminal.
1007
1007
 
1008
1008
  ### Extension UI Requests (stdout)
1009
1009
 
package/docs/sdk.md CHANGED
@@ -1112,6 +1112,11 @@ createEventBus
1112
1112
 
1113
1113
  // Helpers
1114
1114
  defineTool
1115
+ getAgentDir
1116
+ getPackageDir
1117
+ getReadmePath
1118
+ getDocsPath
1119
+ getExamplesPath
1115
1120
 
1116
1121
  // Session management
1117
1122
  SessionManager
@@ -0,0 +1,57 @@
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 inputs. 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 trust inputs when it finds any of these from the current working directory:
10
+
11
+ - `.pi/` in the current directory
12
+ - `AGENTS.md` or `CLAUDE.md` in the current directory or an ancestor directory
13
+ - `.agents/skills` in the current directory or an ancestor directory
14
+
15
+ When an interactive session starts in a project with trust inputs and no saved decision, pi asks whether to trust the project. Saved decisions are stored per canonical working directory in `~/.pi/agent/trust.json`.
16
+
17
+ Trusting a project allows pi to load project-local inputs, including:
18
+
19
+ - project instructions from `AGENTS.md` or `CLAUDE.md`
20
+ - `.pi/settings.json`
21
+ - `.pi` resources such as extensions, skills, prompt templates, themes, and system prompt files
22
+ - missing project packages configured through project settings
23
+ - project-local extensions and project package-managed extensions
24
+
25
+ Declining trust skips those project-local inputs. Before trust is resolved, pi only loads 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.
26
+
27
+ Non-interactive modes (`-p`, `--mode json`, and `--mode rpc`) do not show a trust prompt. Without a saved trust decision, they ignore project-local inputs unless `--approve`/`-a` is passed. Use `--no-approve`/`-na` to ignore project-local inputs for one run even when the project is trusted.
28
+
29
+ ## No Built-in Sandbox
30
+
31
+ 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.
32
+
33
+ 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.
34
+
35
+ Project trust is only an input-loading guard. It prevents a repository from silently changing pi's instructions, 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, or build output is expected local-agent risk and cannot be reliably prevented by pi.
36
+
37
+ ## Running Untrusted or Unmonitored Work
38
+
39
+ 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.
40
+
41
+ Common patterns are documented in [Containerization](containerization.md):
42
+
43
+ - run the whole `pi` process inside OpenShell or Docker
44
+ - run host pi while routing built-in tool execution into a Gondolin micro-VM
45
+ - mount only the workspace paths the agent should access
46
+ - avoid mounting host `~/.pi/agent` unless the container should access host sessions, settings, and credentials
47
+ - pass the minimum required API keys or use short-lived credentials
48
+ - restrict network access when the task does not need it
49
+ - review diffs and outputs before copying results back to trusted systems
50
+
51
+ 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.
52
+
53
+ ## Reporting Security Issues
54
+
55
+ To report a security issue, follow the repository [Security Policy](https://github.com/earendil-works/pi-mono/blob/main/SECURITY.md). Do not open a public issue for security-sensitive reports.
56
+
57
+ 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.
package/docs/settings.md CHANGED
@@ -9,6 +9,16 @@ Pi uses JSON settings files with project settings overriding global settings.
9
9
 
10
10
  Edit directly or use `/settings` for common options.
11
11
 
12
+ ## Project Trust
13
+
14
+ On interactive startup, pi asks before trusting a project folder that contains project-local inputs and has no saved decision in `~/.pi/agent/trust.json`. Trusting a project allows pi to read project instructions (`AGENTS.md`/`CLAUDE.md`), load `.pi/settings.json` and `.pi` resources, install missing project packages, and execute project extensions.
15
+
16
+ Non-interactive modes (`-p`, `--mode json`, and `--mode rpc`) do not show a trust prompt. Without a saved trust decision, they ignore project-local inputs unless `--approve`/`-a` is passed. Use `--no-approve`/`-na` to ignore project-local inputs for one run even when the project is trusted.
17
+
18
+ `pi config` assumes project trust for that command so you can view and change project resource settings before starting a session. It does not save a trust decision; starting a session in that folder still prompts. Pass `--no-approve` to hide project-local inputs in `pi config`.
19
+
20
+ Use `/trust` in interactive mode to save a project trust decision for future sessions. It writes `~/.pi/agent/trust.json` only; the current session is not reloaded, so restart pi for changes to take effect.
21
+
12
22
  ## All Settings
13
23
 
14
24
  ### Model & Thinking
package/docs/skills.md CHANGED
@@ -26,7 +26,7 @@ Pi loads skills from:
26
26
  - Global:
27
27
  - `~/.pi/agent/skills/`
28
28
  - `~/.agents/skills/`
29
- - Project:
29
+ - Project (only after the project is trusted):
30
30
  - `.pi/skills/`
31
31
  - `.agents/skills/` in `cwd` and ancestor directories (up to git repo root, or filesystem root when not in a repo)
32
32
  - Packages: `skills/` directories or `pi.skills` entries in `package.json`
@@ -40,7 +40,7 @@ If you want `Shift+Enter` to keep working in tmux via that remap, add `ctrl+j` t
40
40
 
41
41
  ## WezTerm
42
42
 
43
- Create `~/.wezterm.lua`:
43
+ WezTerm usually works out of the box for `Shift+Enter` via xterm modifyOtherKeys. To use the Kitty keyboard protocol explicitly, create `~/.wezterm.lua`:
44
44
 
45
45
  ```lua
46
46
  local wezterm = require 'wezterm'
@@ -49,16 +49,50 @@ config.enable_kitty_keyboard = true
49
49
  return config
50
50
  ```
51
51
 
52
+ On macOS, WezTerm binds `Option+Enter` to fullscreen by default. To use `Option+Enter` for pi follow-up queueing, add this key override:
53
+
54
+ ```lua
55
+ local wezterm = require 'wezterm'
56
+ local config = wezterm.config_builder()
57
+ config.keys = {
58
+ {
59
+ key = 'Enter',
60
+ mods = 'ALT',
61
+ action = wezterm.action.SendString('\x1b[13;3u'),
62
+ },
63
+ }
64
+ return config
65
+ ```
66
+
67
+ If you already have a `config.keys` table, add the entry to it.
68
+
52
69
  On WSL, WezTerm may require a visible hardware cursor for IME candidate window positioning. If CJK IME candidates do not follow the text cursor, set `PI_HARDWARE_CURSOR=1` before running pi or set `showHardwareCursor` to `true` in settings.
53
70
 
71
+ ## Alacritty
72
+
73
+ Alacritty usually works out of the box for `Shift+Enter`. On macOS, `Option+Enter` may arrive as plain `Enter`. To use `Option+Enter` for pi follow-up queueing, add to `~/.config/alacritty/alacritty.toml`:
74
+
75
+ ```toml
76
+ [[keyboard.bindings]]
77
+ key = "Enter"
78
+ mods = "Alt"
79
+ chars = "\u001b[13;3u"
80
+ ```
81
+
82
+ Restart Alacritty after changing the config.
83
+
54
84
  ## VS Code (Integrated Terminal)
55
85
 
86
+ VS Code 1.109.5 and newer enable Kitty keyboard protocol in the integrated terminal by default, so `Shift+Enter` should work out of the box.
87
+
88
+ VS Code versions older than 1.109.5 need an explicit terminal keybinding for `Shift+Enter`.
89
+
56
90
  `keybindings.json` locations:
57
91
  - macOS: `~/Library/Application Support/Code/User/keybindings.json`
58
92
  - Linux: `~/.config/Code/User/keybindings.json`
59
93
  - Windows: `%APPDATA%\\Code\\User\\keybindings.json`
60
94
 
61
- Add to `keybindings.json` to enable `Shift+Enter` for multi-line input:
95
+ Add to `keybindings.json`:
62
96
 
63
97
  ```json
64
98
  {
package/docs/themes.md CHANGED
@@ -20,7 +20,7 @@ Pi loads themes from:
20
20
 
21
21
  - Built-in: `dark`, `light`
22
22
  - Global: `~/.pi/agent/themes/*.json`
23
- - Project: `.pi/themes/*.json`
23
+ - Project: `.pi/themes/*.json` (only after the project is trusted)
24
24
  - Packages: `themes/` directories or `pi.themes` entries in `package.json`
25
25
  - Settings: `themes` array with files or directories
26
26
  - CLI: `--theme <path>` (repeatable)
package/docs/tmux.md CHANGED
@@ -18,7 +18,7 @@ tmux kill-server
18
18
  tmux
19
19
  ```
20
20
 
21
- Pi requests extended key reporting automatically when Kitty keyboard protocol is not available. With `extended-keys-format csi-u`, tmux forwards modified keys in CSI-u format, which is the most reliable configuration.
21
+ Pi requests extended key reporting automatically when Kitty keyboard protocol is not available. With `extended-keys-format csi-u`, tmux forwards modified keys in CSI-u format, which is the most reliable configuration. The `extended-keys-format` option requires tmux 3.5 or later.
22
22
 
23
23
  ## Why `csi-u` Is Recommended
24
24
 
@@ -57,5 +57,7 @@ This affects the default keybindings (`Enter` to submit, `Shift+Enter` for newli
57
57
 
58
58
  ## Requirements
59
59
 
60
- - tmux 3.2 or later (run `tmux -V` to check)
60
+ - tmux 3.5 or later for `extended-keys-format csi-u` (run `tmux -V` to check)
61
61
  - A terminal emulator that supports extended keys (Ghostty, Kitty, iTerm2, WezTerm, Windows Terminal)
62
+
63
+ With tmux 3.2 through 3.4, omit `extended-keys-format csi-u`; Pi still supports tmux's default xterm `modifyOtherKeys` format.
package/docs/tui.md CHANGED
@@ -145,8 +145,11 @@ const result = await ctx.ui.custom<string | null>(
145
145
  // Responsive: hide on narrow terminals
146
146
  visible: (termWidth, termHeight) => termWidth >= 80,
147
147
  },
148
- // Get handle for programmatic visibility control
148
+ // Get handle for programmatic focus and visibility control
149
149
  onHandle: (handle) => {
150
+ // handle.focus() - focus this overlay and bring it to the visual front
151
+ // handle.unfocus() - release input to normal fallback
152
+ // handle.unfocus({ target }) - release input to a specific component or null
150
153
  // handle.setHidden(true/false) - toggle visibility
151
154
  // handle.hide() - permanently remove
152
155
  },
@@ -154,6 +157,12 @@ const result = await ctx.ui.custom<string | null>(
154
157
  );
155
158
  ```
156
159
 
160
+ ### Overlay Focus
161
+
162
+ A focused visible overlay keeps input ownership across temporary non-overlay UI. If an overlay opens another `ctx.ui.custom()` component without `{ overlay: true }`, that replacement UI receives input while it is active; when it closes, the focused overlay can reclaim input.
163
+
164
+ Use `handle.unfocus()` when a visible overlay should stop owning input and let TUI fall back to another visible capturing overlay or the previous focus target. Use `handle.unfocus({ target })` when a specific component should receive input while the overlay stays visible. Passing `{ target: null }` intentionally leaves no focused component until focus is set again.
165
+
157
166
  ### Overlay Lifecycle
158
167
 
159
168
  Overlay components are disposed when closed. Don't reuse references - create fresh instances:
package/docs/usage.md CHANGED
@@ -96,8 +96,8 @@ See [Sessions](sessions.md) and [Compaction](compaction.md) for details.
96
96
  Pi loads `AGENTS.md` or `CLAUDE.md` at startup from:
97
97
 
98
98
  - `~/.pi/agent/AGENTS.md` for global instructions
99
- - parent directories, walking up from the current working directory
100
- - the current directory
99
+ - parent directories, walking up from the current working directory when the project is trusted
100
+ - the current directory when the project is trusted
101
101
 
102
102
  Use context files for project conventions, commands, safety rules, and preferences. Disable loading with `--no-context-files` or `-nc`.
103
103
 
@@ -110,6 +110,16 @@ Replace the default system prompt with:
110
110
 
111
111
  Append to the default prompt without replacing it with `APPEND_SYSTEM.md` in either location.
112
112
 
113
+ ### Project Trust
114
+
115
+ On interactive startup, pi asks before trusting a project folder that contains project-local inputs and has no saved decision in `~/.pi/agent/trust.json`. Trusting a project allows pi to read project instructions (`AGENTS.md`/`CLAUDE.md`), load `.pi/settings.json` and `.pi` resources, install missing project packages, and execute project extensions.
116
+
117
+ Non-interactive modes (`-p`, `--mode json`, and `--mode rpc`) do not show a trust prompt. Without a saved trust decision, they ignore project-local inputs unless `--approve`/`-a` is passed. Use `--no-approve`/`-na` to ignore project-local inputs for one run even when the project is trusted.
118
+
119
+ `pi config` assumes project trust for that command so you can view and change project resource settings before starting a session. It does not save a trust decision; starting a session in that folder still prompts. Pass `--no-approve` to hide project-local inputs in `pi config`.
120
+
121
+ Use `/trust` in interactive mode to save a project trust decision for future sessions. It writes `~/.pi/agent/trust.json` only; the current session is not reloaded, so restart pi for changes to take effect.
122
+
113
123
  ## Exporting and Sharing Sessions
114
124
 
115
125
  Use `/export [file]` to write a session to HTML.
@@ -138,7 +148,7 @@ pi list # List installed packages
138
148
  pi config # Enable/disable package resources
139
149
  ```
140
150
 
141
- These commands manage pi packages, not the pi CLI installation. To uninstall pi itself, see [Quickstart](quickstart.md#uninstall).
151
+ These commands manage pi packages, not the pi CLI installation. To uninstall pi itself, see [Quickstart](quickstart.md#uninstall). Project package commands accept `--approve`/`--no-approve` to trust or ignore project-local package settings for one command.
142
152
 
143
153
  See [Pi Packages](packages.md) for package sources and security notes.
144
154
 
@@ -219,6 +229,8 @@ pi --no-extensions -e ./my-extension.ts
219
229
  | `--system-prompt <text>` | Replace default prompt; context files and skills are still appended |
220
230
  | `--append-system-prompt <text>` | Append to system prompt |
221
231
  | `--verbose` | Force verbose startup |
232
+ | `-a`, `--approve` | Trust project-local files for this run |
233
+ | `-na`, `--no-approve` | Ignore project-local files for this run |
222
234
  | `-h`, `--help` | Show help |
223
235
  | `-v`, `--version` | Show version |
224
236
 
@@ -275,7 +287,7 @@ pi --exclude-tools ask_question
275
287
  | `PI_PACKAGE_DIR` | Override package directory, useful for Nix/Guix store paths |
276
288
  | `PI_OFFLINE` | Disable startup network operations, including update checks, package update checks, and install/update telemetry |
277
289
  | `PI_SKIP_VERSION_CHECK` | Skip the Pi version update check at startup. This prevents the `pi.dev` latest-version request |
278
- | `PI_TELEMETRY` | Override install/update telemetry: `1`/`true`/`yes` or `0`/`false`/`no`. This does not disable update checks |
290
+ | `PI_TELEMETRY` | Override install/update telemetry and provider attribution headers: `1`/`true`/`yes` or `0`/`false`/`no`. This does not disable update checks |
279
291
  | `PI_CACHE_RETENTION` | Set to `long` for extended prompt cache where supported |
280
292
  | `VISUAL`, `EDITOR` | External editor for Ctrl+G |
281
293
 
@@ -19,10 +19,12 @@ cp permission-gate.ts ~/.pi/agent/extensions/
19
19
  | Extension | Description |
20
20
  |-----------|-------------|
21
21
  | `permission-gate.ts` | Prompts for confirmation before dangerous bash commands (rm -rf, sudo, etc.) |
22
+ | `project-trust.ts` | Demonstrates the `project_trust` event for user/global and CLI extensions |
22
23
  | `protected-paths.ts` | Blocks writes to protected paths (.env, .git/, node_modules/) |
23
24
  | `confirm-destructive.ts` | Confirms before destructive session actions (clear, switch, fork) |
24
25
  | `dirty-repo-guard.ts` | Prevents session changes with uncommitted git changes |
25
26
  | `sandbox/` | OS-level sandboxing using `@anthropic-ai/sandbox-runtime` with per-project config |
27
+ | `gondolin/` | Route built-in tools and `!` commands into a Gondolin micro-VM |
26
28
 
27
29
  ### Custom Tools
28
30
 
@@ -47,7 +47,7 @@ function getPiMascot(theme: Theme): string[] {
47
47
  export default function (pi: ExtensionAPI) {
48
48
  // Set custom header immediately on load (if UI is available)
49
49
  pi.on("session_start", async (_event, ctx) => {
50
- if (ctx.hasUI) {
50
+ if (ctx.mode === "tui") {
51
51
  ctx.ui.setHeader((_tui, theme) => {
52
52
  return {
53
53
  render(_width: number): string[] {