@introspection-ai/pi-recipes 0.1.0-beta.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.
- package/README.md +116 -0
- package/dist/child-agent.d.ts +40 -0
- package/dist/child-agent.js +235 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +479 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/pi-extension.d.ts +26 -0
- package/dist/pi-extension.js +809 -0
- package/dist/recipe-agent.d.ts +51 -0
- package/dist/recipe-agent.js +359 -0
- package/dist/recipe-dev.d.ts +30 -0
- package/dist/recipe-dev.js +180 -0
- package/dist/recipe-package.d.ts +38 -0
- package/dist/recipe-package.js +231 -0
- package/dist/recipe-publish.d.ts +30 -0
- package/dist/recipe-publish.js +192 -0
- package/dist/recipe-store.d.ts +66 -0
- package/dist/recipe-store.js +691 -0
- package/docs/pi-extension.md +413 -0
- package/docs/recipe-cli.md +529 -0
- package/docs/recipe-flow.md +148 -0
- package/package.json +92 -0
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
# Pi Recipe Extension
|
|
2
|
+
|
|
3
|
+
The Pi recipe extension resolves a recipe directory, selects a recipe agent, and
|
|
4
|
+
maps recipe resources into the live Pi session.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
Install the recipe tooling:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install -g @introspection-ai/pi-recipes
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`recipes install ...` automatically installs this companion extension into
|
|
15
|
+
Pi when it is missing. To set it up explicitly:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
recipes setup
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Manual Pi installation is still available:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pi install npm:@introspection-ai/pi-recipes
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
For a local clone:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pnpm install
|
|
31
|
+
pnpm build
|
|
32
|
+
pi install "$(pwd)"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Re-run `pnpm build` after changing extension source.
|
|
36
|
+
|
|
37
|
+
## Launch
|
|
38
|
+
|
|
39
|
+
Launch with a local recipe directory:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pi --recipe /path/to/recipe
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Launch with an installed recipe:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
recipes install github:owner/repo
|
|
49
|
+
pi --recipe owner/repo
|
|
50
|
+
pi --recipe recipe-name
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Select an explicit recipe agent:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pi --recipe recipe-name --agent reviewer
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Environment variable equivalents:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
PI_RECIPE_DIR=recipe-name pi
|
|
63
|
+
PI_RECIPE_DIR=recipe-name PI_AGENT_NAME=reviewer pi
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`--recipe` accepts:
|
|
67
|
+
|
|
68
|
+
- an existing local directory
|
|
69
|
+
- an installed short recipe name
|
|
70
|
+
- an installed scoped recipe name
|
|
71
|
+
|
|
72
|
+
The extension resolves installed recipes from the `recipes` store. Set
|
|
73
|
+
`PI_RECIPES_HOME` if Pi should use a non-default store.
|
|
74
|
+
|
|
75
|
+
## Launch Flow
|
|
76
|
+
|
|
77
|
+
On session startup, the extension:
|
|
78
|
+
|
|
79
|
+
1. Reads `--recipe` or `PI_RECIPE_DIR`.
|
|
80
|
+
2. Resolves the value as a local directory or installed recipe.
|
|
81
|
+
3. Loads the recipe manifest from `package.json`.
|
|
82
|
+
4. Selects the active recipe agent.
|
|
83
|
+
5. Loads declared recipe extensions.
|
|
84
|
+
6. Sets the Pi session name.
|
|
85
|
+
7. Sets the model and thinking level from the selected agent when specified.
|
|
86
|
+
8. Selects active tools from the selected agent.
|
|
87
|
+
9. Returns recipe resources for skills, prompts, and themes.
|
|
88
|
+
10. Composes the runtime system prompt from Pi defaults, `SYSTEM.md`, selected agent instructions, and recipe runtime context.
|
|
89
|
+
|
|
90
|
+
The current Pi working directory remains the user's project workspace. The
|
|
91
|
+
recipe directory is available in runtime context, but it does not become the
|
|
92
|
+
workspace.
|
|
93
|
+
|
|
94
|
+
## Manifest File
|
|
95
|
+
|
|
96
|
+
`package.json` is the recipe manifest. Top-level package fields tell Pi what
|
|
97
|
+
recipe this is:
|
|
98
|
+
|
|
99
|
+
- `name`, `version`, and `description`
|
|
100
|
+
|
|
101
|
+
The `pi` block tells Pi which recipe-owned files should be loaded:
|
|
102
|
+
|
|
103
|
+
- agent definition globs
|
|
104
|
+
- extension globs
|
|
105
|
+
- skill, prompt, and theme paths
|
|
106
|
+
|
|
107
|
+
The same file also carries normal Node package metadata for extension
|
|
108
|
+
dependencies. Add `dependencies`, `peerDependencies`, `packageManager`, and a
|
|
109
|
+
lockfile when TypeScript extensions under `extensions/` import npm packages.
|
|
110
|
+
|
|
111
|
+
Minimal example:
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"name": "my-recipe",
|
|
116
|
+
"version": "0.1.0",
|
|
117
|
+
"description": "A short description of what this recipe is for.",
|
|
118
|
+
"type": "module",
|
|
119
|
+
"pi": {
|
|
120
|
+
"agents": ["agents/*.yaml"]
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Agent Selection
|
|
126
|
+
|
|
127
|
+
Selection order:
|
|
128
|
+
|
|
129
|
+
1. `--agent` or `PI_AGENT_NAME`
|
|
130
|
+
2. `agents/agent.yaml`
|
|
131
|
+
3. the only available agent
|
|
132
|
+
|
|
133
|
+
If multiple agents exist and no default can be inferred, launch fails with a
|
|
134
|
+
clear error.
|
|
135
|
+
|
|
136
|
+
Agent files are YAML:
|
|
137
|
+
|
|
138
|
+
```yaml
|
|
139
|
+
name: agent
|
|
140
|
+
description: Main coordinator
|
|
141
|
+
model:
|
|
142
|
+
name: openai/gpt-5.4
|
|
143
|
+
thinking_level: medium
|
|
144
|
+
tools:
|
|
145
|
+
- read
|
|
146
|
+
- bash
|
|
147
|
+
skills:
|
|
148
|
+
- repo-index
|
|
149
|
+
subagents:
|
|
150
|
+
- explorer
|
|
151
|
+
system_instructions:
|
|
152
|
+
mode: append
|
|
153
|
+
content: |
|
|
154
|
+
Extra instructions for this agent.
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
A named variant is another agent that inherits from a base with `from:`:
|
|
158
|
+
|
|
159
|
+
```yaml
|
|
160
|
+
name: agent-opus
|
|
161
|
+
from: agent
|
|
162
|
+
model:
|
|
163
|
+
name: openrouter/anthropic/claude-opus-4.8
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Objects such as `model` and `extensions` merge by key. Arrays such as `tools`,
|
|
167
|
+
`skills`, and `subagents` replace the inherited array.
|
|
168
|
+
|
|
169
|
+
`system_instructions.mode` can be:
|
|
170
|
+
|
|
171
|
+
- `append`: append to the current prompt
|
|
172
|
+
- `replace`: replace the current prompt
|
|
173
|
+
|
|
174
|
+
## Session Prompt
|
|
175
|
+
|
|
176
|
+
The session prompt is assembled from:
|
|
177
|
+
|
|
178
|
+
1. Pi's base system prompt
|
|
179
|
+
2. recipe `SYSTEM.md`, when present
|
|
180
|
+
3. selected agent `system_instructions`
|
|
181
|
+
4. runtime context containing the current workspace and recipe directory
|
|
182
|
+
|
|
183
|
+
This lets recipes carry durable workflow guidance without changing where the
|
|
184
|
+
user is working.
|
|
185
|
+
|
|
186
|
+
## Tools
|
|
187
|
+
|
|
188
|
+
The selected agent controls active tools:
|
|
189
|
+
|
|
190
|
+
```yaml
|
|
191
|
+
tools:
|
|
192
|
+
- read
|
|
193
|
+
- bash
|
|
194
|
+
- WebFetch
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
If the selected agent has visible subagents, the extension also enables the
|
|
198
|
+
recipe `agent` tool.
|
|
199
|
+
|
|
200
|
+
Recipe extensions must be loaded before active tools are selected, because they
|
|
201
|
+
can register additional tools such as `WebFetch`, `WebSearch`, `todo_write`, or
|
|
202
|
+
custom workflow tools.
|
|
203
|
+
|
|
204
|
+
The selected agent can gate which declared recipe extensions load:
|
|
205
|
+
|
|
206
|
+
```yaml
|
|
207
|
+
extensions:
|
|
208
|
+
include:
|
|
209
|
+
- "*"
|
|
210
|
+
exclude:
|
|
211
|
+
- optional-runtime
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Omitting `extensions` or `extensions.include` loads all declared recipe
|
|
215
|
+
extensions. `exclude` subtracts matching extension names.
|
|
216
|
+
|
|
217
|
+
## Commands
|
|
218
|
+
|
|
219
|
+
When a recipe is active, the extension registers:
|
|
220
|
+
|
|
221
|
+
```text
|
|
222
|
+
/recipe
|
|
223
|
+
/recipe reload
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
`/recipe` shows:
|
|
227
|
+
|
|
228
|
+
- active recipe name and version
|
|
229
|
+
- selected agent
|
|
230
|
+
- selected model and thinking level
|
|
231
|
+
- visible subagents
|
|
232
|
+
- active recipe tools
|
|
233
|
+
- recipe directory
|
|
234
|
+
- project workspace
|
|
235
|
+
|
|
236
|
+
`/recipe reload` asks Pi to reload extensions, skills, prompts, and themes, and
|
|
237
|
+
clears the cached recipe manifest and agent state first. Use it after editing a
|
|
238
|
+
local recipe's `package.json`, agent files, resources, or extension code.
|
|
239
|
+
|
|
240
|
+
## Resources
|
|
241
|
+
|
|
242
|
+
The extension responds to Pi `resources_discover` with:
|
|
243
|
+
|
|
244
|
+
- `skillPaths`
|
|
245
|
+
- `promptPaths`
|
|
246
|
+
- `themePaths`
|
|
247
|
+
|
|
248
|
+
Declared manifest paths are used first. When omitted, conventional folders are
|
|
249
|
+
used if present:
|
|
250
|
+
|
|
251
|
+
- `skills`
|
|
252
|
+
- `prompts`
|
|
253
|
+
- `themes`
|
|
254
|
+
|
|
255
|
+
Skills become Pi `/skill:name` commands. Prompt templates and themes are
|
|
256
|
+
surfaced through Pi's normal resource system.
|
|
257
|
+
|
|
258
|
+
## Subagents
|
|
259
|
+
|
|
260
|
+
Recipe subagents are other agents from the same recipe, exposed through the
|
|
261
|
+
`agent` tool.
|
|
262
|
+
|
|
263
|
+
If the selected agent declares `subagents`, only those agents are visible:
|
|
264
|
+
|
|
265
|
+
```yaml
|
|
266
|
+
name: agent
|
|
267
|
+
subagents:
|
|
268
|
+
- explorer
|
|
269
|
+
- reviewer
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
If it omits `subagents`, every other recipe agent is visible.
|
|
273
|
+
|
|
274
|
+
The `agent` tool accepts:
|
|
275
|
+
|
|
276
|
+
- `name`: child agent name
|
|
277
|
+
- `task`: delegated task
|
|
278
|
+
- `label`: optional display label
|
|
279
|
+
- `wait`: wait for completion on start, defaulting to `true`
|
|
280
|
+
- `action`: `start`, `status`, `wait`, `interrupt`, or `close`
|
|
281
|
+
- `id`: child-run id for management actions
|
|
282
|
+
|
|
283
|
+
Child runs use the same recipe directory and current Pi workspace as the parent
|
|
284
|
+
session.
|
|
285
|
+
|
|
286
|
+
## Recipe Extensions
|
|
287
|
+
|
|
288
|
+
Recipes can declare Pi extensions:
|
|
289
|
+
|
|
290
|
+
```json
|
|
291
|
+
{
|
|
292
|
+
"pi": {
|
|
293
|
+
"extensions": ["extensions/*.ts", "extensions/*/index.ts"]
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Extensions are loaded during `session_start`. If one extension fails, Pi shows a
|
|
299
|
+
warning and continues loading the rest of the recipe. During local recipe
|
|
300
|
+
development, run `/recipe reload` after editing extension files to reload them
|
|
301
|
+
without restarting Pi.
|
|
302
|
+
|
|
303
|
+
Extension glob branches are optional, so a recipe can declare both flat and
|
|
304
|
+
nested extension layouts without failing when one branch has no matches.
|
|
305
|
+
|
|
306
|
+
Extensions are loaded with module resolution rooted at the recipe directory. If
|
|
307
|
+
an extension imports a third-party package, declare that dependency in the
|
|
308
|
+
recipe's `package.json` and install/register the recipe with `recipes install`
|
|
309
|
+
so dependencies are installed into the recipe directory. For remote Git recipes,
|
|
310
|
+
commit a lockfile with the recipe.
|
|
311
|
+
|
|
312
|
+
Example layout:
|
|
313
|
+
|
|
314
|
+
```text
|
|
315
|
+
my-recipe/
|
|
316
|
+
package.json
|
|
317
|
+
package-lock.json
|
|
318
|
+
agents/
|
|
319
|
+
agent.yaml
|
|
320
|
+
extensions/
|
|
321
|
+
tools.ts
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
Example dependency manifest:
|
|
325
|
+
|
|
326
|
+
```json
|
|
327
|
+
{
|
|
328
|
+
"name": "hello-tools",
|
|
329
|
+
"version": "0.1.0",
|
|
330
|
+
"type": "module",
|
|
331
|
+
"pi": {
|
|
332
|
+
"agents": ["agents/*.yaml"],
|
|
333
|
+
"extensions": ["extensions/*.ts"]
|
|
334
|
+
},
|
|
335
|
+
"dependencies": {
|
|
336
|
+
"zod": "^4.0.0"
|
|
337
|
+
},
|
|
338
|
+
"peerDependencies": {
|
|
339
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
340
|
+
"typebox": "*"
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Generate the lockfile from inside the recipe directory:
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
cd my-recipe
|
|
349
|
+
npm install --package-lock-only
|
|
350
|
+
recipes install .
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
For a remote Git recipe, commit `package.json` and the lockfile.
|
|
354
|
+
When users run `recipes install github:owner/repo`, the CLI installs production
|
|
355
|
+
dependencies into that cloned recipe before Pi loads extensions.
|
|
356
|
+
|
|
357
|
+
Imports of Pi runtime packages such as `@earendil-works/pi-coding-agent`,
|
|
358
|
+
`@earendil-works/pi-ai`, and `typebox` are resolved to the host Pi installation.
|
|
359
|
+
Declare those as peers in the recipe `package.json` rather than bundling another
|
|
360
|
+
copy.
|
|
361
|
+
|
|
362
|
+
Use normal `dependencies` for packages your extension imports at runtime. Use
|
|
363
|
+
`devDependencies` only for local recipe development tools; they are not needed
|
|
364
|
+
for Pi to run the recipe.
|
|
365
|
+
|
|
366
|
+
Example extension:
|
|
367
|
+
|
|
368
|
+
```ts
|
|
369
|
+
import { defineTool, type ExtensionFactory } from "@earendil-works/pi-coding-agent";
|
|
370
|
+
import { Type } from "typebox";
|
|
371
|
+
|
|
372
|
+
const extension: ExtensionFactory = (pi) => {
|
|
373
|
+
pi.registerTool(
|
|
374
|
+
defineTool({
|
|
375
|
+
name: "hello_recipe",
|
|
376
|
+
label: "Hello",
|
|
377
|
+
description: "Return a greeting from the recipe.",
|
|
378
|
+
parameters: Type.Object({ name: Type.String() }),
|
|
379
|
+
async execute(_id, params) {
|
|
380
|
+
return { content: [{ type: "text", text: `Hello ${params.name}` }] };
|
|
381
|
+
},
|
|
382
|
+
})
|
|
383
|
+
);
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
export default extension;
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
## Troubleshooting
|
|
390
|
+
|
|
391
|
+
If Pi cannot find an installed recipe, check the store:
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
recipes list
|
|
395
|
+
recipes path recipe-name
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
If Pi and `recipes` are using different stores, set:
|
|
399
|
+
|
|
400
|
+
```bash
|
|
401
|
+
PI_RECIPES_HOME=/path/to/store pi --recipe recipe-name
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
If an agent selects a model but Pi reports the model is unavailable, confirm the
|
|
405
|
+
model provider exists in Pi and the corresponding API key is configured.
|
|
406
|
+
|
|
407
|
+
If a recipe tool is listed in an agent but not active, confirm the extension
|
|
408
|
+
that registers the tool is declared in the recipe manifest and loads without a
|
|
409
|
+
warning.
|
|
410
|
+
|
|
411
|
+
If an extension fails with `Cannot find module`, confirm the dependency is in
|
|
412
|
+
the recipe `package.json`, the recipe was installed with `recipes install`, and the
|
|
413
|
+
dependency was written to the recipe's `node_modules`.
|