mu-agent 0.1.7 → 0.1.10

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 (198) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +34 -29
  3. package/dist/bundle/chunks/anthropic-messages-4PAJY4R6.js +6 -0
  4. package/dist/bundle/chunks/anthropic.js +2 -2
  5. package/dist/bundle/chunks/azure-openai-responses-Y4BBWQ3N.js +2 -0
  6. package/dist/bundle/chunks/bedrock-converse-stream.js +12 -9
  7. package/dist/bundle/chunks/{chunk-TRDNDS6A.js → chunk-3V45WARH.js} +6 -3
  8. package/dist/bundle/chunks/{chunk-XDUWOHPL.js → chunk-5AGIVGSV.js} +3 -3
  9. package/dist/bundle/chunks/chunk-6QGV3IWD.js +6 -0
  10. package/dist/bundle/chunks/chunk-7CBJINYJ.js +20 -0
  11. package/dist/bundle/chunks/{chunk-DRQDKNXA.js → chunk-7DDKXS2Q.js} +1 -1
  12. package/dist/bundle/chunks/chunk-BSS6T6KQ.js +2 -0
  13. package/dist/bundle/chunks/chunk-CF5GWZHW.js +31 -0
  14. package/dist/bundle/chunks/chunk-DNNHZBQR.js +4 -0
  15. package/dist/bundle/chunks/chunk-FN6OEZYR.js +2 -0
  16. package/dist/bundle/chunks/chunk-FTJT2X6E.js +2 -0
  17. package/dist/bundle/chunks/chunk-HZNN636Z.js +130 -0
  18. package/dist/bundle/chunks/{chunk-4L3WN2XY.js → chunk-JXWJOIH4.js} +1 -1
  19. package/dist/bundle/chunks/{chunk-4O2SCVYF.js → chunk-KIDDRTZP.js} +4 -4
  20. package/dist/bundle/chunks/chunk-LMNWTX2L.js +11 -0
  21. package/dist/bundle/chunks/chunk-LPXNMA2W.js +2 -0
  22. package/dist/bundle/chunks/{chunk-6CYCI3EJ.js → chunk-LVVZS2NO.js} +1 -1
  23. package/dist/bundle/chunks/chunk-NN4BEPYX.js +2 -0
  24. package/dist/bundle/chunks/chunk-O7IPTASE.js +1221 -0
  25. package/dist/bundle/chunks/chunk-PMRZO46Y.js +2 -0
  26. package/dist/bundle/chunks/chunk-QOEEJKS4.js +9 -0
  27. package/dist/bundle/chunks/chunk-R4VPBBDS.js +2 -0
  28. package/dist/bundle/chunks/chunk-RAQ6TU76.js +2 -0
  29. package/dist/bundle/chunks/chunk-RDZVAGPR.js +2 -0
  30. package/dist/bundle/chunks/chunk-SGOTYFMT.js +91 -0
  31. package/dist/bundle/chunks/chunk-TMTOQ7H7.js +2 -0
  32. package/dist/bundle/chunks/chunk-UKVNB6C4.js +2 -0
  33. package/dist/bundle/chunks/chunk-VJLOQZKR.js +9 -0
  34. package/dist/bundle/chunks/chunk-WCGU75WO.js +11 -0
  35. package/dist/bundle/chunks/chunk-X234222Q.js +64 -0
  36. package/dist/bundle/chunks/cli-722OL3K5.js +51 -0
  37. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-MEZHQVNP.js +2 -0
  38. package/dist/bundle/chunks/codemode-worker.js +478 -0
  39. package/dist/bundle/chunks/easter-egg-3d-6H34EDGX.js +2 -0
  40. package/dist/bundle/chunks/execute-KVSEIDWL.js +499 -0
  41. package/dist/bundle/chunks/github-copilot.js +1 -1
  42. package/dist/bundle/chunks/{google-generative-ai-C44KRRZ4.js → google-generative-ai-D2VJQBTK.js} +1 -1
  43. package/dist/bundle/chunks/{google-vertex-25DUXPTJ.js → google-vertex-SQG2BO6C.js} +1 -1
  44. package/dist/bundle/chunks/https-proxy-agent-LVOO5TPL.js +13 -0
  45. package/dist/bundle/chunks/image-resize-worker.js +1 -1
  46. package/dist/bundle/chunks/{jiti-loader-C3NU2SDH.js → jiti-loader-GL4HJFAD.js} +1 -1
  47. package/dist/bundle/chunks/{jiti-static-loader-E6ANQD5T.js → jiti-static-loader-2RCDI6B4.js} +1 -1
  48. package/dist/bundle/chunks/{lib-HGQMNYVT.js → lib-4AVRLBHM.js} +2 -2
  49. package/dist/bundle/chunks/llama-cpp-classify-5YHLY3RC.js +22 -0
  50. package/dist/bundle/chunks/mistral-conversations-BDARVJTT.js +5 -0
  51. package/dist/bundle/chunks/{multipart-parser-SQ6GDJL7.js → multipart-parser-FMGQ7342.js} +1 -1
  52. package/dist/bundle/chunks/{node-TWVVAGPO.js → node-AUOGOBCN.js} +1 -1
  53. package/dist/bundle/chunks/node-KCMANYC2.js +16 -0
  54. package/dist/bundle/chunks/openai-chatgpt.js +86 -0
  55. package/dist/bundle/chunks/openai-codex-responses-CECGTDYD.js +10 -0
  56. package/dist/bundle/chunks/openai-codex.js +2 -2
  57. package/dist/bundle/chunks/openai-completions-UOA7MELD.js +7 -0
  58. package/dist/bundle/chunks/openai-decisions-HLM372N6.js +5 -0
  59. package/dist/bundle/chunks/openai-responses-TII7ZY5X.js +3 -0
  60. package/dist/bundle/chunks/{openrouter-images-JVEJN44Q.js → openrouter-images-7T452AS5.js} +1 -1
  61. package/dist/bundle/chunks/openrouter.js +2 -2
  62. package/dist/bundle/chunks/{pi-messages-TM5SOOIW.js → pi-messages-2UDKLKOO.js} +1 -1
  63. package/dist/bundle/chunks/radius.js +2 -2
  64. package/dist/bundle/chunks/runtime-O3ELDOM7.js +2 -0
  65. package/dist/bundle/chunks/{src-UK77SYZE.js → src-QKGKDFSU.js} +1 -1
  66. package/dist/bundle/chunks/typesafe-system-one-KNCICMO5.js +2 -0
  67. package/dist/bundle/chunks/virtual-modules-IKEARUOZ.js +2 -0
  68. package/dist/bundle/cli-runtime.js +1 -1
  69. package/dist/bundle/index.js +1 -1
  70. package/dist/bundle/native/darwin/prebuilds/darwin-arm64/darwin-platform.node +0 -0
  71. package/dist/bundle/native/darwin/prebuilds/darwin-x64/darwin-platform.node +0 -0
  72. package/dist/bundle/rpc-entry.js +1 -1
  73. package/dist/core/export-html/template.js +37 -16
  74. package/dist/modes/interactive/theme/dark.json +60 -73
  75. package/dist/modes/interactive/theme/light.json +58 -70
  76. package/dist/modes/interactive/theme/system-theme.d.ts +55 -0
  77. package/dist/modes/interactive/theme/system-theme.d.ts.map +1 -0
  78. package/dist/modes/interactive/theme/system-theme.js +546 -0
  79. package/dist/modes/interactive/theme/system-theme.js.map +1 -0
  80. package/dist/modes/interactive/theme/theme-controller.d.ts +43 -9
  81. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  82. package/dist/modes/interactive/theme/theme-controller.js +121 -79
  83. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  84. package/dist/modes/interactive/theme/theme-schema.d.ts +28 -0
  85. package/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -0
  86. package/dist/modes/interactive/theme/theme-schema.js +105 -0
  87. package/dist/modes/interactive/theme/theme-schema.js.map +1 -0
  88. package/dist/modes/interactive/theme/theme-tokens.d.ts +257 -0
  89. package/dist/modes/interactive/theme/theme-tokens.d.ts.map +1 -0
  90. package/dist/modes/interactive/theme/theme-tokens.js +94 -0
  91. package/dist/modes/interactive/theme/theme-tokens.js.map +1 -0
  92. package/dist/modes/interactive/theme/theme.d.ts +47 -56
  93. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  94. package/dist/modes/interactive/theme/theme.js +149 -143
  95. package/dist/modes/interactive/theme/theme.js.map +1 -1
  96. package/dist/native/darwin/prebuilds/darwin-arm64/darwin-platform.node +0 -0
  97. package/dist/native/darwin/prebuilds/darwin-x64/darwin-platform.node +0 -0
  98. package/docs/cli-integration.md +1 -1
  99. package/docs/cli.md +78 -13
  100. package/docs/codemode.md +230 -0
  101. package/docs/compaction.md +5 -5
  102. package/docs/configuration.md +2 -0
  103. package/docs/custom-provider.md +53 -1
  104. package/docs/docs.json +21 -1
  105. package/docs/environment-variables.md +5 -3
  106. package/docs/extensions.md +172 -10
  107. package/docs/index.md +1 -1
  108. package/docs/json.md +3 -3
  109. package/docs/keybindings.md +7 -6
  110. package/docs/llama-cpp.md +21 -1
  111. package/docs/mcp.md +272 -0
  112. package/docs/message-types.md +22 -4
  113. package/docs/models-configuration.md +187 -0
  114. package/docs/models.md +100 -2
  115. package/docs/nvidia-rtx-llama-cpp.md +96 -0
  116. package/docs/packages.md +1 -1
  117. package/docs/providers.md +66 -6
  118. package/docs/quickstart.md +16 -2
  119. package/docs/rpc-commands.md +9 -3
  120. package/docs/rpc.md +3 -1
  121. package/docs/sdk.md +8 -3
  122. package/docs/security.md +2 -0
  123. package/docs/session-format.md +5 -1
  124. package/docs/sessions.md +1 -1
  125. package/docs/settings.md +30 -8
  126. package/docs/terminal-setup.md +14 -0
  127. package/docs/themes.md +31 -7
  128. package/docs/tui.md +71 -1
  129. package/docs/usage.md +2 -2
  130. package/docs/virtual-models.md +114 -0
  131. package/docs/windows.md +2 -0
  132. package/examples/README.md +1 -4
  133. package/examples/extensions/README.md +1 -0
  134. package/examples/extensions/built-in-tool-renderer.ts +16 -40
  135. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  136. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  137. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  138. package/examples/extensions/custom-provider-gitlab-duo/test.ts +5 -5
  139. package/examples/extensions/dynamic-resources/dynamic.json +1 -1
  140. package/examples/extensions/gondolin/package-lock.json +2 -2
  141. package/examples/extensions/gondolin/package.json +1 -1
  142. package/examples/extensions/jev-router.ts +113 -0
  143. package/examples/extensions/minimal-mode.ts +28 -101
  144. package/examples/extensions/overlay-test.ts +2 -2
  145. package/examples/extensions/plan-mode/index.ts +6 -2
  146. package/examples/extensions/sandbox/package-lock.json +2 -2
  147. package/examples/extensions/sandbox/package.json +1 -1
  148. package/examples/extensions/subagent/index.ts +4 -6
  149. package/examples/extensions/with-deps/package-lock.json +2 -2
  150. package/examples/extensions/with-deps/package.json +1 -1
  151. package/examples/rpc-client.ts +1 -1
  152. package/examples/rpc-extension-ui.ts +1 -1
  153. package/examples/sdk/14-codemode-mcp.ts +61 -0
  154. package/examples/sdk/README.md +2 -1
  155. package/judge/THIRD_PARTY_NOTICES.md +63 -0
  156. package/judge/dist/auth.js +169 -123
  157. package/judge/dist/import.js +36 -30
  158. package/judge/dist/setup.js +250 -120
  159. package/judge/manifest.json +1008 -316
  160. package/judge/{dist/kyrn-judge.js → mu/index.js} +6933 -5995
  161. package/judge/themes/mu-dark.json +80 -0
  162. package/judge/themes/mu-light.json +80 -0
  163. package/kyrn/bin/kyrn-doctor +75 -25
  164. package/kyrn/bin/kyrn-judge-local +2 -2
  165. package/kyrn/bin/kyrn-ledger +1 -1
  166. package/kyrn/bin/mu.mjs +149 -107
  167. package/package.json +4 -5
  168. package/dist/bundle/chunks/anthropic-messages-VMESUHQ7.js +0 -6
  169. package/dist/bundle/chunks/azure-openai-responses-K232MQFF.js +0 -2
  170. package/dist/bundle/chunks/chunk-A3JYRWB6.js +0 -2
  171. package/dist/bundle/chunks/chunk-AYFRR3OD.js +0 -2
  172. package/dist/bundle/chunks/chunk-DTD7JQ7Y.js +0 -42
  173. package/dist/bundle/chunks/chunk-FU4XQUSL.js +0 -11
  174. package/dist/bundle/chunks/chunk-GNYZK6XN.js +0 -2
  175. package/dist/bundle/chunks/chunk-HEMXN7VJ.js +0 -1653
  176. package/dist/bundle/chunks/chunk-MVPXOVOJ.js +0 -2
  177. package/dist/bundle/chunks/chunk-NUHFSC37.js +0 -25
  178. package/dist/bundle/chunks/chunk-V7IXECST.js +0 -11
  179. package/dist/bundle/chunks/chunk-XNGRGP62.js +0 -2
  180. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-NR2TDCXU.js +0 -2
  181. package/dist/bundle/chunks/https-proxy-agent-2VXB7436.js +0 -13
  182. package/dist/bundle/chunks/mistral-conversations-6IHQOR4R.js +0 -5
  183. package/dist/bundle/chunks/node-O3RIBJRH.js +0 -16
  184. package/dist/bundle/chunks/openai-codex-responses-3UAYOSSR.js +0 -10
  185. package/dist/bundle/chunks/openai-completions-FIEQGWAH.js +0 -7
  186. package/dist/bundle/chunks/openai-responses-OZJXLHFC.js +0 -2
  187. package/dist/bundle/chunks/typesafe-system-one-VKYX4OGY.js +0 -2
  188. package/dist/bundle/chunks/virtual-modules-V7SXVVLP.js +0 -2
  189. package/dist/modes/interactive/theme/theme-json.d.ts +0 -85
  190. package/dist/modes/interactive/theme/theme-json.d.ts.map +0 -1
  191. package/dist/modes/interactive/theme/theme-json.js +0 -132
  192. package/dist/modes/interactive/theme/theme-json.js.map +0 -1
  193. package/dist/modes/interactive/theme/theme-schema.json +0 -361
  194. package/examples/plugins/pi-example-plugin/README.md +0 -38
  195. package/examples/plugins/pi-example-plugin/package.json +0 -10
  196. package/examples/plugins/pi-example-plugin/src/contract.ts +0 -13
  197. package/examples/plugins/pi-example-plugin/src/session.ts +0 -24
  198. package/examples/plugins/pi-example-plugin/src/tui.ts +0 -31
