@introspection-ai/recipes 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/LICENSE +191 -0
  2. package/README.md +184 -0
  3. package/dist/agent-tool.d.ts +42 -0
  4. package/dist/agent-tool.d.ts.map +1 -0
  5. package/dist/agent-tool.js +159 -0
  6. package/dist/agent-tool.js.map +1 -0
  7. package/dist/child-agent-completions.d.ts +61 -0
  8. package/dist/child-agent-completions.d.ts.map +1 -0
  9. package/dist/child-agent-completions.js +135 -0
  10. package/dist/child-agent-completions.js.map +1 -0
  11. package/dist/child-agent-store.d.ts +48 -0
  12. package/dist/child-agent-store.d.ts.map +1 -0
  13. package/dist/child-agent-store.js +98 -0
  14. package/dist/child-agent-store.js.map +1 -0
  15. package/dist/child-agent.d.ts +43 -0
  16. package/dist/child-agent.d.ts.map +1 -0
  17. package/dist/child-agent.js +268 -0
  18. package/dist/child-agent.js.map +1 -0
  19. package/dist/direct-cli.d.ts +9 -0
  20. package/dist/direct-cli.d.ts.map +1 -0
  21. package/dist/direct-cli.js +22 -0
  22. package/dist/direct-cli.js.map +1 -0
  23. package/dist/index.d.ts +14 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +14 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/inspect.d.ts +26 -0
  28. package/dist/inspect.d.ts.map +1 -0
  29. package/dist/inspect.js +70 -0
  30. package/dist/inspect.js.map +1 -0
  31. package/dist/interactions.d.ts +204 -0
  32. package/dist/interactions.d.ts.map +1 -0
  33. package/dist/interactions.js +358 -0
  34. package/dist/interactions.js.map +1 -0
  35. package/dist/mcp-catalog.d.ts +8 -0
  36. package/dist/mcp-catalog.d.ts.map +1 -0
  37. package/dist/mcp-catalog.js +60 -0
  38. package/dist/mcp-catalog.js.map +1 -0
  39. package/dist/mcp-cli-core.d.ts +79 -0
  40. package/dist/mcp-cli-core.d.ts.map +1 -0
  41. package/dist/mcp-cli-core.js +1717 -0
  42. package/dist/mcp-cli-core.js.map +1 -0
  43. package/dist/mcp-cli-help.d.ts +2 -0
  44. package/dist/mcp-cli-help.d.ts.map +1 -0
  45. package/dist/mcp-cli-help.js +36 -0
  46. package/dist/mcp-cli-help.js.map +1 -0
  47. package/dist/mcp-cli-policy.d.ts +17 -0
  48. package/dist/mcp-cli-policy.d.ts.map +1 -0
  49. package/dist/mcp-cli-policy.js +230 -0
  50. package/dist/mcp-cli-policy.js.map +1 -0
  51. package/dist/mcp-cli.d.ts +3 -0
  52. package/dist/mcp-cli.d.ts.map +1 -0
  53. package/dist/mcp-cli.js +33 -0
  54. package/dist/mcp-cli.js.map +1 -0
  55. package/dist/mcp-client.d.ts +3 -0
  56. package/dist/mcp-client.d.ts.map +1 -0
  57. package/dist/mcp-client.js +86 -0
  58. package/dist/mcp-client.js.map +1 -0
  59. package/dist/mcp-command-context.d.ts +13 -0
  60. package/dist/mcp-command-context.d.ts.map +1 -0
  61. package/dist/mcp-command-context.js +29 -0
  62. package/dist/mcp-command-context.js.map +1 -0
  63. package/dist/mcp-contract.d.ts +16 -0
  64. package/dist/mcp-contract.d.ts.map +1 -0
  65. package/dist/mcp-contract.js +306 -0
  66. package/dist/mcp-contract.js.map +1 -0
  67. package/dist/mcp-daemon-client.d.ts +10 -0
  68. package/dist/mcp-daemon-client.d.ts.map +1 -0
  69. package/dist/mcp-daemon-client.js +119 -0
  70. package/dist/mcp-daemon-client.js.map +1 -0
  71. package/dist/mcp-daemon-protocol.d.ts +64 -0
  72. package/dist/mcp-daemon-protocol.d.ts.map +1 -0
  73. package/dist/mcp-daemon-protocol.js +6 -0
  74. package/dist/mcp-daemon-protocol.js.map +1 -0
  75. package/dist/mcp-daemon.d.ts +3 -0
  76. package/dist/mcp-daemon.d.ts.map +1 -0
  77. package/dist/mcp-daemon.js +76880 -0
  78. package/dist/mcp-daemon.js.map +1 -0
  79. package/dist/mcp-run-worker.d.ts +2 -0
  80. package/dist/mcp-run-worker.d.ts.map +1 -0
  81. package/dist/mcp-run-worker.js +76579 -0
  82. package/dist/mcp-run-worker.js.map +1 -0
  83. package/dist/mcp.d.ts +168 -0
  84. package/dist/mcp.d.ts.map +1 -0
  85. package/dist/mcp.js +558 -0
  86. package/dist/mcp.js.map +1 -0
  87. package/dist/pi-extension.d.ts +30 -0
  88. package/dist/pi-extension.d.ts.map +1 -0
  89. package/dist/pi-extension.js +880 -0
  90. package/dist/pi-extension.js.map +1 -0
  91. package/dist/provider-env.d.ts +2 -0
  92. package/dist/provider-env.d.ts.map +1 -0
  93. package/dist/provider-env.js +21 -0
  94. package/dist/provider-env.js.map +1 -0
  95. package/dist/recipe/resolve.d.ts +30 -0
  96. package/dist/recipe/resolve.d.ts.map +1 -0
  97. package/dist/recipe/resolve.js +131 -0
  98. package/dist/recipe/resolve.js.map +1 -0
  99. package/dist/recipe-agent.d.ts +71 -0
  100. package/dist/recipe-agent.d.ts.map +1 -0
  101. package/dist/recipe-agent.js +555 -0
  102. package/dist/recipe-agent.js.map +1 -0
  103. package/dist/recipe-extensions.d.ts +9 -0
  104. package/dist/recipe-extensions.d.ts.map +1 -0
  105. package/dist/recipe-extensions.js +81 -0
  106. package/dist/recipe-extensions.js.map +1 -0
  107. package/dist/recipe-mcp-config.d.ts +15 -0
  108. package/dist/recipe-mcp-config.d.ts.map +1 -0
  109. package/dist/recipe-mcp-config.js +82 -0
  110. package/dist/recipe-mcp-config.js.map +1 -0
  111. package/dist/recipe-model.d.ts +49 -0
  112. package/dist/recipe-model.d.ts.map +1 -0
  113. package/dist/recipe-model.js +299 -0
  114. package/dist/recipe-model.js.map +1 -0
  115. package/dist/recipe-package.d.ts +79 -0
  116. package/dist/recipe-package.d.ts.map +1 -0
  117. package/dist/recipe-package.js +479 -0
  118. package/dist/recipe-package.js.map +1 -0
  119. package/dist/recipe-skills.d.ts +7 -0
  120. package/dist/recipe-skills.d.ts.map +1 -0
  121. package/dist/recipe-skills.js +46 -0
  122. package/dist/recipe-skills.js.map +1 -0
  123. package/dist/run-controller.d.ts +32 -0
  124. package/dist/run-controller.d.ts.map +1 -0
  125. package/dist/run-controller.js +259 -0
  126. package/dist/run-controller.js.map +1 -0
  127. package/dist/run.d.ts +28 -0
  128. package/dist/run.d.ts.map +1 -0
  129. package/dist/run.js +84 -0
  130. package/dist/run.js.map +1 -0
  131. package/dist/session.d.ts +140 -0
  132. package/dist/session.d.ts.map +1 -0
  133. package/dist/session.js +363 -0
  134. package/dist/session.js.map +1 -0
  135. package/dist/test-utils.d.ts +32 -0
  136. package/dist/test-utils.d.ts.map +1 -0
  137. package/dist/test-utils.js +259 -0
  138. package/dist/test-utils.js.map +1 -0
  139. package/dist/testing.d.ts +25 -0
  140. package/dist/testing.d.ts.map +1 -0
  141. package/dist/testing.js +96 -0
  142. package/dist/testing.js.map +1 -0
  143. package/docs/agent-composition.md +196 -0
  144. package/docs/deployment-configuration.md +65 -0
  145. package/docs/index.md +49 -0
  146. package/docs/interactions.md +210 -0
  147. package/docs/mcp-auth.md +80 -0
  148. package/docs/mcp-configuration.md +126 -0
  149. package/docs/migration.md +70 -0
  150. package/docs/pi-extension.md +97 -0
  151. package/docs/python-bindings-release.md +47 -0
  152. package/docs/recipe-evals.md +70 -0
  153. package/docs/recipe-flow.md +41 -0
  154. package/docs/recipe-format.md +186 -0
  155. package/docs/recipe-judges.md +152 -0
  156. package/docs/runtime-library.md +171 -0
  157. package/package.json +106 -0
  158. package/vendor/mcp-client/darwin-arm64/mcp-client +0 -0
  159. package/vendor/mcp-client/darwin-x64/mcp-client +0 -0
  160. package/vendor/mcp-client/linux-arm64/mcp-client +0 -0
  161. package/vendor/mcp-client/linux-x64/mcp-client +0 -0
