@introspection-ai/pi-recipes 0.1.0-beta.0 → 0.1.0-beta.1

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 CHANGED
@@ -13,7 +13,7 @@ those recipe files into the live Pi session at launch time.
13
13
  `package.json` owns both recipe identity and Node dependency metadata. The
14
14
  top-level `name`, `version`, and `description` identify the recipe, while the
15
15
  `pi` block declares recipe resources such as agents, extensions, skills,
16
- prompts, and themes.
16
+ and prompts.
17
17
 
18
18
  ## Documentation
19
19
 
@@ -88,6 +88,10 @@ repository and pushes the local recipe:
88
88
  recipes publish ./my-recipe --github owner/my-recipe --visibility private
89
89
  ```
90
90
 
91
+ Use `--visibility public` to submit the recipe's public GitHub metadata to the
92
+ marketplace catalog after a successful push. Catalog submissions are
93
+ best-effort; private publishes are not listed.
94
+
91
95
  Customize an installed recipe into an editable local copy:
92
96
 
93
97
  ```bash
package/dist/cli.js CHANGED
@@ -274,6 +274,7 @@ function printPublishedRecipe(result) {
274
274
  `Repository: ${result.createdRepository ? "created" : "existing"}`,
275
275
  `Commit: ${result.committed ? "created" : "no changes"}`,
276
276
  "Push: ok",
277
+ `Catalog: ${result.catalogued ? "submitted" : "skipped"}`,
277
278
  "",
278
279
  "Use:",
279
280
  ` pi --recipe ${result.shortName}`,
package/dist/index.d.ts CHANGED
@@ -4,4 +4,5 @@ export * from "./recipe-dev.js";
4
4
  export * from "./recipe-package.js";
5
5
  export * from "./recipe-publish.js";
6
6
  export * from "./recipe-store.js";
7
+ export * from "./recipe-telemetry.js";
7
8
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -4,4 +4,5 @@ export * from "./recipe-dev.js";
4
4
  export * from "./recipe-package.js";
5
5
  export * from "./recipe-publish.js";
6
6
  export * from "./recipe-store.js";
7
+ export * from "./recipe-telemetry.js";
7
8
  //# sourceMappingURL=index.js.map
@@ -481,7 +481,6 @@ export function createPiRecipesExtension(opts = {}) {
481
481
  agent: resolved.agent,
482
482
  skillPaths: packageResourcePaths(manifest, "skills"),
483
483
  promptPaths: packageResourcePaths(manifest, "prompts"),
484
- themePaths: packageResourcePaths(manifest, "themes"),
485
484
  extensionPaths,
486
485
  extensionsLoaded: false,
487
486
  configured: false,
@@ -791,7 +790,6 @@ export function createPiRecipesExtension(opts = {}) {
791
790
  return {
792
791
  skillPaths: launchState.skillPaths,
793
792
  promptPaths: launchState.promptPaths,
794
- themePaths: launchState.themePaths,
795
793
  };
796
794
  });
797
795
  pi.on("before_agent_start", (event, ctx) => {
@@ -37,13 +37,12 @@ function parseModel(data) {
37
37
  }
38
38
  function parseSystemInstructions(data) {
39
39
  const raw = asRecord(data.system_instructions ?? data.systemInstructions);
40
- const content = typeof raw.content === "string" ? raw.content.trim() : "";
41
- if (!content) {
42
- const prompt = typeof data.prompt === "string" ? data.prompt.trim() : "";
43
- return prompt ? { mode: "append", content: prompt } : undefined;
40
+ if (Object.hasOwn(raw, "content") && typeof raw.content === "string") {
41
+ const mode = raw.mode === "replace" ? "replace" : "append";
42
+ return { mode, content: raw.content.trim() };
44
43
  }
45
- const mode = raw.mode === "replace" ? "replace" : "append";
46
- return { mode, content };
44
+ const prompt = typeof data.prompt === "string" ? data.prompt.trim() : "";
45
+ return prompt ? { mode: "append", content: prompt } : undefined;
47
46
  }
48
47
  function parseExtensions(data) {
49
48
  const raw = asRecord(data.extensions);
@@ -7,7 +7,6 @@ const RESOURCE_KEYS = [
7
7
  "extensions",
8
8
  "skills",
9
9
  "prompts",
10
- "themes",
11
10
  ];
12
11
  function recipeNameFromTarget(target) {
13
12
  const name = basename(resolve(target)).replace(/[^a-zA-Z0-9._-]+/g, "-");
@@ -165,7 +164,7 @@ export function createRecipePublishGuide(recipeDir) {
165
164
  checklist: [
166
165
  "Run `recipes doctor .` and fix any errors.",
167
166
  `Run \`recipes publish . --github owner/${repositoryName} --visibility private\` to create, commit, and push a GitHub repository.`,
168
- "Commit package.json, agents, prompts, skills, themes, extensions, and SYSTEM.md.",
167
+ "Commit package.json, agents, prompts, skills, extensions, and SYSTEM.md.",
169
168
  "If extensions have runtime dependencies, commit the package lockfile.",
170
169
  "Push the recipe to a Git repository.",
171
170
  "Tag releases when users should install a stable version.",
@@ -3,7 +3,6 @@ export interface RecipePackageResources {
3
3
  extensions: string[];
4
4
  skills: string[];
5
5
  prompts: string[];
6
- themes: string[];
7
6
  }
8
7
  export interface RecipePackageManifest {
9
8
  name: string;
@@ -5,7 +5,6 @@ const RESOURCE_KEYS = [
5
5
  "extensions",
6
6
  "skills",
7
7
  "prompts",
8
- "themes",
9
8
  ];
10
9
  function stringArray(value) {
11
10
  return Array.isArray(value)
@@ -18,7 +17,6 @@ function emptyResources() {
18
17
  extensions: [],
19
18
  skills: [],
20
19
  prompts: [],
21
- themes: [],
22
20
  };
23
21
  }
24
22
  function normalizeResourcePath(path) {
@@ -196,7 +194,6 @@ export function defaultPiPackageResourcePaths(pkg, key) {
196
194
  agents: [join(pkg.path, "agents")],
197
195
  skills: [join(pkg.path, "skills")],
198
196
  prompts: [join(pkg.path, "prompts")],
199
- themes: [join(pkg.path, "themes")],
200
197
  };
201
198
  return (defaults[key] ?? []).filter((path) => existsSync(path));
202
199
  }
@@ -205,8 +202,7 @@ export function packageResourcePaths(pkg, key) {
205
202
  return resolvePiPackageResourcePaths(pkg, key, {
206
203
  allowEmptyGlobMatches: key === "extensions" ||
207
204
  key === "skills" ||
208
- key === "prompts" ||
209
- key === "themes",
205
+ key === "prompts",
210
206
  });
211
207
  }
212
208
  return defaultPiPackageResourcePaths(pkg, key);
@@ -25,6 +25,7 @@ export interface PublishedRecipe {
25
25
  createdRepository: boolean;
26
26
  committed: boolean;
27
27
  pushed: boolean;
28
+ catalogued: boolean;
28
29
  }
29
30
  export declare function publishRecipe(target: string, opts: RecipePublishOptions): Promise<PublishedRecipe>;
30
31
  //# sourceMappingURL=recipe-publish.d.ts.map
@@ -5,6 +5,7 @@ import { promisify } from "node:util";
5
5
  import { validateRecipeDirectory } from "./recipe-dev.js";
6
6
  import { readPiPackageManifest } from "./recipe-package.js";
7
7
  import { addRecipe, customizeRecipe, defaultRecipeStoreDir, findInstalledRecipe, recipePreferredIdentifier, recipeScopedIdentifier, } from "./recipe-store.js";
8
+ import { sendPublishTelemetry, telemetryDisabled } from "./recipe-telemetry.js";
8
9
  const execFileAsync = promisify(execFile);
9
10
  function isSafeGithubName(value) {
10
11
  return /^[a-zA-Z0-9_.-]+$/.test(value) && value !== "." && value !== "..";
@@ -82,6 +83,14 @@ function ensureGitignore(recipeDir) {
82
83
  writeFileSync(gitignorePath, `${existing.join("\n").replace(/\n*$/, "")}${prefix}${missing.join("\n")}\n`);
83
84
  return true;
84
85
  }
86
+ function resourceCounts(resources) {
87
+ return {
88
+ agents: resources.agents?.length ?? 0,
89
+ extensions: resources.extensions?.length ?? 0,
90
+ skills: resources.skills?.length ?? 0,
91
+ prompts: resources.prompts?.length ?? 0,
92
+ };
93
+ }
85
94
  function localPathForInput(input, cwd) {
86
95
  const expanded = input === "~"
87
96
  ? process.env.HOME ?? input
@@ -176,7 +185,23 @@ export async function publishRecipe(target, opts) {
176
185
  const createdRepository = await ensureGithubRepository(github, opts.visibility, recipeDir, env, opts.commandRunner);
177
186
  await setOrigin(github, recipeDir, env, opts.commandRunner);
178
187
  await runCommand("git", ["push", "-u", "origin", "HEAD:main"], { cwd: recipeDir, env }, opts.commandRunner);
188
+ const publishedManifest = readPiPackageManifest(recipeDir);
179
189
  const recipe = await addRecipe(recipeDir, opts);
190
+ const catalogued = opts.visibility === "public" && !telemetryDisabled(env);
191
+ if (catalogued) {
192
+ const source = `github:${github.fullName}`;
193
+ await sendPublishTelemetry({
194
+ id: source,
195
+ name: publishedManifest.name,
196
+ version: publishedManifest.version,
197
+ ...(publishedManifest.description ? { description: publishedManifest.description } : {}),
198
+ github: github.fullName,
199
+ source,
200
+ installCommand: `recipes install ${source}`,
201
+ homepage: `https://github.com/${github.fullName}`,
202
+ resources: resourceCounts(report.resources),
203
+ }, { env: opts.env, fetchImpl: opts.fetchImpl });
204
+ }
180
205
  return {
181
206
  recipe,
182
207
  recipeDir,
@@ -187,6 +212,7 @@ export async function publishRecipe(target, opts) {
187
212
  createdRepository,
188
213
  committed,
189
214
  pushed: true,
215
+ catalogued,
190
216
  };
191
217
  }
192
218
  //# sourceMappingURL=recipe-publish.js.map
@@ -1,7 +1,9 @@
1
+ import { type FetchImpl } from "./recipe-telemetry.js";
1
2
  export interface RecipeStoreOptions {
2
3
  storeDir?: string;
3
4
  cwd?: string;
4
5
  env?: NodeJS.ProcessEnv;
6
+ fetchImpl?: FetchImpl;
5
7
  }
6
8
  export interface InstalledRecipe {
7
9
  id: string;
@@ -5,6 +5,7 @@ import { basename, dirname, isAbsolute, join, relative, resolve } from "node:pat
5
5
  import { execFile } from "node:child_process";
6
6
  import { promisify } from "node:util";
7
7
  import { readPiPackageManifest, validatePiPackageManifest, } from "./recipe-package.js";
8
+ import { sendInstallTelemetry } from "./recipe-telemetry.js";
8
9
  const execFileAsync = promisify(execFile);
9
10
  const STORE_LOCK_STALE_MS = 30_000;
10
11
  const STORE_LOCK_TIMEOUT_MS = 10_000;
@@ -602,6 +603,11 @@ export async function addRecipe(input, opts = {}) {
602
603
  ].sort((a, b) => a.name.localeCompare(b.name));
603
604
  writeRecipeStore(store, storeDir);
604
605
  });
606
+ // Anonymous, best-effort install ping for the public directory. Only remote
607
+ // (github/git) installs are counted; local recipe registration is private.
608
+ if (source.kind === "github" || source.kind === "git") {
609
+ await sendInstallTelemetry(installed, { env: opts.env, fetchImpl: opts.fetchImpl });
610
+ }
605
611
  return installed;
606
612
  }
607
613
  export function listRecipes(opts = {}) {
@@ -0,0 +1,44 @@
1
+ import type { InstalledRecipe } from "./recipe-store.js";
2
+ import type { RecipePackageResources } from "./recipe-package.js";
3
+ export declare const DEFAULT_TELEMETRY_ENDPOINT = "https://pi.recipes/api/installs";
4
+ export declare const DEFAULT_CATALOG_ENDPOINT = "https://pi.recipes/api/catalog/recipes";
5
+ export type FetchImpl = typeof fetch;
6
+ export interface InstallTelemetryOptions {
7
+ env?: NodeJS.ProcessEnv;
8
+ fetchImpl?: FetchImpl;
9
+ }
10
+ export interface PublishTelemetryOptions extends InstallTelemetryOptions {
11
+ endpoint?: string;
12
+ }
13
+ export interface PublishTelemetryRecipe {
14
+ id: string;
15
+ name: string;
16
+ version: string;
17
+ description?: string;
18
+ github: string;
19
+ source: string;
20
+ installCommand: string;
21
+ homepage: string;
22
+ resources: Record<keyof RecipePackageResources, number>;
23
+ }
24
+ /**
25
+ * Returns true when the user has opted out of recipe telemetry.
26
+ * Honors the cross-tool `DO_NOT_TRACK` convention plus a package-specific
27
+ * `PI_RECIPES_NO_TELEMETRY` escape hatch.
28
+ */
29
+ export declare function telemetryDisabled(env: NodeJS.ProcessEnv): boolean;
30
+ export declare function telemetryEndpoint(env: NodeJS.ProcessEnv): string;
31
+ export declare function catalogEndpoint(env: NodeJS.ProcessEnv): string;
32
+ /**
33
+ * Send a single anonymous install ping. Resolves once the request settles or
34
+ * the timeout elapses; all network and serialization errors are swallowed so a
35
+ * telemetry failure can never break `recipes install`.
36
+ */
37
+ export declare function sendInstallTelemetry(recipe: InstalledRecipe, opts?: InstallTelemetryOptions): Promise<void>;
38
+ /**
39
+ * Submit a public recipe for marketplace cataloguing. The backend owns
40
+ * trust/moderation fields such as `official`; clients submit only public
41
+ * package metadata derived from the GitHub repository and recipe manifest.
42
+ */
43
+ export declare function sendPublishTelemetry(recipe: PublishTelemetryRecipe, opts?: PublishTelemetryOptions): Promise<void>;
44
+ //# sourceMappingURL=recipe-telemetry.d.ts.map
@@ -0,0 +1,79 @@
1
+ // Best-effort telemetry for the recipes directory at https://pi.recipes.
2
+ // Installs send only anonymous counters. Public publishes submit public package
3
+ // metadata so the directory can catalogue recipes. Telemetry never blocks or
4
+ // fails a recipe command.
5
+ export const DEFAULT_TELEMETRY_ENDPOINT = "https://pi.recipes/api/installs";
6
+ export const DEFAULT_CATALOG_ENDPOINT = "https://pi.recipes/api/catalog/recipes";
7
+ const TELEMETRY_TIMEOUT_MS = 1500;
8
+ /**
9
+ * Returns true when the user has opted out of recipe telemetry.
10
+ * Honors the cross-tool `DO_NOT_TRACK` convention plus a package-specific
11
+ * `PI_RECIPES_NO_TELEMETRY` escape hatch.
12
+ */
13
+ export function telemetryDisabled(env) {
14
+ return isTruthy(env.DO_NOT_TRACK) || isTruthy(env.PI_RECIPES_NO_TELEMETRY);
15
+ }
16
+ export function telemetryEndpoint(env) {
17
+ const configured = env.PI_RECIPES_TELEMETRY_ENDPOINT?.trim();
18
+ return configured && configured.length > 0 ? configured : DEFAULT_TELEMETRY_ENDPOINT;
19
+ }
20
+ export function catalogEndpoint(env) {
21
+ const configured = env.PI_RECIPES_CATALOG_ENDPOINT?.trim();
22
+ return configured && configured.length > 0 ? configured : DEFAULT_CATALOG_ENDPOINT;
23
+ }
24
+ /**
25
+ * Send a single anonymous install ping. Resolves once the request settles or
26
+ * the timeout elapses; all network and serialization errors are swallowed so a
27
+ * telemetry failure can never break `recipes install`.
28
+ */
29
+ export async function sendInstallTelemetry(recipe, opts = {}) {
30
+ await postTelemetry(telemetryEndpoint(opts.env ?? process.env), {
31
+ event: "install",
32
+ id: recipe.id,
33
+ name: recipe.name,
34
+ version: recipe.version,
35
+ }, opts);
36
+ }
37
+ /**
38
+ * Submit a public recipe for marketplace cataloguing. The backend owns
39
+ * trust/moderation fields such as `official`; clients submit only public
40
+ * package metadata derived from the GitHub repository and recipe manifest.
41
+ */
42
+ export async function sendPublishTelemetry(recipe, opts = {}) {
43
+ const env = opts.env ?? process.env;
44
+ await postTelemetry(opts.endpoint ?? catalogEndpoint(env), {
45
+ event: "publish",
46
+ ...recipe,
47
+ }, opts);
48
+ }
49
+ async function postTelemetry(endpoint, body, opts) {
50
+ const env = opts.env ?? process.env;
51
+ if (telemetryDisabled(env))
52
+ return;
53
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
54
+ if (typeof fetchImpl !== "function")
55
+ return;
56
+ const controller = new AbortController();
57
+ const timer = setTimeout(() => controller.abort(), TELEMETRY_TIMEOUT_MS);
58
+ try {
59
+ await fetchImpl(endpoint, {
60
+ method: "POST",
61
+ headers: { "content-type": "application/json" },
62
+ body: JSON.stringify(body),
63
+ signal: controller.signal,
64
+ });
65
+ }
66
+ catch {
67
+ // Telemetry is best-effort. Never surface failures to the caller.
68
+ }
69
+ finally {
70
+ clearTimeout(timer);
71
+ }
72
+ }
73
+ function isTruthy(value) {
74
+ if (!value)
75
+ return false;
76
+ const normalized = value.trim().toLowerCase();
77
+ return normalized !== "" && normalized !== "0" && normalized !== "false";
78
+ }
79
+ //# sourceMappingURL=recipe-telemetry.js.map
@@ -84,7 +84,7 @@ On session startup, the extension:
84
84
  6. Sets the Pi session name.
85
85
  7. Sets the model and thinking level from the selected agent when specified.
86
86
  8. Selects active tools from the selected agent.
87
- 9. Returns recipe resources for skills, prompts, and themes.
87
+ 9. Returns recipe resources for skills and prompts.
88
88
  10. Composes the runtime system prompt from Pi defaults, `SYSTEM.md`, selected agent instructions, and recipe runtime context.
89
89
 
90
90
  The current Pi working directory remains the user's project workspace. The
@@ -102,7 +102,7 @@ The `pi` block tells Pi which recipe-owned files should be loaded:
102
102
 
103
103
  - agent definition globs
104
104
  - extension globs
105
- - skill, prompt, and theme paths
105
+ - skill and prompt paths
106
106
 
107
107
  The same file also carries normal Node package metadata for extension
108
108
  dependencies. Add `dependencies`, `peerDependencies`, `packageManager`, and a
@@ -171,6 +171,9 @@ Objects such as `model` and `extensions` merge by key. Arrays such as `tools`,
171
171
  - `append`: append to the current prompt
172
172
  - `replace`: replace the current prompt
173
173
 
174
+ Use `content: ""` when an agent intentionally adds no instructions beyond
175
+ `SYSTEM.md` but still needs to declare the field explicitly.
176
+
174
177
  ## Session Prompt
175
178
 
176
179
  The session prompt is assembled from:
@@ -233,7 +236,7 @@ When a recipe is active, the extension registers:
233
236
  - recipe directory
234
237
  - project workspace
235
238
 
236
- `/recipe reload` asks Pi to reload extensions, skills, prompts, and themes, and
239
+ `/recipe reload` asks Pi to reload extensions, skills, and prompts, and
237
240
  clears the cached recipe manifest and agent state first. Use it after editing a
238
241
  local recipe's `package.json`, agent files, resources, or extension code.
239
242
 
@@ -243,17 +246,15 @@ The extension responds to Pi `resources_discover` with:
243
246
 
244
247
  - `skillPaths`
245
248
  - `promptPaths`
246
- - `themePaths`
247
249
 
248
250
  Declared manifest paths are used first. When omitted, conventional folders are
249
251
  used if present:
250
252
 
251
253
  - `skills`
252
254
  - `prompts`
253
- - `themes`
254
255
 
255
- Skills become Pi `/skill:name` commands. Prompt templates and themes are
256
- surfaced through Pi's normal resource system.
256
+ Skills become Pi `/skill:name` commands. Prompt templates are surfaced through
257
+ Pi's normal resource system.
257
258
 
258
259
  ## Subagents
259
260
 
@@ -133,6 +133,9 @@ model:
133
133
  Objects such as `model` and `extensions` merge by key, while arrays such as
134
134
  `tools`, `skills`, and `subagents` replace the inherited array.
135
135
 
136
+ Use `system_instructions.content: ""` when an agent intentionally adds no
137
+ instructions beyond `SYSTEM.md` but still needs to declare the field explicitly.
138
+
136
139
  `SYSTEM.md` is optional. When present, Pi uses it as the recipe-level system
137
140
  prompt before applying the selected agent's `system_instructions`.
138
141
 
@@ -183,7 +186,6 @@ The `pi` block declares recipe-owned resources:
183
186
  - `extensions`: TypeScript extension globs
184
187
  - `skills`: skill paths or globs
185
188
  - `prompts`: prompt paths or globs
186
- - `themes`: theme paths or globs
187
189
 
188
190
  Normal package-manager fields such as `dependencies`, `optionalDependencies`,
189
191
  `peerDependencies`, `devDependencies`, `packageManager`, and lockfile metadata
@@ -201,8 +203,7 @@ boundaries:
201
203
  "agents": ["agents/*.yaml"],
202
204
  "extensions": ["extensions/*.ts", "extensions/*/index.ts"],
203
205
  "skills": ["skills/**/SKILL.md"],
204
- "prompts": ["prompts"],
205
- "themes": ["themes/*.json"]
206
+ "prompts": ["prompts"]
206
207
  }
207
208
  }
208
209
  ```
@@ -212,7 +213,6 @@ When entries are omitted, conventional folders are used if present:
212
213
  - `agents`
213
214
  - `skills`
214
215
  - `prompts`
215
- - `themes`
216
216
 
217
217
  `extensions` are only loaded when declared.
218
218
 
@@ -448,6 +448,8 @@ recipes publish ./my-recipe --github owner/my-recipe --visibility public
448
448
  `recipes publish` runs the same development validation as `doctor`, updates
449
449
  `package.json#name` to `@owner/my-recipe`, commits local changes, creates the
450
450
  GitHub repository when needed, pushes `main`, and re-registers the local recipe.
451
+ When `--visibility public` is used, it also submits the public package metadata
452
+ to the recipe catalog so the marketplace can add or refresh the listing.
451
453
 
452
454
  For a standalone public recipe:
453
455
 
@@ -506,6 +508,40 @@ recipes install github:owner/repo/recipes/code-review
506
508
  recipes install github:owner/repo/recipes/research#v1.0.0
507
509
  ```
508
510
 
511
+ ## Telemetry
512
+
513
+ When you install a recipe from a remote source (`github:` or a Git URL),
514
+ `recipes install` sends a single anonymous ping to the public recipe directory
515
+ at [pi.recipes](https://pi.recipes) so it can rank recipes by install count.
516
+
517
+ The ping contains only the recipe's canonical id, name, and version:
518
+
519
+ ```json
520
+ { "event": "install", "id": "github:owner/repo", "name": "my-recipe", "version": "1.0.0" }
521
+ ```
522
+
523
+ No paths, machine identifiers, or other personal data are sent. Local recipe
524
+ registration (`recipes install ./my-recipe`) is never reported. The ping is
525
+ best-effort and never blocks or fails an install.
526
+
527
+ When you publish with `--visibility public`, `recipes publish` sends the
528
+ recipe's public GitHub source, package name, version, description, install
529
+ command, homepage, and resource counts so it can appear in the catalog.
530
+
531
+ Opt out by setting either environment variable to a truthy value:
532
+
533
+ ```bash
534
+ DO_NOT_TRACK=1 recipes install github:owner/repo
535
+ PI_RECIPES_NO_TELEMETRY=1 recipes install github:owner/repo
536
+ ```
537
+
538
+ Point install pings or catalog submissions at different collectors with:
539
+
540
+ ```bash
541
+ PI_RECIPES_TELEMETRY_ENDPOINT=https://example.com/api/installs recipes install github:owner/repo
542
+ PI_RECIPES_CATALOG_ENDPOINT=https://example.com/api/catalog/recipes recipes publish . --github owner/my-recipe --visibility public
543
+ ```
544
+
509
545
  ## Troubleshooting
510
546
 
511
547
  If a private GitHub recipe fails to install with `github:owner/repo`, use SSH or
@@ -1,7 +1,7 @@
1
1
  # Pi Recipes: Install, Customize, Publish
2
2
 
3
3
  A recipe is a shareable Pi workflow package: it can add agents, instructions,
4
- skills, prompts, themes, and optional runtime extensions.
4
+ skills, prompts, and optional runtime extensions.
5
5
 
6
6
  Use `recipes` to install recipes, make local edits, validate them, and
7
7
  publish your own.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@introspection-ai/pi-recipes",
3
- "version": "0.1.0-beta.0",
3
+ "version": "0.1.0-beta.1",
4
4
  "description": "Local session tooling for package-based workflows.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -24,6 +24,8 @@
24
24
  "dist/recipe-publish.js",
25
25
  "dist/recipe-store.d.ts",
26
26
  "dist/recipe-store.js",
27
+ "dist/recipe-telemetry.d.ts",
28
+ "dist/recipe-telemetry.js",
27
29
  "docs",
28
30
  "README.md",
29
31
  "package.json"