package/docs/models.md CHANGED
@@ -18,7 +18,7 @@ Browse the [model catalog](https://pi.dev/models) for current providers, model I
18
18
 
19
19
  Run `/login` and select a provider. Pi stores credentials in [`auth.json`](configuration.md#agent-directory). Run `/logout` to remove stored credentials for a provider.
20
20
 
21
- You can instead provide an API key through the provider's environment variable. This is useful in CI and other environments where Pi should not write credentials. [Provider Authentication](providers.md) lists the variables and cloud-provider setup.
21
+ You can instead provide an API key through the provider's environment variable. This is useful in CI and other environments where Pi should not write credentials. [Providers](providers.md) lists the variables and provider-specific setup.
22
22
 
23
23
  When several credential sources are configured, Pi uses a runtime `--api-key` first, then a stored `auth.json` credential, an `apiKey` from `models.json`, and finally the provider's environment variables or ambient cloud credentials. Provider extensions can define their own authentication behavior.
24
24
 
@@ -48,6 +48,7 @@ Use [`models.json`](configuration.md#agent-directory) when an endpoint speaks an
48
48
 
49
49
  ```json
50
50
  {
51
+ "$schema": "https://pi.dev/schemas/models.schema.json",
51
52
  "providers": {
52
53
  "ollama": {
53
54
  "baseUrl": "http://localhost:11434/v1",
@@ -61,10 +62,22 @@ Use [`models.json`](configuration.md#agent-directory) when an endpoint speaks an
61
62
  }
62
63
  ```
63
64
 
64
- The dummy key makes the model available to Pi; Ollama ignores it. For an authenticated endpoint, `apiKey` and header values can use `$NAME` or `${NAME}` environment interpolation, a literal value, or a leading `!command`. Commands in `models.json` run at request time and are not cached by Pi.
65
+ The dummy key makes the model available to Pi; Ollama ignores it. For an authenticated endpoint, `apiKey` and header values can use `$NAME` or `${NAME}` environment interpolation, a literal value, or a leading `!command`. `$$` and `$!` produce a literal `$` and `!`. Commands in `models.json` run at request time and are not cached by Pi.
65
66
 
66
67
  Opening `/model` reloads the file. A `models` entry adds or replaces a model with the same ID on that provider. Use `modelOverrides` to change metadata for an existing built-in or extension-provided model without replacing the provider's model list. Unknown override IDs are ignored.
67
68
 
69
+ To route a built-in provider through a proxy, set only its `baseUrl`. Its models and authentication stay unchanged:
70
+
71
+ ```json
72
+ {
73
+ "providers": {
74
+ "anthropic": { "baseUrl": "https://proxy.example.com/v1" }
75
+ }
76
+ }
77
+ ```
78
+
79
+ [Models Configuration](models-configuration.md) lists every field.
80
+
68
81
  ### Describe model input and caching
69
82
 
70
83
  Use `inputLimits.images.resize` to control how Pi encodes new image attachments, `read` results, and tool-result images before storing them in conversation history:
@@ -98,8 +111,93 @@ Use `promptCache` to declare the provider's best-effort cache lifetime in second
98
111
 
99
112
  Choose the conservative end of any published range. A model without a lifetime for the active tier is not eligible for cache warming. A `modelOverrides` entry can set `inputLimits` or `promptCache` for a built-in or extension model, including a model accessed through a validated proxy. See [`cacheWarming`](settings.md#model-and-thinking).
100
113
 
114
+ ### Configure sampling by thinking level
115
+
116
+ OpenAI-compatible APIs support free-form `samplingParams` model defaults and `samplingParamsByThinkingLevel` overrides. The latter uses Pi thinking-level keys (`off`, `minimal`, `low`, `medium`, `high`, `xhigh`, and `max`), not provider values from `thinkingLevelMap`:
117
+
118
+ ```json
119
+ {
120
+ "id": "qwen-thinking-model",
121
+ "reasoning": true,
122
+ "samplingParams": {
123
+ "temperature": 1.0,
124
+ "top_p": 0.95
125
+ },
126
+ "samplingParamsByThinkingLevel": {
127
+ "off": {
128
+ "temperature": 0.7,
129
+ "top_p": 0.8
130
+ },
131
+ "high": {
132
+ "top_k": 20
133
+ }
134
+ }
135
+ }
136
+ ```
137
+
138
+ Pi first clamps unsupported thinking levels, then merges model `samplingParams`, the effective level's override, and request-level `samplingParams` in that order. Later values win per key. Missing levels inherit the model defaults. `modelOverrides` merges per-level entries per key with the base model. These fields apply only to `openai-completions`, `openai-responses`, and `azure-openai-responses`; other APIs ignore them.
139
+
101
140
  Compatibility settings should describe verified differences in the endpoint's request or response behavior. Do not enable them based only on an endpoint advertising OpenAI or Anthropic compatibility.
102
141
 
142
+ ## Use classifier models
143
+
144
+ Classifier models do not chat. They answer typed questions about JSON state: pick one of several choices, answer yes or no, or give a score, each with probabilities. Pi includes TypeSafe's Jev model from these providers, Cloudflare's Clef and Clef Flash models from Workers AI, and OpenAI's GPT-6 Luna through the [Decisions API](https://developers.openai.com/api/docs/guides/decisions):
145
+
146
+ | Provider | Model IDs | Authentication |
147
+ |---|---|---|
148
+ | `typesafe` | `jev-latest` | `TYPESAFE_API_KEY` |
149
+ | `openrouter` | `typesafe/jev-1.13`, `~typesafe/jev-latest` | `OPENROUTER_API_KEY` or `/login` |
150
+ | `cloudflare-workers-ai` | `typesafe/jev`, `@cf/cloudflare/clef`, `@cf/cloudflare/clef-flash` | `CLOUDFLARE_API_KEY` and `CLOUDFLARE_ACCOUNT_ID` |
151
+ | `vercel-ai-gateway` | `typesafe-ai/jev` | `AI_GATEWAY_API_KEY` |
152
+ | `opencode` | `jev-1.13`, `jev-1.13-free` | `OPENCODE_API_KEY` |
153
+ | `openai` | `gpt-6-luna` | `OPENAI_API_KEY` |
154
+
155
+ Chat models on a [llama.cpp router](llama-cpp.md#classification) are also listed as classifier models.
156
+
157
+ OpenAI's Decisions API needs an API key. Sign in with ChatGPT credentials do not work with it, so `gpt-6-luna` is not listed as available while `openai` is logged in through `/login`, even when `OPENAI_API_KEY` is set; log out of `openai` to use the key. GPT-6 Luna also judges images passed in `images` (see [Codemode](codemode.md#classify)); other classifier models return an error for them. The API rejects inputs above 922K tokens, but requests that run longer than about five seconds, currently above roughly 600K input tokens, fail with a gateway timeout.
158
+
159
+ Classifier models do not appear in `/model`. The model reaches them through the [`codemode`](cli.md#enable-codemode) tool, which is off unless an MCP server turned it on. Enable it with `"defaultTools": ["+codemode"]` in [settings](settings.md#tools). Scripts then list classifier models with `models.getAvailableOfType("classifier")` and call `models.classify(model, { state, questions })`:
160
+
161
+ ```js
162
+ const jev = await models.getModelOfType("classifier", "typesafe", "jev-latest");
163
+ const result = await models.classify(jev, {
164
+ state: { message: "The change works, thanks." },
165
+ questions: {
166
+ approved: {
167
+ type: "bool",
168
+ instructions: "Does the user approve of the result?",
169
+ criteria: { true: "Approval", false: "No approval" },
170
+ },
171
+ },
172
+ });
173
+ return result.answers;
174
+ ```
175
+
176
+ [Codemode](codemode.md#classify) describes the question and answer types.
177
+
178
+ When the service reports token counts, as all System One services do, `result.usage` carries them with their cost. Pi adds the usage of a script's classifier calls to the `codemode` tool result, so it counts toward the session cost in the footer and `/session`. The cost uses the model's catalog price; models without one, such as TypeSafe's direct `jev-latest`, report tokens at no cost.
179
+
180
+ Extensions call classifiers through `ctx.modelRegistry.classify()`, without codemode. [Virtual models](virtual-models.md#route-requests) can use them to route requests; see the `jev-router.ts` example.
181
+
182
+ ## Use image models
183
+
184
+ Image models generate images from a prompt and optional input images. Pi lists OpenRouter's image models, such as `google/gemini-2.5-flash-image` and `black-forest-labs/flux.2-pro`, under the `openrouter` provider; they use the same `OPENROUTER_API_KEY` or `/login` credential as its chat models.
185
+
186
+ Like classifier models, image models do not appear in `/model`; the model reaches them through the [`codemode`](cli.md#enable-codemode) tool. Scripts list them with `models.getAvailableOfType("image")` and call `models.generateImages(model, { input })`. The result's `output` holds base64 image blocks, which `image()` attaches to the `codemode` result so the model sees them:
187
+
188
+ ```js
189
+ const painter = await models.getModelOfType("image", "openrouter", "google/gemini-2.5-flash-image");
190
+ const result = await models.generateImages(painter, {
191
+ input: [{ type: "text", text: "A red fox in the snow, watercolor" }],
192
+ });
193
+ if (result.stopReason !== "stop") return result.errorMessage;
194
+ for (const block of result.output) if (block.type === "image") image(block);
195
+ ```
196
+
197
+ `input` can also contain `{ type: "image", data, mimeType }` blocks to edit or use as references. Pi adds the usage of a script's image calls to the `codemode` tool result, like classifier calls. Generated images are not saved to disk. [Codemode](codemode.md#generate-images) describes the full API.
198
+
199
+ Extensions generate images through `ctx.modelRegistry.generateImages()`, without codemode.
200
+
103
201
  ## Add a custom provider
104
202
 
105
203
  Use an extension when the provider needs custom streaming, model discovery, or authentication behavior. See [Custom Providers](custom-provider.md) for the extension workflow.
@@ -0,0 +1,96 @@
1
+ # Run Pi with NVIDIA RTX and llama.cpp
2
+
3
+ [NVIDIA Local AI Inference Recipes](https://nvidia.github.io/local-ai-inference-recipes/index.html) provides llama.cpp settings tuned for specific NVIDIA hardware and models. Each recipe gives a single-model `llama-server` command. Pi works with the llama.cpp router, which can serve and manage several models, so this guide converts the recipe command into a router preset.
4
+
5
+ The examples below use Windows PowerShell. See [Local Models with llama.cpp](llama-cpp.md) for Pi's complete router and model-management reference.
6
+
7
+ ## Before you begin
8
+
9
+ 1. Open the [recipe catalog](https://nvidia.github.io/local-ai-inference-recipes/index.html), select your hardware, operating system, and model, then choose **llama.cpp**. Check the prerequisites and memory requirements. Keep the recipe's launch command for the conversion below.
10
+ 2. Install llama.cpp with the recipe's setup instructions. The recipe's settings depend on its build, for example CUDA support or speculative decoding options.
11
+ 3. Run `llama-server --help` and check that it lists `--models-preset`. Without it, the build cannot load the recipe as a router preset. Use a newer build that still meets the recipe's requirements.
12
+ 4. Install Pi with the [Quickstart](quickstart.md). On native Windows, also see [Run Pi on Windows](windows.md).
13
+
14
+ ## Convert the recipe to a preset
15
+
16
+ A preset lists the settings for one or more models. Each section name becomes the model ID shown in Pi. Save the preset next to `llama-server`, or pass its full path when starting the router.
17
+
18
+ Convert each option from the recipe command into one preset line:
19
+
20
+ - Remove the leading dashes: `--ctx-size 65536` becomes `ctx-size = 65536`.
21
+ - Write options without a value as `true`: `--jinja` becomes `jinja = true`.
22
+ - Remove quotes and PowerShell line-continuation backticks around values.
23
+ - Leave out `--host` and `--port`. They belong on the router command line.
24
+ - Add `load-on-startup = true` so the router loads the model when it starts.
25
+ - Replace short model-file options with their long preset keys:
26
+
27
+ | Recipe option | Preset key |
28
+ |---|---|
29
+ | `-hf` | `hf-repo` |
30
+ | `-hff` | `hf-file` |
31
+ | `-hfrd` | `hf-repo-draft` |
32
+ | `--spec-draft-model` | `spec-draft-model` |
33
+
34
+ For example, this recipe command:
35
+
36
+ ```powershell
37
+ llama-server.exe -hf "unsloth/Qwen3.8-27B-GGUF" `
38
+ -hff "Qwen3.8-27B-UD-Q4_K_M.gguf" `
39
+ -hfrd "z-lab/Qwen3.8-27B-DFlash2-GGUF" `
40
+ --spec-draft-model "Qwen3.8-27B-DFlash2-Q4_K_M.gguf" `
41
+ --no-mmproj `
42
+ --host 127.0.0.1 `
43
+ --port 9931 `
44
+ --batch-size 4096 `
45
+ --ubatch-size 1024 `
46
+ --ctx-size 65536 `
47
+ --parallel 1 `
48
+ -ngl 999 `
49
+ --jinja `
50
+ --chat-template-kwargs '{"preserve_thinking":true}' `
51
+ --spec-type draft-dflash `
52
+ --spec-draft-n-max 7 `
53
+ --spec-draft-backend-sampling
54
+ ```
55
+
56
+ becomes `qwen3.8-27b.ini`:
57
+
58
+ ```ini
59
+ version = 1
60
+
61
+ [qwen3.8-27b]
62
+ load-on-startup = true
63
+ hf-repo = unsloth/Qwen3.8-27B-GGUF
64
+ hf-file = Qwen3.8-27B-UD-Q4_K_M.gguf
65
+ hf-repo-draft = z-lab/Qwen3.8-27B-DFlash2-GGUF
66
+ spec-draft-model = Qwen3.8-27B-DFlash2-Q4_K_M.gguf
67
+ no-mmproj = true
68
+ batch-size = 4096
69
+ ubatch-size = 1024
70
+ ctx-size = 65536
71
+ parallel = 1
72
+ ngl = 999
73
+ jinja = true
74
+ chat-template-kwargs = {"preserve_thinking":true}
75
+ spec-type = draft-dflash
76
+ spec-draft-n-max = 7
77
+ spec-draft-backend-sampling = true
78
+ ```
79
+
80
+ ## Start the router
81
+
82
+ Open PowerShell in the llama.cpp folder and run:
83
+
84
+ ```powershell
85
+ .\llama-server.exe --models-preset qwen3.8-27b.ini --host 127.0.0.1 --port 8080
86
+ ```
87
+
88
+ If the recipe requires a Hugging Face token, set `$env:HF_TOKEN` in the same PowerShell window before starting the router. On its first start, the router downloads the model files.
89
+
90
+ Use the [router health checks](llama-cpp.md#troubleshooting) to confirm that the server is ready. In Windows PowerShell, use `curl.exe` rather than `curl`, which PowerShell maps to a different command. The model is ready when `/models` lists `qwen3.8-27b` with the status `loaded`.
91
+
92
+ ## Use the model in Pi
93
+
94
+ Follow [Configure Pi](llama-cpp.md#configure-pi) and connect to `http://127.0.0.1:8080`. The preset section name is the model ID, so select `qwen3.8-27b` in `/model` for this example.
95
+
96
+ NVIDIA recipe memory settings assume that only the selected model uses the GPU. If `/llama` shows other loaded models, unload them before using the recipe model.
package/docs/packages.md CHANGED
@@ -118,7 +118,7 @@ For each resource type:
118
118
 
119
119
  Filters narrow the package manifest. They do not expose resources that the package itself did not declare.
120
120
 
121
- Run `pi config` to enable or disable discovered resources. It starts with personal configuration; press Tab to switch scope, or run `pi config --local` to start with project overrides.
121
+ Run `pi config` to enable or disable discovered resources and pi's built-in extensions. It starts with personal configuration; press Tab to switch scope, or run `pi config --local` to start with project overrides.
122
122
 
123
123
  ## Understand scope and identity
124
124
 
package/docs/providers.md CHANGED
@@ -1,4 +1,4 @@
1
- # Provider Authentication
1
+ # Providers
2
2
 
3
3
  Most hosted providers support one or both of these authentication methods:
4
4
 
@@ -17,8 +17,6 @@ Run `/logout` and select a provider to remove its stored credential. This does n
17
17
 
18
18
  `auth.json` can contain API keys and OAuth tokens. Keep it private and do not commit it.
19
19
 
20
- Radius authentication uses its gateway catalog and caches refreshed model metadata for later offline startup. A custom Radius gateway configured in `models.json` uses its own catalog rather than inheriting the public `radius.pi.dev` catalog.
21
-
22
20
  ## Use an API key from the environment
23
21
 
24
22
  Environment variables are useful in CI and anywhere Pi should not store the key. Set the variable before starting Pi:
@@ -28,7 +26,7 @@ export ANTHROPIC_API_KEY=sk-ant-...
28
26
  pi
29
27
  ```
30
28
 
31
- This table covers providers with a single primary API-key variable. Providers that need additional configuration or support ambient credentials are covered under [Cloud providers](#cloud-providers).
29
+ This table covers providers with a single primary API-key variable. Providers that need additional configuration or support ambient credentials are covered under [Provider Specific Config](#provider-specific-config).
32
30
 
33
31
  | Provider | Environment variable |
34
32
  |---|---|
@@ -49,6 +47,7 @@ This table covers providers with a single primary API-key variable. Providers th
49
47
  | ZAI Coding Plan (China) | `ZAI_CODING_CN_API_KEY` |
50
48
  | OpenCode Zen and Go | `OPENCODE_API_KEY` |
51
49
  | Radius | `RADIUS_API_KEY` |
50
+ | TypeSafe ([classifier models](models.md#use-classifier-models)) | `TYPESAFE_API_KEY` |
52
51
  | Hugging Face | `HF_TOKEN` |
53
52
  | Fireworks | `FIREWORKS_API_KEY` |
54
53
  | Together AI | `TOGETHER_API_KEY` |
@@ -67,6 +66,8 @@ This table covers providers with a single primary API-key variable. Providers th
67
66
 
68
67
  Anthropic also recognizes `ANTHROPIC_OAUTH_TOKEN` as an API credential and `ANTHROPIC_AUTH_TOKEN` as bearer authentication.
69
68
 
69
+ With no key or token set, Anthropic uses workload identity federation when `ANTHROPIC_FEDERATION_RULE_ID`, `ANTHROPIC_ORGANIZATION_ID` and `ANTHROPIC_IDENTITY_TOKEN_FILE` are set: the Anthropic SDK exchanges the identity token for a short-lived access token and refreshes it itself (re-reading the identity token file, so keep that file fresh for long sessions). `ANTHROPIC_SERVICE_ACCOUNT_ID` and `ANTHROPIC_WORKSPACE_ID` are passed through when set.
70
+
70
71
  ## Load an API key from a command
71
72
 
72
73
  To use a secret manager without writing the resolved key to disk, set a provider's `key` in `auth.json` to a command prefixed with `!`:
@@ -82,9 +83,9 @@ To use a secret manager without writing the resolved key to disk, set a provider
82
83
 
83
84
  Pi runs the command when the key is first needed and caches its standard output for the process lifetime. Empty output, a timeout, or a nonzero exit leaves the key unresolved until Pi restarts.
84
85
 
85
- ## Cloud Providers
86
+ ## Provider Specific Config
86
87
 
87
- The providers below need additional settings or can use credentials supplied by their cloud platform.
88
+ The providers below have additional setup, need additional settings, or can use credentials supplied by their platform.
88
89
 
89
90
  A stored API-key credential can include an `env` object. Its values take priority over the process environment for that provider:
90
91
 
@@ -100,8 +101,44 @@ A stored API-key credential can include an `env` object. Its values take priorit
100
101
  }
101
102
  ```
102
103
 
104
+ ### Radius
105
+
106
+ Radius is a service crafted for Pi by the builders of Pi, Earendil Works. It provides a customizable AI gateway with organization-level controls and analytics built in, and artifacts for sharing what you create with Pi.
107
+
108
+ To get started, run `/login radius` in Pi. This adds Radius as a provider, and its models appear in `/model` like any other provider's.
109
+
110
+ Radius also has an MCP server, so Pi can manage Radius for you.
111
+
112
+ Radius is currently in early alpha and evolving quickly. See [radius.earendil.com](https://radius.earendil.com) for more.
113
+
114
+ Radius authentication uses its gateway catalog and caches refreshed model metadata for later offline startup. A custom Radius gateway configured in `models.json` uses its own catalog rather than inheriting the public `radius.pi.dev` catalog.
115
+
116
+ ### OpenRouter
117
+
118
+ Authenticate with `/login openrouter` or `OPENROUTER_API_KEY`.
119
+
120
+ With a key, Pi lists only the OpenRouter chat models that key may use, with the key's context size, max output, and prices. These come from OpenRouter's `/models/user` endpoint and reflect guardrails and provider restrictions set in OpenRouter. Image and classifier models are not filtered.
121
+
122
+ Pi refreshes the list in the background at startup in interactive mode, when `/model` opens, after `/login`, and on `pi update --models`. The last list is saved and used offline and in `pi -p` and RPC mode. After switching keys outside `/login`, the previous key's list stays until the next refresh.
123
+
124
+ Regional endpoints filter models to their region. To use one, set the base URL in [`models.json`](models.md#configure-a-compatible-endpoint):
125
+
126
+ ```json
127
+ {
128
+ "providers": {
129
+ "openrouter": { "baseUrl": "https://us.openrouter.ai/api/v1" }
130
+ }
131
+ }
132
+ ```
133
+
134
+ If the base URL rejects the key at `/models/user` or does not have that endpoint, for example a proxy configured as the OpenRouter base URL, Pi lists every OpenRouter model.
135
+
103
136
  ### Azure OpenAI
104
137
 
138
+ The provider ID is `azure` (formerly `azure-openai-responses`). Use it as the key in `auth.json`, `models.json`, and `settings.json`, and in model references such as `--model azure/gpt-5.4`.
139
+
140
+ The `azure` provider serves OpenAI models through the Responses API and Microsoft Foundry models through Chat Completions, such as `azure/deepseek-v4-pro`.
141
+
105
142
  Set an API key plus either a base URL or resource name:
106
143
 
107
144
  ```bash
@@ -113,6 +150,29 @@ export AZURE_OPENAI_RESOURCE_NAME=your-resource
113
150
 
114
151
  Resource root URLs under `ai.azure.com`, `cognitiveservices.azure.com`, and `openai.azure.com` are normalized to the OpenAI API path.
115
152
 
153
+ Pi sends the model ID as the deployment name. If a deployment has a different name, map it with `AZURE_OPENAI_DEPLOYMENT_NAME_MAP`:
154
+
155
+ ```bash
156
+ export AZURE_OPENAI_DEPLOYMENT_NAME_MAP=gpt-5.4=my-gpt-deployment,deepseek-v4-pro=my-deepseek
157
+ ```
158
+
159
+ `AZURE_OPENAI_API_VERSION` overrides the API version for OpenAI models (default `v1`).
160
+
161
+ To use a Foundry model that Pi does not include, add it under `azure` in [`models.json`](models.md#configure-a-compatible-endpoint) with `api: "openai-completions"`. Custom models require a `baseUrl`; `AZURE_OPENAI_BASE_URL` and `AZURE_OPENAI_RESOURCE_NAME` take priority over it when set:
162
+
163
+ ```json
164
+ {
165
+ "providers": {
166
+ "azure": {
167
+ "baseUrl": "https://your-resource.services.ai.azure.com",
168
+ "models": [
169
+ { "id": "your-deployment", "api": "openai-completions" }
170
+ ]
171
+ }
172
+ }
173
+ }
174
+ ```
175
+
116
176
  ### Amazon Bedrock
117
177
 
118
178
  Bedrock can use a bearer token or an ambient AWS credential source:
@@ -12,7 +12,7 @@ On macOS or Linux, you can use the installer:
12
12
  curl -fsSL https://pi.dev/install.sh | sh
13
13
  ```
14
14
 
15
- Alternatively, install Pi from npm. This requires Node.js 22.19 or newer:
15
+ The installer pins all dependencies and updates Pi with `pi update`. Alternatively, install Pi from npm, which does not pin transitive dependencies. This requires Node.js 22.19 or newer:
16
16
 
17
17
  ```bash
18
18
  npm install -g --ignore-scripts @earendil-works/pi-coding-agent
@@ -20,6 +20,14 @@ npm install -g --ignore-scripts @earendil-works/pi-coding-agent
20
20
 
21
21
  Pi does not require dependency lifecycle scripts for a normal npm installation.
22
22
 
23
+ With Nix on macOS or Linux, install the latest release from Pi's flake. Nix builds Pi from source:
24
+
25
+ ```bash
26
+ nix profile add github:earendil-works/pi/stable
27
+ ```
28
+
29
+ Older Nix versions use `nix profile install` instead. Update with `nix profile upgrade pi`; `pi update` cannot update a Nix installation. To pin a release, use a tag such as `github:earendil-works/pi/v1.0.0`.
30
+
23
31
  Verify the installation:
24
32
 
25
33
  ```bash
@@ -119,4 +127,10 @@ If you used the installer, run it again and choose **Uninstall Pi**:
119
127
  curl -fsSL https://pi.dev/install.sh | sh
120
128
  ```
121
129
 
122
- Neither method removes configuration, credentials, sessions, or installed Pi packages from `~/.pi/agent/`.
130
+ If you installed Pi with Nix, run:
131
+
132
+ ```bash
133
+ nix profile remove pi
134
+ ```
135
+
136
+ None of these methods removes configuration, credentials, sessions, or installed Pi packages from `~/.pi/agent/`.
@@ -34,9 +34,11 @@ If the agent is streaming and no `streamingBehavior` is specified, the command r
34
34
 
35
35
  Response:
36
36
  ```json
37
- {"id": "req-1", "type": "response", "command": "prompt", "success": true}
37
+ {"id": "req-1", "type": "response", "command": "prompt", "success": true, "data": {"disposition": "started"}}
38
38
  ```
39
39
 
40
+ `data.disposition` is `"handled"` if an extension command or input handler consumed the prompt, `"queued"` if Pi queued it during a run, or `"started"` if Pi accepted it to start a run. This describes the submitted prompt, not independent work started by an extension or a guarantee of completion.
41
+
40
42
  `success: true` means the prompt was accepted, queued, or handled immediately. `success: false` means the prompt was rejected before acceptance. Failures after acceptance are reported through the normal event and message stream, not as a second `response` for the same request id.
41
43
 
42
44
  The `images` field is optional. Each image uses `ImageContent` format: `{"type": "image", "data": "base64-encoded-data", "mimeType": "image/png"}`.
@@ -58,9 +60,11 @@ The `images` field is optional. Each image uses `ImageContent` format (same as `
58
60
 
59
61
  Response:
60
62
  ```json
61
- {"type": "response", "command": "steer", "success": true}
63
+ {"type": "response", "command": "steer", "success": true, "data": {"disposition": "queued"}}
62
64
  ```
63
65
 
66
+ `data.disposition` is `"handled"` if an input handler consumed this steer, or `"queued"` if Pi queued it (including after a handler transformed it). It does not guarantee this message remains queued.
67
+
64
68
  See [set_steering_mode](#set_steering_mode) for controlling how steering messages are processed.
65
69
 
66
70
  ### follow_up
@@ -80,9 +84,11 @@ The `images` field is optional. Each image uses `ImageContent` format (same as `
80
84
 
81
85
  Response:
82
86
  ```json
83
- {"type": "response", "command": "follow_up", "success": true}
87
+ {"type": "response", "command": "follow_up", "success": true, "data": {"disposition": "queued"}}
84
88
  ```
85
89
 
90
+ `data.disposition` has the same `"handled"` or `"queued"` meaning as for `steer`, applied to this follow-up.
91
+
86
92
  See [set_follow_up_mode](#set_follow_up_mode) for controlling how follow-up messages are processed.
87
93
 
88
94
  ### abort
package/docs/rpc.md CHANGED
@@ -61,9 +61,11 @@ A successful `prompt` response means the prompt was accepted, queued, or handled
61
61
 
62
62
  ```json
63
63
  {"id":"req-2","type":"prompt","message":"Review this repository"}
64
- {"id":"req-2","type":"response","command":"prompt","success":true}
64
+ {"id":"req-2","type":"response","command":"prompt","success":true,"data":{"disposition":"started"}}
65
65
  ```
66
66
 
67
+ `data.disposition` reports what happened to the prompt. If it is `"handled"`, no run started for this prompt, so don't wait for `agent_settled`. See [RPC Commands](rpc-commands.md#prompt) for all values.
68
+
67
69
  Continue consuming [events](json.md) after that response. `agent_end` marks the end of one low-level agent run, but retries, overflow recovery, compaction, steering, or follow-up work can still follow. Wait for `agent_settled` when the client needs to know Pi will not continue automatically.
68
70
 
69
71
  Subscribe before sending a prompt to avoid missing a fast completion. `RpcClient.promptAndWait()` does this internally. If using separate `RpcClient` calls, install the event listener before `prompt()` and call `waitForIdle()` only while a run is active.
package/docs/sdk.md CHANGED
@@ -65,7 +65,7 @@ After a runtime replacement, subscriptions belong to the old `AgentSession` and
65
65
 
66
66
  A prompt sent while the session is already streaming must specify whether it should steer the current run or follow it. Calling `prompt()` without that choice rejects rather than guessing.
67
67
 
68
- A steering message enters after the current assistant turn and its tool calls. A follow-up enters after the current run finishes its pending work. `steer()` and `followUp()` expose those behaviors directly.
68
+ A steering message enters after the current assistant turn and its tool calls. A follow-up enters after the current run finishes its pending work. `steer()` and `followUp()` expose those behaviors directly and return `"queued"` if the input was queued (including after an extension transformed it), or `"handled"` if an extension consumed it.
69
69
 
70
70
  `abort()` stops the active operation and waits for the session to become idle. `waitForIdle()` waits without aborting it.
71
71
 
@@ -109,7 +109,11 @@ Use `DefaultResourceLoader` when you want standard discovery with selected overr
109
109
 
110
110
  <a id="inlineextension"></a>
111
111
 
112
- Inline extension factories can be supplied through `DefaultResourceLoader`. Give one an `InlineExtension` name only when it needs a stable name in diagnostics and startup output.
112
+ Inline extension factories can be supplied through `DefaultResourceLoader`. Give one an `InlineExtension` name only when it needs a stable name in diagnostics and startup output. A named inline extension with `replaceable: true` is left out when another extension registers a tool, command, or flag with a name it registers during loading, instead of both loading with a conflict. The CLI's built-in codemode, tool search, and MCP extensions are replaceable. A named entry with `builtin: true` is not an inline extension: it supplies the code of the `builtin:<name>` extension, which loads like a configured extension file. It loads by default, is listed in `pi config`, and is disabled by `-builtin:<name>` in the `extensions` setting or by `noExtensions`; `additionalExtensionPaths: ["builtin:<name>"]` loads it explicitly. It loads after project trust is resolved, so it cannot handle `project_trust`. The CLI's built-in extensions use it.
113
+
114
+ <a id="codemode-mcp"></a>
115
+
116
+ The CLI loads `codemode`, `tool_search`, and MCP as built-in extensions. SDK sessions do not; add `createCodemodeExtension()`, `createToolSearchExtension()`, and `createMcpExtension()` to the `extensionFactories` of `DefaultResourceLoader`. `codemode` and `tool_search` are registered inactive: enable them through the `defaultTools` setting (`["+codemode", "+tool_search"]` keeps the other default tools), or let the MCP extension activate them: `codemode` for servers with `codemode` exposure, `tool_search` for servers with `deferred` exposure. The MCP extension connects its servers on `session_start`, so call `session.bindExtensions()`. See [Codemode and MCP](../examples/sdk/14-codemode-mcp.ts).
113
117
 
114
118
  See the focused examples for [models](../examples/sdk/02-custom-model.ts), [tools](../examples/sdk/05-tools.ts), [extensions](../examples/sdk/06-extensions.ts), and [full control](../examples/sdk/12-full-control.ts).
115
119
 
@@ -130,12 +134,13 @@ See the focused examples for [models](../examples/sdk/02-custom-model.ts), [tool
130
134
  | [Sessions](../examples/sdk/11-sessions.ts) | Control session persistence and restoration |
131
135
  | [Full control](../examples/sdk/12-full-control.ts) | Replace default discovery and state services |
132
136
  | [Session runtime](../examples/sdk/13-session-runtime.ts) | Replace the active session safely |
137
+ | [Codemode and MCP](../examples/sdk/14-codemode-mcp.ts) | Add the `codemode`, `tool_search`, and MCP extensions |
133
138
 
134
139
  <a id="exports"></a>
135
140
 
136
141
  ## Resources
137
142
 
138
- - [Choose a Model](models.md) covers model selection and compatible endpoints; [Provider Authentication](providers.md) covers credentials and cloud-provider setup.
143
+ - [Choose a Model](models.md) covers model selection and compatible endpoints; [Providers](providers.md) covers credentials and provider-specific setup.
139
144
  - [Configuration](configuration.md) explains normal discovery and settings; [Settings](settings.md) lists every setting.
140
145
  - [Sessions and Context](sessions.md) explains session behavior; [Session Format](session-format.md) defines persisted entries; [Message Types](message-types.md) defines shared transcript values.
141
146
  - [Extensions](extensions.md), [Skills](skills.md), and [Prompt Templates](prompt-templates.md) document resources supplied through a `ResourceLoader`.
package/docs/security.md CHANGED
@@ -37,6 +37,7 @@ Project trust does not limit what tool calls can access or affect. After Pi star
37
37
  Pi requires a project-trust decision when it finds any of these resources from the current working directory:
38
38
 
39
39
  - `.pi/settings.json`
40
+ - `.pi/mcp.json`
40
41
  - `.pi/extensions`, `.pi/skills`, `.pi/prompts`, or `.pi/themes`
41
42
  - `.pi/SYSTEM.md` or `.pi/APPEND_SYSTEM.md`
42
43
  - project `.agents/skills` in the current directory or an ancestor directory
@@ -46,6 +47,7 @@ A bare `.pi` directory does not require project trust.
46
47
  Granting project trust allows Pi to load:
47
48
 
48
49
  - project settings
50
+ - project MCP servers from `.pi/mcp.json`
49
51
  - extensions, skills, prompt templates, themes, and system-prompt files under `.pi`
50
52
  - missing packages configured through project settings
51
53
  - project-local and project-package extensions
@@ -92,9 +92,11 @@ Sessions created before system messages existed have no leading system message;
92
92
  {"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}}
93
93
  ```
94
94
 
95
+ Assistant messages name the model that produced them. Newer messages also record `thinkingLevel`, the Pi thinking level requested for that response.
96
+
95
97
  ### ModelChangeEntry
96
98
 
97
- Emitted when the user switches models mid-session.
99
+ Emitted when the user switches models mid-session. The latest entry is the selected model, which may be a [virtual model](virtual-models.md); assistant messages then name the physical model that answered.
98
100
 
99
101
  ```json
100
102
  {"type":"model_change","id":"d4e5f6g7","parentId":"c3d4e5f6","timestamp":"2024-12-03T14:05:00.000Z","provider":"openai","modelId":"gpt-4o"}
@@ -169,6 +171,8 @@ Extension state persistence. Does NOT participate in LLM context.
169
171
 
170
172
  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.
171
173
 
174
+ Pi stores [virtual model](virtual-models.md) router state as custom entries with `customType` `pi.virtual-model-state` and `data` `{ provider, modelId, state }`.
175
+
172
176
  ### CustomMessageEntry
173
177
 
174
178
  Extension-injected messages that DO participate in LLM context.
package/docs/sessions.md CHANGED
@@ -55,7 +55,7 @@ Use `--session` when you already know the session path or ID. Use `--fork` to cr
55
55
 
56
56
  ## Export or share a session
57
57
 
58
- Use `/export` to write the current session as HTML or JSONL. Use `/share` to upload it and get a viewer link. Pi uses a Radius artifact when Radius authentication is configured; otherwise, it uses a private GitHub gist.
58
+ Use `/export` to write the current session as HTML or JSONL. Use `/share` to upload it and get a viewer link. By default, Pi uses a Radius artifact when Radius authentication is configured; otherwise, it uses a private GitHub gist. Set [`sessionShareDestination`](settings.md#sessions-and-context) to `gist` or `radius` to force one destination.
59
59
 
60
60
  Review exported or shared sessions first. They can contain prompts, model responses, tool arguments, command output, file contents, and extension messages.
61
61
 
package/docs/settings.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  This reference lists user-configurable settings, their types, defaults, and purposes. Project settings override agent-directory settings. Resource lists are combined. See [Configuration](configuration.md) for file locations and trust behavior.
4
4
 
5
+ Add `"$schema": "https://pi.dev/schemas/settings.schema.json"` to `settings.json` for editor validation and completion.
6
+
5
7
  ## Model and thinking
6
8
 
7
9
  <a id="model-cycling"></a>
@@ -37,22 +39,39 @@ See [Choose a Model](models.md) for model selection and thinking controls.
37
39
 
38
40
  | Setting | Type | Default | Description |
39
41
  |---|---|---|---|
40
- | `defaultTools` | `string[]` | `read`, `bash`, `edit`, `write` | Built-in tools enabled at startup. An empty array disables all built-in tools but not extension or SDK tools. |
42
+ | `defaultTools` | `string[]` | `read`, `bash`, `edit`, `write` | Tools enabled at startup. Plain names replace the defaults; `+name` adds a tool and `-name` removes one. An empty array disables all built-in tools but not extension or SDK tools. |
43
+ | `codemode.mode` | `"on"` \| `"only"` | `"on"` | How the `codemode` tool presents tools while it is active. `on`: declared tools get a note on calling them from scripts appended to their description, and `codemode` lists only tools that are not declared. `only`: `codemode` lists every tool scripts can call, and active built-in and extension tools are hidden from the model, so it reaches them through `codemode`. |
44
+ | `codemode.inlineBudget` | number | `3000` | Estimated tokens (characters / 4) the `codemode` tool's description may spend on tool declarations. Tools that do not fit are left out and found with `searchTools()`. `0` lists only namespaces. |
45
+
46
+ Available built-in tools are `read`, `bash`, `powershell`, `edit`, `write`, `grep`, `find`, and `ls`. `defaultTools` can also name `codemode` and `tool_search`, which built-in extensions register inactive, and other extension tools registered inactive.
47
+
48
+ A list of only `+name` and `-name` entries changes the inherited selection instead of replacing it. For example, this enables `codemode` next to the default tools:
49
+
50
+ ```json
51
+ {
52
+ "defaultTools": ["+codemode"]
53
+ }
54
+ ```
41
55
 
42
- Available built-in tools are `read`, `bash`, `powershell`, `edit`, `write`, `grep`, `find`, and `ls`. CLI tool options override this setting for one invocation. See [Command Line](cli.md#tools).
56
+ This replaces `bash` with `powershell` and enables `grep`: `["-bash", "+powershell", "+grep"]`. Project settings apply on top of user settings: a project list with only `+name` and `-name` entries changes the user's selection, and a project list with a plain name replaces it. In one list, plain names form the selection, and `+name` and `-name` then apply in order.
57
+
58
+ `/reload` enables tools newly added to `defaultTools`. It does not disable tools removed from it or re-enable unchanged tools you turned off. `--tools` with plain names, `--no-tools`, and `--no-builtin-tools` override `defaultTools`, also on reload.
59
+
60
+ CLI tool options override this setting for one invocation. `--tools` with only `+name` and `-name` entries changes the resolved `defaultTools` selection instead, for example `pi --tools +codemode`. On `/reload`, these entries apply to the reloaded setting too, so a tool removed with `-name` stays removed. See [Command Line](cli.md#tools).
43
61
 
44
62
  ## Sessions and context
45
63
 
46
64
  | Setting | Type | Default | Description |
47
65
  |---|---|---|---|
48
66
  | `sessionDir` | string | Agent session directory | Session storage directory. Relative paths resolve from the working directory. `PI_CODING_AGENT_SESSION_DIR` and `--session-dir` override this setting. |
67
+ | `sessionShareDestination` | `"auto" \| "gist" \| "radius"` | `"auto"` | Destination used by `/share`. `auto` uses Radius when authenticated and otherwise creates a GitHub gist. `gist` always uses a gist. `radius` requires Radius authentication and never falls back to a gist. |
49
68
 
50
69
  ### Compaction
51
70
 
52
71
  | Setting | Type | Default | Description |
53
72
  |---|---|---|---|
54
73
  | `compaction.enabled` | boolean | `true` | Enable automatic compaction. |
55
- | `compaction.reserveTokens` | number | `16384` | Tokens reserved for the model response. |
74
+ | `compaction.reserveTokens` | number | `16384` | Free context tokens below which automatic compaction starts. |
56
75
  | `compaction.keepRecentTokens` | number | `20000` | Recent tokens retained without summarization. |
57
76
  | `compaction.modelOverrides` | object | None | Per-model token settings keyed by exact `provider/modelId`. |
58
77
 
@@ -73,16 +92,17 @@ See [Compaction Reference](compaction.md) for trigger, summarization, and valida
73
92
 
74
93
  | Setting | Type | Default | Description |
75
94
  |---|---|---|---|
76
- | `theme` | string | Detected | Built-in or custom theme name. |
77
- | `quietStartup` | boolean | `false` | Hide the startup header. |
78
- | `tuiMode` | `"regular" \| "fullscreen"` | `"regular"` | Interactive terminal UI mode. |
95
+ | `theme` | string | `"system"` | Built-in or custom theme name. `system` derives colors from the terminal theme. |
96
+ | `quietStartup` | boolean \| `"header"` | `false` | `true` hides the startup header and loaded-resource listing. `"header"` keeps the header (version and key hints) but hides the model scope line and loaded-resource listing. |
97
+ | `tuiMode` | `"regular" \| "fullscreen"` | `"fullscreen"` | Interactive terminal UI mode. |
79
98
  | `fullscreenExitOutput` | `"transcript" \| "resume-hint"` | `"transcript"` | Output printed when fullscreen mode exits. |
80
99
  | `fullscreenScrollbar` | `"auto" \| "always" \| "hidden"` | `"auto"` | Fullscreen transcript scrollbar behavior. |
81
100
  | `fullscreenCopyOnSelect` | boolean | `true` | Copy selected text automatically in fullscreen mode. |
101
+ | `fullscreenWheelScrollLines` | `"auto"` \| number | `"auto"` | Lines per mouse-wheel event in fullscreen mode, from 1 to 100. `"auto"` moves one line per event in local macOS terminals, which already accelerate wheel and trackpad input; elsewhere, and over SSH, it speeds up fast wheel spins to at most 6 lines per event. Alt+wheel moves five times as far. |
82
102
  | `editorPaddingX` | number | `0` | Horizontal editor padding from 0 to 3 cells. |
83
- | `outputPad` | `0 \| 1` | `1` | Horizontal transcript padding. |
103
+ | `outputPad` | `0 \| 1` | `1` | Horizontal transcript padding for messages, tool output, `!` command output, and summary blocks. |
84
104
  | `autocompleteMaxVisible` | number | `5` | Visible autocomplete entries, from 3 to 20. |
85
- | `showHardwareCursor` | boolean | `false` | Show the terminal cursor while Pi positions it for input methods. |
105
+ | `showHardwareCursor` | boolean | `false` | Use the terminal cursor instead of Pi's drawn cursor. Pi still positions it for input methods. |
86
106
  | `terminal.showImages` | boolean | `true` | Display inline images when supported. |
87
107
  | `terminal.imageWidthCells` | number | `60` | Preferred inline image width in terminal cells. |
88
108
  | `terminal.clearOnShrink` | boolean | `false` | Clear empty rows when rendered content shrinks. |
@@ -140,6 +160,8 @@ Resource paths in user settings resolve from the agent directory. Paths in proje
140
160
 
141
161
  Resource arrays support glob exclusions with `!pattern`, exact inclusion with `+path`, and exact exclusion with `-path`. Pi loads resources listed in both user-level and project settings.
142
162
 
163
+ The built-in extensions are named `builtin:mcp`, `builtin:llama.cpp`, `builtin:codemode`, and `builtin:tool-search` in `extensions`. They load by default; `-builtin:mcp` disables one. A `+builtin:<name>` or `-builtin:<name>` entry in project settings overrides the user setting. `pi config` lists them under Built-in. `--no-extensions` disables them too, and `-e builtin:<name>` loads one explicitly.
164
+
143
165
  ## Updates, telemetry, and warnings
144
166
 
145
167
  | Setting | Type | Default | Description |