@@ -0,0 +1,186 @@
1
+ # Recipe Format
2
+
3
+ **Status:** Open format, version 1
4
+ **Reference implementation:** `@introspection-ai/recipes`
5
+ **Validator:** `pi-recipe-check`
6
+
7
+ The Recipe Format is a Git-native package contract for complete Pi agents. It
8
+ defines the agent-owned inputs that a compatible host must interpret the same
9
+ way. It does not define deployment infrastructure or a network protocol.
10
+
11
+ The key words **MUST**, **MUST NOT**, **SHOULD**, and **MAY** are normative.
12
+
13
+ ## Compatibility scope
14
+
15
+ A conforming Recipe is **Pi-native and host-portable**:
16
+
17
+ - it MUST produce the same resolved agent configuration in compatible Pi hosts;
18
+ - it MUST NOT depend on an Introspection-managed runtime;
19
+ - it MAY declare host requirements that a particular host cannot satisfy;
20
+ - a host MUST fail closed when a required capability cannot be bound.
21
+
22
+ This format does not claim interoperability with non-Pi agent harnesses.
23
+
24
+ ## Package root
25
+
26
+ A Recipe MUST be a directory containing `package.json`. The manifest MUST have:
27
+
28
+ ```json
29
+ {
30
+ "name": "acme-research",
31
+ "version": "1.0.0",
32
+ "description": "Research an account and produce a sourced brief.",
33
+ "pi": {
34
+ "agents": ["agents/*.yaml"],
35
+ "skills": ["skills/**/SKILL.md"],
36
+ "extensions": ["extensions/*.ts"],
37
+ "prompts": ["prompts/*.md"]
38
+ }
39
+ }
40
+ ```
41
+
42
+ `name` is the package identity. `version` is distribution metadata and defaults
43
+ to `0.0.0` when omitted for compatibility. `description` is human-facing.
44
+
45
+ Resource paths:
46
+
47
+ - MUST be relative to the package root;
48
+ - MUST NOT traverse outside the package;
49
+ - MAY be files, directories, or supported glob patterns;
50
+ - are resolved deterministically in lexical order.
51
+
52
+ Unknown top-level `package.json` fields retain normal npm semantics. Unknown
53
+ Recipe fields inside supported `pi` structures are validation errors unless a
54
+ later format version explicitly defines them.
55
+
56
+ ## Agents
57
+
58
+ `pi.agents` declares YAML agent definitions. A resolved Recipe MUST contain at
59
+ least one agent.
60
+
61
+ ```yaml
62
+ name: agent
63
+ description: Produce a sourced research brief.
64
+ model:
65
+ name: openrouter/anthropic/claude-sonnet-4.5
66
+ thinking_level: high
67
+ tools: [read, bash]
68
+ skills: [research]
69
+ subagents: [reviewer]
70
+ extensions:
71
+ include: [citations]
72
+ system_instructions:
73
+ mode: append
74
+ content: Verify every material claim.
75
+ ```
76
+
77
+ An agent MAY inherit from another named agent with `from`. Inheritance MUST be
78
+ acyclic. Child fields override inherited scalar fields; documented collection
79
+ fields use the merge or replacement behavior in
80
+ [Agent composition](agent-composition.md).
81
+
82
+ Every fully resolved agent MUST define:
83
+
84
+ - `model.name` as `<provider>/<model_id>`;
85
+ - `model.thinking_level`;
86
+ - `tools`;
87
+ - `system_instructions`.
88
+
89
+ Omitted `skills` and `subagents` resolve to empty lists.
90
+
91
+ The default agent is named `agent`. If no `agent` exists, a host MAY select the
92
+ only declared agent. When multiple agents exist without `agent`, the caller
93
+ MUST select one explicitly.
94
+
95
+ ## Instructions, skills, prompts, and extensions
96
+
97
+ `SYSTEM.md`, when present, is package-wide instruction source. Agent
98
+ `system_instructions.mode` determines whether agent instructions append to or
99
+ replace the current prompt.
100
+
101
+ Skills follow the [Agent Skills](https://agentskills.io) directory convention
102
+ and are selected from the resources declared by `pi.skills`.
103
+
104
+ Prompt templates are declared by `pi.prompts`.
105
+
106
+ Recipe-owned Pi extensions are declared by `pi.extensions`. An agent MAY select
107
+ declared extensions with `extensions.include` and `extensions.exclude`. A host
108
+ MUST NOT load undeclared Recipe extension source.
109
+
110
+ ## Tools, subagents, and capabilities
111
+
112
+ `tools` is an allowlist. A host MUST expose no undeclared Pi or extension tool
113
+ through this field.
114
+
115
+ `subagents` names agents the selected agent may invoke. A host MUST expose only
116
+ those resolved definitions through the shared `agent` tool. How child work is
117
+ scheduled or isolated belongs to the host.
118
+
119
+ The `pi.mcp` package block declares capability servers and package-level tool
120
+ policy. Agent `mcp` blocks narrow those declarations. Credentials and concrete
121
+ endpoint bindings MUST NOT be required in distributable Recipe source. A host
122
+ MUST reject an unbound required server before the session begins.
123
+
124
+ See [MCP configuration](mcp-configuration.md) for the complete authored and
125
+ binding grammar.
126
+
127
+ ## Quality and resource intent
128
+
129
+ Recipe-owned judge YAML expresses portable quality definitions. Hosts MAY use
130
+ those definitions online or offline, but MUST preserve their authored identity
131
+ and semantics.
132
+
133
+ `pi.evals` MAY pin external evaluation suites. The format records the pin; an
134
+ evaluation runner remains an external tool.
135
+
136
+ Portable resource intent is declared under the documented runtime resource
137
+ grammar. A host decides whether it can satisfy that intent and MUST report
138
+ unsupported required resources rather than silently weakening them.
139
+
140
+ ## Host responsibilities
141
+
142
+ The Recipe Format owns:
143
+
144
+ - package and agent interpretation;
145
+ - instruction composition;
146
+ - model and tool selection;
147
+ - skill, prompt, and extension selection;
148
+ - subagent visibility;
149
+ - capability policy;
150
+ - quality definitions and resource intent.
151
+
152
+ The host owns:
153
+
154
+ - credentials and secret resolution;
155
+ - workspaces and filesystem isolation;
156
+ - task and process lifecycle;
157
+ - persistence and recovery;
158
+ - scheduling and concurrency enforcement;
159
+ - network protocols and user authentication;
160
+ - telemetry export policy;
161
+ - deployment.
162
+
163
+ Those host concerns MUST NOT become mandatory Recipe source fields.
164
+
165
+ ## Conformance
166
+
167
+ There are two conformance layers:
168
+
169
+ 1. `pi-recipe-check` validates authored package snapshots without executing
170
+ them.
171
+ 2. `@introspection-ai/recipes/test-utils` verifies that a host constructs and
172
+ disposes Recipe sessions with the required semantics.
173
+
174
+ A host SHOULD run both layers in CI.
175
+
176
+ ## Evolution
177
+
178
+ The format follows additive evolution while version 1 is active:
179
+
180
+ - new optional fields MAY be added;
181
+ - existing field meaning MUST NOT change incompatibly;
182
+ - required fields MUST NOT be added without a new major format version;
183
+ - hosts MUST ignore only extension points explicitly documented as open.
184
+
185
+ The implementation package follows SemVer independently. Package version and
186
+ format version are not the same thing.
@@ -0,0 +1,152 @@
1
+ # Recipe judge definitions
2
+
3
+ Recipe judges are optional, recipe-owned LLM grading definitions. Author them
4
+ as direct children of `judges/` using a lowercase `.yaml` or `.yml` extension:
5
+
6
+ ```text
7
+ my-recipe/
8
+ judges/
9
+ helpful.yaml
10
+ ```
11
+
12
+ Nested files such as `judges/calibration/helpful.yaml` are not judge sources.
13
+ The standalone `recipe-check` binary, `introspection check`, and in-memory
14
+ bindings discover the same direct-child set and return the same validation
15
+ result. Recipes without judge sources have no judge diagnostics or
16
+ `resources.judges` count.
17
+
18
+ ## Ownership boundary
19
+
20
+ `pi-recipe-check` owns the portable authored YAML specification and its static,
21
+ file-oriented diagnostics. The I/O-free `check_recipe_files` core is the common
22
+ validation path used by the filesystem checker, npm CLI, serialized snapshot
23
+ API, and Python binding.
24
+
25
+ The Introspection judge engine owns runtime evaluation: applicability
26
+ execution, conversation assembly and transcript protection, model request
27
+ construction, retries, verdict normalization, and evaluation identity. Runtime
28
+ implementations should consume or remain explicitly compatible with the
29
+ authored specification defined here; new authored fields must land in this
30
+ checker and its contract tests rather than being introduced only in a runtime
31
+ parser.
32
+
33
+ The Rust checker and Python binding return a `Report` containing diagnostics
34
+ and, when judges exist, a `resources.judges` source count. The report does not
35
+ contain a normalized judge definition, `judge_id`, `definition_hash`, or
36
+ registry projection. Migrating project-scoped registry projection away from
37
+ the runtime parser is a separate platform change and must not add project or
38
+ tenant context to this portable API.
39
+
40
+ ## Definition shape
41
+
42
+ The minimal definition is:
43
+
44
+ ```yaml
45
+ judge: helpful
46
+
47
+ instructions: |
48
+ Determine whether the assistant answered the user correctly.
49
+
50
+ llm:
51
+ model: gpt-5
52
+ ```
53
+
54
+ `judge`, `instructions`, and `llm.model` are required and non-empty. Judge names
55
+ must be unique across all judge files in one recipe. `llm.provider` defaults to
56
+ `openai` at runtime.
57
+
58
+ The canonical expanded definition is:
59
+
60
+ ```yaml
61
+ judge: helpful
62
+ description: Did the assistant answer correctly?
63
+
64
+ on:
65
+ - event: message
66
+ match:
67
+ role: assistant
68
+
69
+ instructions: |
70
+ Determine whether the assistant answered the user correctly.
71
+
72
+ llm:
73
+ provider: openai
74
+ model: gpt-5
75
+ request:
76
+ temperature: 0
77
+ max_tokens: 1024
78
+ reasoning_effort: medium
79
+ transport:
80
+ timeout_ms: 60000
81
+ max_retries: 2
82
+ max_retry_delay_ms: 5000
83
+ local:
84
+ base_url: https://api.openai.com/v1
85
+ api_key_env: OPENAI_API_KEY
86
+ ```
87
+
88
+ Unknown fields are errors at every level. The obsolete top-level `model:`
89
+ block is rejected.
90
+
91
+ ### LLM settings
92
+
93
+ - `provider` is a 1-64 byte lowercase slug containing ASCII letters, digits,
94
+ and hyphens. The portable checker does not restrict it to managed platform
95
+ providers because custom slugs can be used with an explicit local endpoint.
96
+ - `model` is a trimmed, non-empty string of at most 255 bytes.
97
+ - `request.temperature` is a finite number from 0 through 2 and defaults to 0.
98
+ - `request.max_tokens` is an integer from 1 through 131072 when present;
99
+ explicit `null` is treated as omitted.
100
+ - `request.reasoning_effort` is a 1-64 byte lowercase slug containing ASCII
101
+ letters and hyphens; explicit `null` is treated as omitted.
102
+ - `transport.timeout_ms` is an integer from 1 through 600000 and defaults to
103
+ 60000.
104
+ - `transport.max_retries` is an integer from 0 through 10 and defaults to 0.
105
+ - `transport.max_retry_delay_ms` is an integer from 0 through 60000 and
106
+ defaults to 5000.
107
+ - `local` requires both `base_url` and `api_key_env`. The URL must be HTTP(S),
108
+ have a host, contain no embedded credentials, query, or fragment, and use
109
+ HTTPS unless it targets `localhost`, `127.0.0.1`, or `::1`. `api_key_env` is
110
+ an environment-variable name, not a credential value.
111
+
112
+ Transport and local settings affect execution but not authored grading
113
+ identity. The platform judge engine remains responsible for applying defaults,
114
+ building requests, and enforcing runtime routing.
115
+
116
+ ## Applicability
117
+
118
+ `on` is optional. Omission, an empty mapping, or an empty list makes the judge
119
+ applicable to every conversation selected for judging. Otherwise it is an
120
+ OR-list of matchers. Supported events are `message`, `tool`, and `feedback`;
121
+ fields within one `match` mapping are ANDed by the runtime engine.
122
+
123
+ ```yaml
124
+ on:
125
+ - event: message
126
+ match:
127
+ role: user
128
+ text: /refund|invoice/i
129
+ - event: tool
130
+ match:
131
+ name: shell
132
+ args.command: /pytest/i
133
+ - event: feedback
134
+ match:
135
+ sentiment: negative
136
+ ```
137
+
138
+ Match keys are non-empty field paths. Regex literals use Rust regex syntax and
139
+ support unique `i`, `m`, `s`, and `u` flags. `environment`, `runtime_group`, and
140
+ paths ending in `pattern_id` are platform-owned and cannot appear as authored
141
+ match fields. The runtime engine owns dotted-path traversal and actual gate
142
+ evaluation.
143
+
144
+ ## Diagnostics
145
+
146
+ Invalid recipe content is reported through the normal `Report`/`Diagnostic`
147
+ model. Judge diagnostics use stable `judge.*` codes, recipe-relative source
148
+ paths, useful help text, and deterministic ordering. YAML syntax failures use
149
+ `judge.yaml_malformed` and include a 1-based source span when the parser
150
+ provides one. Invalid definitions do not raise a separate content exception in
151
+ the Python binding; they return `Report(valid=False, ...)` like other recipe
152
+ errors.
@@ -0,0 +1,171 @@
1
+ # Runtime library
2
+
3
+ The Recipes runtime library turns Recipe source into a live Pi agent. It is a
4
+ library boundary, not a hosting framework.
5
+
6
+ ## The embedding ladder
7
+
8
+ ```text
9
+ resolveRecipe() read and resolve the portable package
10
+
11
+
12
+ createRecipeSession() construct the complete live Pi session
13
+
14
+ └── runRecipe() execute one turn and dispose
15
+ ```
16
+
17
+ Hosts should use the lowest layer that preserves their control.
18
+
19
+ ## `resolveRecipe`
20
+
21
+ ```ts
22
+ import { resolveRecipe } from "@introspection-ai/recipes/recipe";
23
+
24
+ const recipe = resolveRecipe({
25
+ recipeDir,
26
+ agentName,
27
+ });
28
+ ```
29
+
30
+ The result contains the selected agent, visible subagents, model settings,
31
+ tools, MCP policy, skills, prompts, extensions, and system-prompt composition.
32
+ It does not create a model client or start a session.
33
+
34
+ ## `createRecipeSession`
35
+
36
+ ```ts
37
+ import { createRecipeSession } from "@introspection-ai/recipes/session";
38
+
39
+ const handle = await createRecipeSession({
40
+ recipeDir,
41
+ agentName,
42
+ cwd: workspaceDir,
43
+ credentials,
44
+ modelOverride,
45
+ mcpBindings,
46
+ eventBus,
47
+ customTools,
48
+ extensionFactories,
49
+ runController,
50
+ agentToolOptions,
51
+ settingsManager,
52
+ sessionManager,
53
+ additionalSkillPaths,
54
+ skillPaths,
55
+ systemPrompt,
56
+ onDiagnostics,
57
+ onEvent,
58
+ otel: {
59
+ tracer,
60
+ meter,
61
+ meta: { conversationId },
62
+ runSpans: false,
63
+ getParentContext: () => currentTurnContext,
64
+ },
65
+ });
66
+ ```
67
+
68
+ This is the primary host integration point. It:
69
+
70
+ - resolves the Recipe and selected agent;
71
+ - resolves model credentials fail-closed;
72
+ - materializes required MCP bindings fail-closed;
73
+ - loads Recipe skills, prompts, and extensions;
74
+ - registers the shared subagent tool;
75
+ - creates and binds the Pi `AgentSession`;
76
+ - returns one idempotent `dispose()` boundary.
77
+
78
+ The returned `RecipeSessionHandle` exposes:
79
+
80
+ - `session` — Pi prompt, steer, follow-up, abort, messages, and events;
81
+ - `recipe` — the resolved portable definition;
82
+ - `runs` — the subagent run controller;
83
+ - `dispose()` — child, session, instrumentation, and MCP cleanup.
84
+
85
+ Host injection is intentional. A managed host can supply durable session state,
86
+ cross-process subagent execution, inline endpoint bindings, platform
87
+ extensions, its own settings, an event bus, host tools, and a
88
+ gateway-decorated model without reimplementing Recipe semantics. The Recipe
89
+ continues to own model configuration and tool selection; host seams replace
90
+ transport and materialized resources, not the portable definition.
91
+
92
+ Default MCP materialization leases the supplied `env` object until the handle
93
+ is disposed and restores its prior MCP/PATH state afterward. Concurrent
94
+ materialized sessions must receive separate environment objects. A host that
95
+ materializes one process-wide MCP runtime instead passes `mcpMode: "inherit"`
96
+ to its sessions, as runtime-agent does.
97
+
98
+ ## `runRecipe`
99
+
100
+ ```ts
101
+ import { runRecipe } from "@introspection-ai/recipes/run";
102
+
103
+ const result = await runRecipe({
104
+ recipeDir,
105
+ cwd: workspaceDir,
106
+ prompt,
107
+ timeoutMs: 120_000,
108
+ });
109
+ ```
110
+
111
+ `runRecipe` creates one session, executes one prompt, returns the transcript and
112
+ final text, and always disposes. It is suitable for tests, cron jobs, and queue
113
+ workers that do not need a durable conversational host.
114
+
115
+ ## Inspection
116
+
117
+ ```ts
118
+ import { inspectRecipe } from "@introspection-ai/recipes/inspect";
119
+
120
+ const requirements = inspectRecipe(recipeDir);
121
+ ```
122
+
123
+ Inspection derives agents, providers, expected credential variables, required
124
+ and optional MCP servers, and resource counts without creating a session.
125
+
126
+ ## OpenTelemetry
127
+
128
+ Pass a tracer through `otel` to attach the JS SDK's OpenTelemetry GenAI
129
+ semantic-convention instrumentation to the session. Recipes derives default
130
+ agent identity from the resolved package and generates a conversation id when
131
+ the host does not provide one. The default in-process subagent controller
132
+ inherits that conversation id while each child derives its own Recipe agent
133
+ identity. Injected run controllers own their child-session instrumentation.
134
+
135
+ Recipes does not create or register an OTel provider, processor, exporter, or
136
+ global context manager. The host owns that pipeline and its content policy. A
137
+ standalone host can therefore use the same standard OTLP exporter for
138
+ Braintrust, Langfuse, an OTel Collector, or another compatible backend. A host
139
+ that needs structure-only infrastructure traces can wrap that exporter with
140
+ `GenAiContentScrubbingExporter` from
141
+ `@introspection-sdk/introspection-pi`.
142
+
143
+ Short-lived hosts must flush their own provider after `runRecipe` completes;
144
+ long-lived hosts should flush and shut it down with the host lifecycle.
145
+
146
+ ## Host conformance
147
+
148
+ ```ts
149
+ import { hostConformanceCases } from "@introspection-ai/recipes/test-utils";
150
+
151
+ for (const testCase of hostConformanceCases(myHostAdapter)) {
152
+ it(testCase.name, testCase.run);
153
+ }
154
+ ```
155
+
156
+ Passing the suite means the host is using the same session construction
157
+ contract as Pi and Introspection. Protocol behavior, persistence, tenancy, and
158
+ deployment remain host-specific and require their own tests.
159
+
160
+ ## Deliberate non-features
161
+
162
+ The package does not provide:
163
+
164
+ - an HTTP server or wire protocol;
165
+ - a task database or task state machine;
166
+ - a scheduler or queue;
167
+ - sandbox or tenant isolation;
168
+ - a deployment CLI;
169
+ - provider-specific hosting adapters.
170
+
171
+ Those layers compose above `createRecipeSession`.
package/package.json ADDED
@@ -0,0 +1,106 @@
1
+ {
2
+ "name": "@introspection-ai/recipes",
3
+ "version": "0.13.0",
4
+ "description": "The open package format for complete, portable Pi agents.",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "engines": {
8
+ "node": ">=24"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "vendor/mcp-client",
13
+ "docs",
14
+ "README.md",
15
+ "package.json"
16
+ ],
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+ssh://git@github.com/introspection-org/pi-recipes.git"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/introspection-org/pi-recipes/issues"
23
+ },
24
+ "homepage": "https://github.com/introspection-org/pi-recipes#readme",
25
+ "publishConfig": {
26
+ "access": "public",
27
+ "tag": "latest"
28
+ },
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/index.d.ts",
32
+ "import": "./dist/index.js"
33
+ },
34
+ "./interactions": {
35
+ "types": "./dist/interactions.d.ts",
36
+ "import": "./dist/interactions.js"
37
+ },
38
+ "./pi-extension": {
39
+ "types": "./dist/pi-extension.d.ts",
40
+ "import": "./dist/pi-extension.js"
41
+ },
42
+ "./pi": {
43
+ "types": "./dist/agent-tool.d.ts",
44
+ "import": "./dist/agent-tool.js"
45
+ },
46
+ "./recipe": {
47
+ "types": "./dist/recipe/resolve.d.ts",
48
+ "import": "./dist/recipe/resolve.js"
49
+ },
50
+ "./session": {
51
+ "types": "./dist/session.d.ts",
52
+ "import": "./dist/session.js"
53
+ },
54
+ "./run": {
55
+ "types": "./dist/run.d.ts",
56
+ "import": "./dist/run.js"
57
+ },
58
+ "./test-utils": {
59
+ "types": "./dist/test-utils.d.ts",
60
+ "import": "./dist/test-utils.js"
61
+ },
62
+ "./inspect": {
63
+ "types": "./dist/inspect.d.ts",
64
+ "import": "./dist/inspect.js"
65
+ }
66
+ },
67
+ "pi": {
68
+ "extensions": [
69
+ "./dist/pi-extension.js"
70
+ ]
71
+ },
72
+ "dependencies": {
73
+ "@introspection-sdk/introspection-pi": "^0.13.0",
74
+ "@opentelemetry/api": "^1.9.1",
75
+ "mcporter": "0.12.3",
76
+ "yaml": "^2.9.0"
77
+ },
78
+ "peerDependencies": {
79
+ "@earendil-works/pi-agent-core": "^0.82.0",
80
+ "@earendil-works/pi-ai": "^0.82.0",
81
+ "@earendil-works/pi-coding-agent": "^0.82.0",
82
+ "@earendil-works/pi-tui": "^0.82.0",
83
+ "typebox": "*"
84
+ },
85
+ "devDependencies": {
86
+ "@earendil-works/pi-agent-core": "0.82.0",
87
+ "@earendil-works/pi-ai": "0.82.0",
88
+ "@earendil-works/pi-coding-agent": "0.82.0",
89
+ "@earendil-works/pi-tui": "0.82.0",
90
+ "@types/node": "^22.10.0",
91
+ "esbuild": "^0.28.1",
92
+ "typebox": "^1.0.56",
93
+ "typescript": "^5.7.3",
94
+ "vitest": "^4.0.18"
95
+ },
96
+ "scripts": {
97
+ "build": "pnpm build:ts && pnpm build:native",
98
+ "build:ts": "rm -rf dist && tsc && node scripts/build-mcp-daemon.mjs",
99
+ "build:native": "cargo build --release -p pi-mcp-client && node scripts/package-mcp-client.mjs",
100
+ "bench:mcp-client": "pnpm build:ts && cargo build --release -p pi-mcp-client && node scripts/benchmark-mcp-client.mjs",
101
+ "typecheck": "node scripts/check-recipe-check-versions.mjs && tsc --noEmit && tsc --noEmit -p tsconfig.test.json",
102
+ "test": "pnpm build:ts && cargo test -p pi-mcp-client -p pi-recipe-check && cargo build -p pi-mcp-client && MCP_CLIENT_BIN=target/debug/mcp-client node scripts/package-mcp-client.mjs && vitest run",
103
+ "pack:check": "pnpm pack --dry-run --json | node scripts/check-npm-pack.mjs",
104
+ "clean": "rm -rf dist .turbo node_modules target vendor/mcp-client"
105
+ }
106
+ }