@oh-my-pi/pi-coding-agent 1.337.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 (224) hide show
  1. package/CHANGELOG.md +1228 -0
  2. package/README.md +1041 -0
  3. package/docs/compaction.md +403 -0
  4. package/docs/custom-tools.md +541 -0
  5. package/docs/extension-loading.md +1004 -0
  6. package/docs/hooks.md +867 -0
  7. package/docs/rpc.md +1040 -0
  8. package/docs/sdk.md +994 -0
  9. package/docs/session-tree-plan.md +441 -0
  10. package/docs/session.md +240 -0
  11. package/docs/skills.md +290 -0
  12. package/docs/theme.md +637 -0
  13. package/docs/tree.md +197 -0
  14. package/docs/tui.md +341 -0
  15. package/examples/README.md +21 -0
  16. package/examples/custom-tools/README.md +124 -0
  17. package/examples/custom-tools/hello/index.ts +20 -0
  18. package/examples/custom-tools/question/index.ts +84 -0
  19. package/examples/custom-tools/subagent/README.md +172 -0
  20. package/examples/custom-tools/subagent/agents/planner.md +37 -0
  21. package/examples/custom-tools/subagent/agents/reviewer.md +35 -0
  22. package/examples/custom-tools/subagent/agents/scout.md +50 -0
  23. package/examples/custom-tools/subagent/agents/worker.md +24 -0
  24. package/examples/custom-tools/subagent/agents.ts +156 -0
  25. package/examples/custom-tools/subagent/commands/implement-and-review.md +10 -0
  26. package/examples/custom-tools/subagent/commands/implement.md +10 -0
  27. package/examples/custom-tools/subagent/commands/scout-and-plan.md +9 -0
  28. package/examples/custom-tools/subagent/index.ts +1002 -0
  29. package/examples/custom-tools/todo/index.ts +212 -0
  30. package/examples/hooks/README.md +56 -0
  31. package/examples/hooks/auto-commit-on-exit.ts +49 -0
  32. package/examples/hooks/confirm-destructive.ts +59 -0
  33. package/examples/hooks/custom-compaction.ts +116 -0
  34. package/examples/hooks/dirty-repo-guard.ts +52 -0
  35. package/examples/hooks/file-trigger.ts +41 -0
  36. package/examples/hooks/git-checkpoint.ts +53 -0
  37. package/examples/hooks/handoff.ts +150 -0
  38. package/examples/hooks/permission-gate.ts +34 -0
  39. package/examples/hooks/protected-paths.ts +30 -0
  40. package/examples/hooks/qna.ts +119 -0
  41. package/examples/hooks/snake.ts +343 -0
  42. package/examples/hooks/status-line.ts +40 -0
  43. package/examples/sdk/01-minimal.ts +22 -0
  44. package/examples/sdk/02-custom-model.ts +49 -0
  45. package/examples/sdk/03-custom-prompt.ts +44 -0
  46. package/examples/sdk/04-skills.ts +44 -0
  47. package/examples/sdk/05-tools.ts +90 -0
  48. package/examples/sdk/06-hooks.ts +61 -0
  49. package/examples/sdk/07-context-files.ts +36 -0
  50. package/examples/sdk/08-slash-commands.ts +42 -0
  51. package/examples/sdk/09-api-keys-and-oauth.ts +55 -0
  52. package/examples/sdk/10-settings.ts +38 -0
  53. package/examples/sdk/11-sessions.ts +48 -0
  54. package/examples/sdk/12-full-control.ts +95 -0
  55. package/examples/sdk/README.md +154 -0
  56. package/package.json +81 -0
  57. package/src/cli/args.ts +246 -0
  58. package/src/cli/file-processor.ts +72 -0
  59. package/src/cli/list-models.ts +104 -0
  60. package/src/cli/plugin-cli.ts +650 -0
  61. package/src/cli/session-picker.ts +41 -0
  62. package/src/cli.ts +10 -0
  63. package/src/commands/init.md +20 -0
  64. package/src/config.ts +159 -0
  65. package/src/core/agent-session.ts +1900 -0
  66. package/src/core/auth-storage.ts +236 -0
  67. package/src/core/bash-executor.ts +196 -0
  68. package/src/core/compaction/branch-summarization.ts +343 -0
  69. package/src/core/compaction/compaction.ts +742 -0
  70. package/src/core/compaction/index.ts +7 -0
  71. package/src/core/compaction/utils.ts +154 -0
  72. package/src/core/custom-tools/index.ts +21 -0
  73. package/src/core/custom-tools/loader.ts +248 -0
  74. package/src/core/custom-tools/types.ts +169 -0
  75. package/src/core/custom-tools/wrapper.ts +28 -0
  76. package/src/core/exec.ts +129 -0
  77. package/src/core/export-html/index.ts +211 -0
  78. package/src/core/export-html/template.css +781 -0
  79. package/src/core/export-html/template.html +54 -0
  80. package/src/core/export-html/template.js +1185 -0
  81. package/src/core/export-html/vendor/highlight.min.js +1213 -0
  82. package/src/core/export-html/vendor/marked.min.js +6 -0
  83. package/src/core/hooks/index.ts +16 -0
  84. package/src/core/hooks/loader.ts +312 -0
  85. package/src/core/hooks/runner.ts +434 -0
  86. package/src/core/hooks/tool-wrapper.ts +99 -0
  87. package/src/core/hooks/types.ts +773 -0
  88. package/src/core/index.ts +52 -0
  89. package/src/core/mcp/client.ts +158 -0
  90. package/src/core/mcp/config.ts +154 -0
  91. package/src/core/mcp/index.ts +45 -0
  92. package/src/core/mcp/loader.ts +68 -0
  93. package/src/core/mcp/manager.ts +181 -0
  94. package/src/core/mcp/tool-bridge.ts +148 -0
  95. package/src/core/mcp/transports/http.ts +316 -0
  96. package/src/core/mcp/transports/index.ts +6 -0
  97. package/src/core/mcp/transports/stdio.ts +252 -0
  98. package/src/core/mcp/types.ts +220 -0
  99. package/src/core/messages.ts +189 -0
  100. package/src/core/model-registry.ts +317 -0
  101. package/src/core/model-resolver.ts +393 -0
  102. package/src/core/plugins/doctor.ts +59 -0
  103. package/src/core/plugins/index.ts +38 -0
  104. package/src/core/plugins/installer.ts +189 -0
  105. package/src/core/plugins/loader.ts +338 -0
  106. package/src/core/plugins/manager.ts +672 -0
  107. package/src/core/plugins/parser.ts +105 -0
  108. package/src/core/plugins/paths.ts +32 -0
  109. package/src/core/plugins/types.ts +190 -0
  110. package/src/core/sdk.ts +760 -0
  111. package/src/core/session-manager.ts +1128 -0
  112. package/src/core/settings-manager.ts +443 -0
  113. package/src/core/skills.ts +437 -0
  114. package/src/core/slash-commands.ts +248 -0
  115. package/src/core/system-prompt.ts +439 -0
  116. package/src/core/timings.ts +25 -0
  117. package/src/core/tools/ask.ts +211 -0
  118. package/src/core/tools/bash-interceptor.ts +120 -0
  119. package/src/core/tools/bash.ts +250 -0
  120. package/src/core/tools/context.ts +32 -0
  121. package/src/core/tools/edit-diff.ts +475 -0
  122. package/src/core/tools/edit.ts +208 -0
  123. package/src/core/tools/exa/company.ts +59 -0
  124. package/src/core/tools/exa/index.ts +64 -0
  125. package/src/core/tools/exa/linkedin.ts +59 -0
  126. package/src/core/tools/exa/logger.ts +56 -0
  127. package/src/core/tools/exa/mcp-client.ts +368 -0
  128. package/src/core/tools/exa/render.ts +196 -0
  129. package/src/core/tools/exa/researcher.ts +90 -0
  130. package/src/core/tools/exa/search.ts +337 -0
  131. package/src/core/tools/exa/types.ts +168 -0
  132. package/src/core/tools/exa/websets.ts +248 -0
  133. package/src/core/tools/find.ts +261 -0
  134. package/src/core/tools/grep.ts +555 -0
  135. package/src/core/tools/index.ts +202 -0
  136. package/src/core/tools/ls.ts +140 -0
  137. package/src/core/tools/lsp/client.ts +605 -0
  138. package/src/core/tools/lsp/config.ts +147 -0
  139. package/src/core/tools/lsp/edits.ts +101 -0
  140. package/src/core/tools/lsp/index.ts +804 -0
  141. package/src/core/tools/lsp/render.ts +447 -0
  142. package/src/core/tools/lsp/rust-analyzer.ts +145 -0
  143. package/src/core/tools/lsp/types.ts +463 -0
  144. package/src/core/tools/lsp/utils.ts +486 -0
  145. package/src/core/tools/notebook.ts +229 -0
  146. package/src/core/tools/path-utils.ts +61 -0
  147. package/src/core/tools/read.ts +240 -0
  148. package/src/core/tools/renderers.ts +540 -0
  149. package/src/core/tools/task/agents.ts +153 -0
  150. package/src/core/tools/task/artifacts.ts +114 -0
  151. package/src/core/tools/task/bundled-agents/browser.md +71 -0
  152. package/src/core/tools/task/bundled-agents/explore.md +82 -0
  153. package/src/core/tools/task/bundled-agents/plan.md +54 -0
  154. package/src/core/tools/task/bundled-agents/reviewer.md +59 -0
  155. package/src/core/tools/task/bundled-agents/task.md +53 -0
  156. package/src/core/tools/task/bundled-commands/architect-plan.md +10 -0
  157. package/src/core/tools/task/bundled-commands/implement-with-critic.md +11 -0
  158. package/src/core/tools/task/bundled-commands/implement.md +11 -0
  159. package/src/core/tools/task/commands.ts +213 -0
  160. package/src/core/tools/task/discovery.ts +208 -0
  161. package/src/core/tools/task/executor.ts +367 -0
  162. package/src/core/tools/task/index.ts +388 -0
  163. package/src/core/tools/task/model-resolver.ts +115 -0
  164. package/src/core/tools/task/parallel.ts +38 -0
  165. package/src/core/tools/task/render.ts +232 -0
  166. package/src/core/tools/task/types.ts +99 -0
  167. package/src/core/tools/truncate.ts +265 -0
  168. package/src/core/tools/web-fetch.ts +2370 -0
  169. package/src/core/tools/web-search/auth.ts +193 -0
  170. package/src/core/tools/web-search/index.ts +537 -0
  171. package/src/core/tools/web-search/providers/anthropic.ts +198 -0
  172. package/src/core/tools/web-search/providers/exa.ts +302 -0
  173. package/src/core/tools/web-search/providers/perplexity.ts +195 -0
  174. package/src/core/tools/web-search/render.ts +182 -0
  175. package/src/core/tools/web-search/types.ts +180 -0
  176. package/src/core/tools/write.ts +99 -0
  177. package/src/index.ts +176 -0
  178. package/src/main.ts +464 -0
  179. package/src/migrations.ts +135 -0
  180. package/src/modes/index.ts +43 -0
  181. package/src/modes/interactive/components/armin.ts +382 -0
  182. package/src/modes/interactive/components/assistant-message.ts +86 -0
  183. package/src/modes/interactive/components/bash-execution.ts +196 -0
  184. package/src/modes/interactive/components/bordered-loader.ts +41 -0
  185. package/src/modes/interactive/components/branch-summary-message.ts +42 -0
  186. package/src/modes/interactive/components/compaction-summary-message.ts +45 -0
  187. package/src/modes/interactive/components/custom-editor.ts +122 -0
  188. package/src/modes/interactive/components/diff.ts +147 -0
  189. package/src/modes/interactive/components/dynamic-border.ts +25 -0
  190. package/src/modes/interactive/components/footer.ts +381 -0
  191. package/src/modes/interactive/components/hook-editor.ts +117 -0
  192. package/src/modes/interactive/components/hook-input.ts +64 -0
  193. package/src/modes/interactive/components/hook-message.ts +96 -0
  194. package/src/modes/interactive/components/hook-selector.ts +91 -0
  195. package/src/modes/interactive/components/model-selector.ts +247 -0
  196. package/src/modes/interactive/components/oauth-selector.ts +120 -0
  197. package/src/modes/interactive/components/plugin-settings.ts +479 -0
  198. package/src/modes/interactive/components/queue-mode-selector.ts +56 -0
  199. package/src/modes/interactive/components/session-selector.ts +204 -0
  200. package/src/modes/interactive/components/settings-selector.ts +453 -0
  201. package/src/modes/interactive/components/show-images-selector.ts +45 -0
  202. package/src/modes/interactive/components/theme-selector.ts +62 -0
  203. package/src/modes/interactive/components/thinking-selector.ts +64 -0
  204. package/src/modes/interactive/components/tool-execution.ts +675 -0
  205. package/src/modes/interactive/components/tree-selector.ts +866 -0
  206. package/src/modes/interactive/components/user-message-selector.ts +159 -0
  207. package/src/modes/interactive/components/user-message.ts +18 -0
  208. package/src/modes/interactive/components/visual-truncate.ts +50 -0
  209. package/src/modes/interactive/components/welcome.ts +183 -0
  210. package/src/modes/interactive/interactive-mode.ts +2516 -0
  211. package/src/modes/interactive/theme/dark.json +101 -0
  212. package/src/modes/interactive/theme/light.json +98 -0
  213. package/src/modes/interactive/theme/theme-schema.json +308 -0
  214. package/src/modes/interactive/theme/theme.ts +998 -0
  215. package/src/modes/print-mode.ts +128 -0
  216. package/src/modes/rpc/rpc-client.ts +527 -0
  217. package/src/modes/rpc/rpc-mode.ts +483 -0
  218. package/src/modes/rpc/rpc-types.ts +203 -0
  219. package/src/utils/changelog.ts +99 -0
  220. package/src/utils/clipboard.ts +265 -0
  221. package/src/utils/fuzzy.ts +108 -0
  222. package/src/utils/mime.ts +30 -0
  223. package/src/utils/shell.ts +276 -0
  224. package/src/utils/tools-manager.ts +274 -0
package/docs/sdk.md ADDED
@@ -0,0 +1,994 @@
1
+ > pi can help you use the SDK. Ask it to build an integration for your use case.
2
+
3
+ # SDK
4
+
5
+ The SDK provides programmatic access to pi's agent capabilities. Use it to embed pi in other applications, build custom interfaces, or integrate with automated workflows.
6
+
7
+ **Example use cases:**
8
+
9
+ - Build a custom UI (web, desktop, mobile)
10
+ - Integrate agent capabilities into existing applications
11
+ - Create automated pipelines with agent reasoning
12
+ - Build custom tools that spawn sub-agents
13
+ - Test agent behavior programmatically
14
+
15
+ See [examples/sdk/](../examples/sdk/) for working examples from minimal to full control.
16
+
17
+ ## Quick Start
18
+
19
+ ```typescript
20
+ import { createAgentSession, discoverAuthStorage, discoverModels, SessionManager } from "@oh-my-pi/pi-coding-agent";
21
+
22
+ // Set up credential storage and model registry
23
+ const authStorage = discoverAuthStorage();
24
+ const modelRegistry = discoverModels(authStorage);
25
+
26
+ const { session } = await createAgentSession({
27
+ sessionManager: SessionManager.inMemory(),
28
+ authStorage,
29
+ modelRegistry,
30
+ });
31
+
32
+ session.subscribe((event) => {
33
+ if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
34
+ process.stdout.write(event.assistantMessageEvent.delta);
35
+ }
36
+ });
37
+
38
+ await session.prompt("What files are in the current directory?");
39
+ ```
40
+
41
+ ## Installation
42
+
43
+ ```bash
44
+ npm install @oh-my-pi/pi-coding-agent
45
+ ```
46
+
47
+ The SDK is included in the main package. No separate installation needed.
48
+
49
+ ## Core Concepts
50
+
51
+ ### createAgentSession()
52
+
53
+ The main factory function. Creates an `AgentSession` with configurable options.
54
+
55
+ **Philosophy:** "Omit to discover, provide to override."
56
+
57
+ - Omit an option → pi discovers/loads from standard locations
58
+ - Provide an option → your value is used, discovery skipped for that option
59
+
60
+ ```typescript
61
+ import { createAgentSession } from "@oh-my-pi/pi-coding-agent";
62
+
63
+ // Minimal: all defaults (discovers everything from cwd and ~/.pi/agent)
64
+ const { session } = await createAgentSession();
65
+
66
+ // Custom: override specific options
67
+ const { session } = await createAgentSession({
68
+ model: myModel,
69
+ systemPrompt: "You are helpful.",
70
+ tools: [readTool, bashTool],
71
+ sessionManager: SessionManager.inMemory(),
72
+ });
73
+ ```
74
+
75
+ ### AgentSession
76
+
77
+ The session manages the agent lifecycle, message history, and event streaming.
78
+
79
+ ```typescript
80
+ interface AgentSession {
81
+ // Send a prompt and wait for completion
82
+ prompt(text: string, options?: PromptOptions): Promise<void>;
83
+
84
+ // Subscribe to events (returns unsubscribe function)
85
+ subscribe(listener: (event: AgentSessionEvent) => void): () => void;
86
+
87
+ // Session info
88
+ sessionFile: string | undefined; // undefined for in-memory
89
+ sessionId: string;
90
+
91
+ // Model control
92
+ setModel(model: Model): Promise<void>;
93
+ setThinkingLevel(level: ThinkingLevel): void;
94
+ cycleModel(): Promise<ModelCycleResult | undefined>;
95
+ cycleThinkingLevel(): ThinkingLevel | undefined;
96
+
97
+ // State access
98
+ agent: Agent;
99
+ model: Model | undefined;
100
+ thinkingLevel: ThinkingLevel;
101
+ messages: AgentMessage[];
102
+ isStreaming: boolean;
103
+
104
+ // Session management
105
+ newSession(options?: { parentSession?: string }): Promise<boolean>; // Returns false if cancelled by hook
106
+ switchSession(sessionPath: string): Promise<boolean>;
107
+
108
+ // Branching
109
+ branch(entryId: string): Promise<{ selectedText: string; cancelled: boolean }>; // Creates new session file
110
+ navigateTree(
111
+ targetId: string,
112
+ options?: { summarize?: boolean }
113
+ ): Promise<{ editorText?: string; cancelled: boolean }>; // In-place navigation
114
+
115
+ // Hook message injection
116
+ sendHookMessage(message: HookMessage, triggerTurn?: boolean): Promise<void>;
117
+
118
+ // Compaction
119
+ compact(customInstructions?: string): Promise<CompactionResult>;
120
+ abortCompaction(): void;
121
+
122
+ // Abort current operation
123
+ abort(): Promise<void>;
124
+
125
+ // Cleanup
126
+ dispose(): void;
127
+ }
128
+ ```
129
+
130
+ ### Agent and AgentState
131
+
132
+ The `Agent` class (from `@oh-my-pi/pi-agent-core`) handles the core LLM interaction. Access it via `session.agent`.
133
+
134
+ ```typescript
135
+ // Access current state
136
+ const state = session.agent.state;
137
+
138
+ // state.messages: AgentMessage[] - conversation history
139
+ // state.model: Model - current model
140
+ // state.thinkingLevel: ThinkingLevel - current thinking level
141
+ // state.systemPrompt: string - system prompt
142
+ // state.tools: Tool[] - available tools
143
+
144
+ // Replace messages (useful for branching, restoration)
145
+ session.agent.replaceMessages(messages);
146
+
147
+ // Wait for agent to finish processing
148
+ await session.agent.waitForIdle();
149
+ ```
150
+
151
+ ### Events
152
+
153
+ Subscribe to events to receive streaming output and lifecycle notifications.
154
+
155
+ ```typescript
156
+ session.subscribe((event) => {
157
+ switch (event.type) {
158
+ // Streaming text from assistant
159
+ case "message_update":
160
+ if (event.assistantMessageEvent.type === "text_delta") {
161
+ process.stdout.write(event.assistantMessageEvent.delta);
162
+ }
163
+ if (event.assistantMessageEvent.type === "thinking_delta") {
164
+ // Thinking output (if thinking enabled)
165
+ }
166
+ break;
167
+
168
+ // Tool execution
169
+ case "tool_execution_start":
170
+ console.log(`Tool: ${event.toolName}`);
171
+ break;
172
+ case "tool_execution_update":
173
+ // Streaming tool output
174
+ break;
175
+ case "tool_execution_end":
176
+ console.log(`Result: ${event.isError ? "error" : "success"}`);
177
+ break;
178
+
179
+ // Message lifecycle
180
+ case "message_start":
181
+ // New message starting
182
+ break;
183
+ case "message_end":
184
+ // Message complete
185
+ break;
186
+
187
+ // Agent lifecycle
188
+ case "agent_start":
189
+ // Agent started processing prompt
190
+ break;
191
+ case "agent_end":
192
+ // Agent finished (event.messages contains new messages)
193
+ break;
194
+
195
+ // Turn lifecycle (one LLM response + tool calls)
196
+ case "turn_start":
197
+ break;
198
+ case "turn_end":
199
+ // event.message: assistant response
200
+ // event.toolResults: tool results from this turn
201
+ break;
202
+
203
+ // Session events (auto-compaction, retry)
204
+ case "auto_compaction_start":
205
+ case "auto_compaction_end":
206
+ case "auto_retry_start":
207
+ case "auto_retry_end":
208
+ break;
209
+ }
210
+ });
211
+ ```
212
+
213
+ ## Options Reference
214
+
215
+ ### Directories
216
+
217
+ ```typescript
218
+ const { session } = await createAgentSession({
219
+ // Working directory for project-local discovery
220
+ cwd: process.cwd(), // default
221
+
222
+ // Global config directory
223
+ agentDir: "~/.pi/agent", // default (expands ~)
224
+ });
225
+ ```
226
+
227
+ `cwd` is used for:
228
+
229
+ - Project hooks (`.pi/hooks/`)
230
+ - Project tools (`.pi/tools/`)
231
+ - Project skills (`.pi/skills/`)
232
+ - Project commands (`.pi/commands/`)
233
+ - Context files (`AGENTS.md` walking up from cwd)
234
+ - Session directory naming
235
+
236
+ `agentDir` is used for:
237
+
238
+ - Global hooks (`hooks/`)
239
+ - Global tools (`tools/`)
240
+ - Global skills (`skills/`)
241
+ - Global commands (`commands/`)
242
+ - Global context file (`AGENTS.md`)
243
+ - Settings (`settings.json`)
244
+ - Custom models (`models.json`)
245
+ - Credentials (`auth.json`)
246
+ - Sessions (`sessions/`)
247
+
248
+ ### Model
249
+
250
+ ```typescript
251
+ import { getModel } from "@oh-my-pi/pi-ai";
252
+ import { discoverAuthStorage, discoverModels } from "@oh-my-pi/pi-coding-agent";
253
+
254
+ const authStorage = discoverAuthStorage();
255
+ const modelRegistry = discoverModels(authStorage);
256
+
257
+ // Find specific built-in model (doesn't check if API key exists)
258
+ const opus = getModel("anthropic", "claude-opus-4-5");
259
+ if (!opus) throw new Error("Model not found");
260
+
261
+ // Find any model by provider/id, including custom models from models.json
262
+ // (doesn't check if API key exists)
263
+ const customModel = modelRegistry.find("my-provider", "my-model");
264
+
265
+ // Get only models that have valid API keys configured
266
+ const available = await modelRegistry.getAvailable();
267
+
268
+ const { session } = await createAgentSession({
269
+ model: opus,
270
+ thinkingLevel: "medium", // off, minimal, low, medium, high, xhigh
271
+
272
+ // Models for cycling (Ctrl+P in interactive mode)
273
+ scopedModels: [
274
+ { model: opus, thinkingLevel: "high" },
275
+ { model: haiku, thinkingLevel: "off" },
276
+ ],
277
+
278
+ authStorage,
279
+ modelRegistry,
280
+ });
281
+ ```
282
+
283
+ If no model is provided:
284
+
285
+ 1. Tries to restore from session (if continuing)
286
+ 2. Uses default from settings
287
+ 3. Falls back to first available model
288
+
289
+ > See [examples/sdk/02-custom-model.ts](../examples/sdk/02-custom-model.ts)
290
+
291
+ ### API Keys and OAuth
292
+
293
+ API key resolution priority (handled by AuthStorage):
294
+
295
+ 1. Runtime overrides (via `setRuntimeApiKey`, not persisted)
296
+ 2. Stored credentials in `auth.json` (API keys or OAuth tokens)
297
+ 3. Environment variables (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, etc.)
298
+ 4. Fallback resolver (for custom provider keys from `models.json`)
299
+
300
+ ```typescript
301
+ import { AuthStorage, ModelRegistry, discoverAuthStorage, discoverModels } from "@oh-my-pi/pi-coding-agent";
302
+
303
+ // Default: uses ~/.pi/agent/auth.json and ~/.pi/agent/models.json
304
+ const authStorage = discoverAuthStorage();
305
+ const modelRegistry = discoverModels(authStorage);
306
+
307
+ const { session } = await createAgentSession({
308
+ sessionManager: SessionManager.inMemory(),
309
+ authStorage,
310
+ modelRegistry,
311
+ });
312
+
313
+ // Runtime API key override (not persisted to disk)
314
+ authStorage.setRuntimeApiKey("anthropic", "sk-my-temp-key");
315
+
316
+ // Custom auth storage location
317
+ const customAuth = new AuthStorage("/my/app/auth.json");
318
+ const customRegistry = new ModelRegistry(customAuth, "/my/app/models.json");
319
+
320
+ const { session } = await createAgentSession({
321
+ sessionManager: SessionManager.inMemory(),
322
+ authStorage: customAuth,
323
+ modelRegistry: customRegistry,
324
+ });
325
+
326
+ // No custom models.json (built-in models only)
327
+ const simpleRegistry = new ModelRegistry(authStorage);
328
+ ```
329
+
330
+ > See [examples/sdk/09-api-keys-and-oauth.ts](../examples/sdk/09-api-keys-and-oauth.ts)
331
+
332
+ ### System Prompt
333
+
334
+ ```typescript
335
+ const { session } = await createAgentSession({
336
+ // Replace entirely
337
+ systemPrompt: "You are a helpful assistant.",
338
+
339
+ // Or modify default (receives default, returns modified)
340
+ systemPrompt: (defaultPrompt) => {
341
+ return `${defaultPrompt}\n\n## Additional Rules\n- Be concise`;
342
+ },
343
+ });
344
+ ```
345
+
346
+ > See [examples/sdk/03-custom-prompt.ts](../examples/sdk/03-custom-prompt.ts)
347
+
348
+ ### Tools
349
+
350
+ ```typescript
351
+ import {
352
+ codingTools, // read, bash, edit, write (default)
353
+ readOnlyTools, // read, grep, find, ls
354
+ readTool,
355
+ bashTool,
356
+ editTool,
357
+ writeTool,
358
+ grepTool,
359
+ findTool,
360
+ lsTool,
361
+ } from "@oh-my-pi/pi-coding-agent";
362
+
363
+ // Use built-in tool set
364
+ const { session } = await createAgentSession({
365
+ tools: readOnlyTools,
366
+ });
367
+
368
+ // Pick specific tools
369
+ const { session } = await createAgentSession({
370
+ tools: [readTool, bashTool, grepTool],
371
+ });
372
+ ```
373
+
374
+ #### Tools with Custom cwd
375
+
376
+ **Important:** The pre-built tool instances (`readTool`, `bashTool`, etc.) use `process.cwd()` for path resolution. When you specify a custom `cwd` AND provide explicit `tools`, you must use the tool factory functions to ensure paths resolve correctly:
377
+
378
+ ```typescript
379
+ import {
380
+ createCodingTools, // Creates [read, bash, edit, write] for specific cwd
381
+ createReadOnlyTools, // Creates [read, grep, find, ls] for specific cwd
382
+ createReadTool,
383
+ createBashTool,
384
+ createEditTool,
385
+ createWriteTool,
386
+ createGrepTool,
387
+ createFindTool,
388
+ createLsTool,
389
+ } from "@oh-my-pi/pi-coding-agent";
390
+
391
+ const cwd = "/path/to/project";
392
+
393
+ // Use factory for tool sets
394
+ const { session } = await createAgentSession({
395
+ cwd,
396
+ tools: createCodingTools(cwd), // Tools resolve paths relative to cwd
397
+ });
398
+
399
+ // Or pick specific tools
400
+ const { session } = await createAgentSession({
401
+ cwd,
402
+ tools: [createReadTool(cwd), createBashTool(cwd), createGrepTool(cwd)],
403
+ });
404
+ ```
405
+
406
+ **When you don't need factories:**
407
+
408
+ - If you omit `tools`, pi automatically creates them with the correct `cwd`
409
+ - If you use `process.cwd()` as your `cwd`, the pre-built instances work fine
410
+
411
+ **When you must use factories:**
412
+
413
+ - When you specify both `cwd` (different from `process.cwd()`) AND `tools`
414
+
415
+ > See [examples/sdk/05-tools.ts](../examples/sdk/05-tools.ts)
416
+
417
+ ### Custom Tools
418
+
419
+ ```typescript
420
+ import { Type } from "@sinclair/typebox";
421
+ import { createAgentSession, discoverCustomTools, type CustomTool } from "@oh-my-pi/pi-coding-agent";
422
+
423
+ // Inline custom tool
424
+ const myTool: CustomTool = {
425
+ name: "my_tool",
426
+ label: "My Tool",
427
+ description: "Does something useful",
428
+ parameters: Type.Object({
429
+ input: Type.String({ description: "Input value" }),
430
+ }),
431
+ execute: async (toolCallId, params) => ({
432
+ content: [{ type: "text", text: `Result: ${params.input}` }],
433
+ details: {},
434
+ }),
435
+ };
436
+
437
+ // Replace discovery with inline tools
438
+ const { session } = await createAgentSession({
439
+ customTools: [{ tool: myTool }],
440
+ });
441
+
442
+ // Merge with discovered tools
443
+ const discovered = await discoverCustomTools();
444
+ const { session } = await createAgentSession({
445
+ customTools: [...discovered, { tool: myTool }],
446
+ });
447
+
448
+ // Add paths without replacing discovery
449
+ const { session } = await createAgentSession({
450
+ additionalCustomToolPaths: ["/extra/tools"],
451
+ });
452
+ ```
453
+
454
+ > See [examples/sdk/05-tools.ts](../examples/sdk/05-tools.ts)
455
+
456
+ ### Hooks
457
+
458
+ ```typescript
459
+ import { createAgentSession, discoverHooks, type HookFactory } from "@oh-my-pi/pi-coding-agent";
460
+
461
+ // Inline hook
462
+ const loggingHook: HookFactory = (api) => {
463
+ // Log tool calls
464
+ api.on("tool_call", async (event) => {
465
+ console.log(`Tool: ${event.toolName}`);
466
+ return undefined; // Don't block
467
+ });
468
+
469
+ // Block dangerous commands
470
+ api.on("tool_call", async (event) => {
471
+ if (event.toolName === "bash" && event.input.command?.includes("rm -rf")) {
472
+ return { block: true, reason: "Dangerous command" };
473
+ }
474
+ return undefined;
475
+ });
476
+
477
+ // Register custom slash command
478
+ api.registerCommand("stats", {
479
+ description: "Show session stats",
480
+ handler: async (ctx) => {
481
+ const entries = ctx.sessionManager.getEntries();
482
+ ctx.ui.notify(`${entries.length} entries`, "info");
483
+ },
484
+ });
485
+
486
+ // Inject messages
487
+ api.sendMessage(
488
+ {
489
+ customType: "my-hook",
490
+ content: "Hook initialized",
491
+ display: false, // Hidden from TUI
492
+ },
493
+ false
494
+ ); // Don't trigger agent turn
495
+
496
+ // Persist hook state
497
+ api.appendEntry("my-hook", { initialized: true });
498
+ };
499
+
500
+ // Replace discovery
501
+ const { session } = await createAgentSession({
502
+ hooks: [{ factory: loggingHook }],
503
+ });
504
+
505
+ // Disable all hooks
506
+ const { session } = await createAgentSession({
507
+ hooks: [],
508
+ });
509
+
510
+ // Merge with discovered
511
+ const discovered = await discoverHooks();
512
+ const { session } = await createAgentSession({
513
+ hooks: [...discovered, { factory: loggingHook }],
514
+ });
515
+
516
+ // Add paths without replacing
517
+ const { session } = await createAgentSession({
518
+ additionalHookPaths: ["/extra/hooks"],
519
+ });
520
+ ```
521
+
522
+ Hook API methods:
523
+
524
+ - `api.on(event, handler)` - Subscribe to events
525
+ - `api.sendMessage(message, triggerTurn?)` - Inject message (creates `CustomMessageEntry`)
526
+ - `api.appendEntry(customType, data?)` - Persist hook state (not in LLM context)
527
+ - `api.registerCommand(name, options)` - Register custom slash command
528
+ - `api.registerMessageRenderer(customType, renderer)` - Custom TUI rendering
529
+ - `api.exec(command, args, options?)` - Execute shell commands
530
+
531
+ > See [examples/sdk/06-hooks.ts](../examples/sdk/06-hooks.ts) and [docs/hooks.md](hooks.md)
532
+
533
+ ### Skills
534
+
535
+ ```typescript
536
+ import { createAgentSession, discoverSkills, type Skill } from "@oh-my-pi/pi-coding-agent";
537
+
538
+ // Discover and filter
539
+ const allSkills = discoverSkills();
540
+ const filtered = allSkills.filter((s) => s.name.includes("search"));
541
+
542
+ // Custom skill
543
+ const mySkill: Skill = {
544
+ name: "my-skill",
545
+ description: "Custom instructions",
546
+ filePath: "/path/to/SKILL.md",
547
+ baseDir: "/path/to",
548
+ source: "custom",
549
+ };
550
+
551
+ const { session } = await createAgentSession({
552
+ skills: [...filtered, mySkill],
553
+ });
554
+
555
+ // Disable skills
556
+ const { session } = await createAgentSession({
557
+ skills: [],
558
+ });
559
+
560
+ // Discovery with settings filter
561
+ const skills = discoverSkills(process.cwd(), undefined, {
562
+ ignoredSkills: ["browser-*"], // glob patterns to exclude
563
+ includeSkills: ["search-*"], // glob patterns to include (empty = all)
564
+ });
565
+ ```
566
+
567
+ > See [examples/sdk/04-skills.ts](../examples/sdk/04-skills.ts)
568
+
569
+ ### Context Files
570
+
571
+ ```typescript
572
+ import { createAgentSession, discoverContextFiles } from "@oh-my-pi/pi-coding-agent";
573
+
574
+ // Discover AGENTS.md files
575
+ const discovered = discoverContextFiles();
576
+
577
+ // Add custom context
578
+ const { session } = await createAgentSession({
579
+ contextFiles: [
580
+ ...discovered,
581
+ {
582
+ path: "/virtual/AGENTS.md",
583
+ content: "# Guidelines\n\n- Be concise\n- Use TypeScript",
584
+ },
585
+ ],
586
+ });
587
+
588
+ // Disable context files
589
+ const { session } = await createAgentSession({
590
+ contextFiles: [],
591
+ });
592
+ ```
593
+
594
+ > See [examples/sdk/07-context-files.ts](../examples/sdk/07-context-files.ts)
595
+
596
+ ### Slash Commands
597
+
598
+ ```typescript
599
+ import { createAgentSession, discoverSlashCommands, type FileSlashCommand } from "@oh-my-pi/pi-coding-agent";
600
+
601
+ const discovered = discoverSlashCommands();
602
+
603
+ const customCommand: FileSlashCommand = {
604
+ name: "deploy",
605
+ description: "Deploy the application",
606
+ source: "(custom)",
607
+ content: "# Deploy\n\n1. Build\n2. Test\n3. Deploy",
608
+ };
609
+
610
+ const { session } = await createAgentSession({
611
+ slashCommands: [...discovered, customCommand],
612
+ });
613
+ ```
614
+
615
+ > See [examples/sdk/08-slash-commands.ts](../examples/sdk/08-slash-commands.ts)
616
+
617
+ ### Session Management
618
+
619
+ Sessions use a tree structure with `id`/`parentId` linking, enabling in-place branching.
620
+
621
+ ```typescript
622
+ import { createAgentSession, SessionManager } from "@oh-my-pi/pi-coding-agent";
623
+
624
+ // In-memory (no persistence)
625
+ const { session } = await createAgentSession({
626
+ sessionManager: SessionManager.inMemory(),
627
+ });
628
+
629
+ // New persistent session
630
+ const { session } = await createAgentSession({
631
+ sessionManager: SessionManager.create(process.cwd()),
632
+ });
633
+
634
+ // Continue most recent
635
+ const { session, modelFallbackMessage } = await createAgentSession({
636
+ sessionManager: SessionManager.continueRecent(process.cwd()),
637
+ });
638
+ if (modelFallbackMessage) {
639
+ console.log("Note:", modelFallbackMessage);
640
+ }
641
+
642
+ // Open specific file
643
+ const { session } = await createAgentSession({
644
+ sessionManager: SessionManager.open("/path/to/session.jsonl"),
645
+ });
646
+
647
+ // List available sessions
648
+ const sessions = SessionManager.list(process.cwd());
649
+ for (const info of sessions) {
650
+ console.log(`${info.id}: ${info.firstMessage} (${info.messageCount} messages)`);
651
+ }
652
+
653
+ // Custom session directory (no cwd encoding)
654
+ const customDir = "/path/to/my-sessions";
655
+ const { session } = await createAgentSession({
656
+ sessionManager: SessionManager.create(process.cwd(), customDir),
657
+ });
658
+ ```
659
+
660
+ **SessionManager tree API:**
661
+
662
+ ```typescript
663
+ const sm = SessionManager.open("/path/to/session.jsonl");
664
+
665
+ // Tree traversal
666
+ const entries = sm.getEntries(); // All entries (excludes header)
667
+ const tree = sm.getTree(); // Full tree structure
668
+ const path = sm.getPath(); // Path from root to current leaf
669
+ const leaf = sm.getLeafEntry(); // Current leaf entry
670
+ const entry = sm.getEntry(id); // Get entry by ID
671
+ const children = sm.getChildren(id); // Direct children of entry
672
+
673
+ // Labels
674
+ const label = sm.getLabel(id); // Get label for entry
675
+ sm.appendLabelChange(id, "checkpoint"); // Set label
676
+
677
+ // Branching
678
+ sm.branch(entryId); // Move leaf to earlier entry
679
+ sm.branchWithSummary(id, "Summary..."); // Branch with context summary
680
+ sm.createBranchedSession(leafId); // Extract path to new file
681
+ ```
682
+
683
+ > See [examples/sdk/11-sessions.ts](../examples/sdk/11-sessions.ts) and [docs/session.md](session.md)
684
+
685
+ ### Settings Management
686
+
687
+ ```typescript
688
+ import { createAgentSession, SettingsManager, SessionManager } from "@oh-my-pi/pi-coding-agent";
689
+
690
+ // Default: loads from files (global + project merged)
691
+ const { session } = await createAgentSession({
692
+ settingsManager: SettingsManager.create(),
693
+ });
694
+
695
+ // With overrides
696
+ const settingsManager = SettingsManager.create();
697
+ settingsManager.applyOverrides({
698
+ compaction: { enabled: false },
699
+ retry: { enabled: true, maxRetries: 5 },
700
+ });
701
+ const { session } = await createAgentSession({ settingsManager });
702
+
703
+ // In-memory (no file I/O, for testing)
704
+ const { session } = await createAgentSession({
705
+ settingsManager: SettingsManager.inMemory({ compaction: { enabled: false } }),
706
+ sessionManager: SessionManager.inMemory(),
707
+ });
708
+
709
+ // Custom directories
710
+ const { session } = await createAgentSession({
711
+ settingsManager: SettingsManager.create("/custom/cwd", "/custom/agent"),
712
+ });
713
+ ```
714
+
715
+ **Static factories:**
716
+
717
+ - `SettingsManager.create(cwd?, agentDir?)` - Load from files
718
+ - `SettingsManager.inMemory(settings?)` - No file I/O
719
+
720
+ **Project-specific settings:**
721
+
722
+ Settings load from two locations and merge:
723
+
724
+ 1. Global: `~/.pi/agent/settings.json`
725
+ 2. Project: `<cwd>/.pi/settings.json`
726
+
727
+ Project overrides global. Nested objects merge keys. Setters only modify global (project is read-only for version control).
728
+
729
+ > See [examples/sdk/10-settings.ts](../examples/sdk/10-settings.ts)
730
+
731
+ ## Discovery Functions
732
+
733
+ All discovery functions accept optional `cwd` and `agentDir` parameters.
734
+
735
+ ```typescript
736
+ import { getModel } from "@oh-my-pi/pi-ai";
737
+ import {
738
+ AuthStorage,
739
+ ModelRegistry,
740
+ discoverAuthStorage,
741
+ discoverModels,
742
+ discoverSkills,
743
+ discoverHooks,
744
+ discoverCustomTools,
745
+ discoverContextFiles,
746
+ discoverSlashCommands,
747
+ loadSettings,
748
+ buildSystemPrompt,
749
+ } from "@oh-my-pi/pi-coding-agent";
750
+
751
+ // Auth and Models
752
+ const authStorage = discoverAuthStorage(); // ~/.pi/agent/auth.json
753
+ const modelRegistry = discoverModels(authStorage); // + ~/.pi/agent/models.json
754
+ const allModels = modelRegistry.getAll(); // All models (built-in + custom)
755
+ const available = await modelRegistry.getAvailable(); // Only models with API keys
756
+ const model = modelRegistry.find("provider", "id"); // Find specific model
757
+ const builtIn = getModel("anthropic", "claude-opus-4-5"); // Built-in only
758
+
759
+ // Skills
760
+ const skills = discoverSkills(cwd, agentDir, skillsSettings);
761
+
762
+ // Hooks (async - loads TypeScript)
763
+ const hooks = await discoverHooks(cwd, agentDir);
764
+
765
+ // Custom tools (async - loads TypeScript)
766
+ const tools = await discoverCustomTools(cwd, agentDir);
767
+
768
+ // Context files
769
+ const contextFiles = discoverContextFiles(cwd, agentDir);
770
+
771
+ // Slash commands
772
+ const commands = discoverSlashCommands(cwd, agentDir);
773
+
774
+ // Settings (global + project merged)
775
+ const settings = loadSettings(cwd, agentDir);
776
+
777
+ // Build system prompt manually
778
+ const prompt = buildSystemPrompt({
779
+ skills,
780
+ contextFiles,
781
+ appendPrompt: "Additional instructions",
782
+ cwd,
783
+ });
784
+ ```
785
+
786
+ ## Return Value
787
+
788
+ `createAgentSession()` returns:
789
+
790
+ ```typescript
791
+ interface CreateAgentSessionResult {
792
+ // The session
793
+ session: AgentSession;
794
+
795
+ // Custom tools (for UI setup)
796
+ customToolsResult: {
797
+ tools: LoadedCustomTool[];
798
+ setUIContext: (ctx, hasUI) => void;
799
+ };
800
+
801
+ // Warning if session model couldn't be restored
802
+ modelFallbackMessage?: string;
803
+ }
804
+ ```
805
+
806
+ ## Complete Example
807
+
808
+ ```typescript
809
+ import { getModel } from "@oh-my-pi/pi-ai";
810
+ import { Type } from "@sinclair/typebox";
811
+ import {
812
+ AuthStorage,
813
+ createAgentSession,
814
+ ModelRegistry,
815
+ SessionManager,
816
+ SettingsManager,
817
+ readTool,
818
+ bashTool,
819
+ type HookFactory,
820
+ type CustomTool,
821
+ } from "@oh-my-pi/pi-coding-agent";
822
+
823
+ // Set up auth storage (custom location)
824
+ const authStorage = new AuthStorage("/custom/agent/auth.json");
825
+
826
+ // Runtime API key override (not persisted)
827
+ if (process.env.MY_KEY) {
828
+ authStorage.setRuntimeApiKey("anthropic", process.env.MY_KEY);
829
+ }
830
+
831
+ // Model registry (no custom models.json)
832
+ const modelRegistry = new ModelRegistry(authStorage);
833
+
834
+ // Inline hook
835
+ const auditHook: HookFactory = (api) => {
836
+ api.on("tool_call", async (event) => {
837
+ console.log(`[Audit] ${event.toolName}`);
838
+ return undefined;
839
+ });
840
+ };
841
+
842
+ // Inline tool
843
+ const statusTool: CustomTool = {
844
+ name: "status",
845
+ label: "Status",
846
+ description: "Get system status",
847
+ parameters: Type.Object({}),
848
+ execute: async () => ({
849
+ content: [{ type: "text", text: `Uptime: ${process.uptime()}s` }],
850
+ details: {},
851
+ }),
852
+ };
853
+
854
+ const model = getModel("anthropic", "claude-opus-4-5");
855
+ if (!model) throw new Error("Model not found");
856
+
857
+ // In-memory settings with overrides
858
+ const settingsManager = SettingsManager.inMemory({
859
+ compaction: { enabled: false },
860
+ retry: { enabled: true, maxRetries: 2 },
861
+ });
862
+
863
+ const { session } = await createAgentSession({
864
+ cwd: process.cwd(),
865
+ agentDir: "/custom/agent",
866
+
867
+ model,
868
+ thinkingLevel: "off",
869
+ authStorage,
870
+ modelRegistry,
871
+
872
+ systemPrompt: "You are a minimal assistant. Be concise.",
873
+
874
+ tools: [readTool, bashTool],
875
+ customTools: [{ tool: statusTool }],
876
+ hooks: [{ factory: auditHook }],
877
+ skills: [],
878
+ contextFiles: [],
879
+ slashCommands: [],
880
+
881
+ sessionManager: SessionManager.inMemory(),
882
+ settingsManager,
883
+ });
884
+
885
+ session.subscribe((event) => {
886
+ if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
887
+ process.stdout.write(event.assistantMessageEvent.delta);
888
+ }
889
+ });
890
+
891
+ await session.prompt("Get status and list files.");
892
+ ```
893
+
894
+ ## RPC Mode Alternative
895
+
896
+ For subprocess-based integration, use RPC mode instead of the SDK:
897
+
898
+ ```bash
899
+ pi --mode rpc --no-session
900
+ ```
901
+
902
+ See [RPC documentation](rpc.md) for the JSON protocol.
903
+
904
+ The SDK is preferred when:
905
+
906
+ - You want type safety
907
+ - You're in the same Node.js process
908
+ - You need direct access to agent state
909
+ - You want to customize tools/hooks programmatically
910
+
911
+ RPC mode is preferred when:
912
+
913
+ - You're integrating from another language
914
+ - You want process isolation
915
+ - You're building a language-agnostic client
916
+
917
+ ## Exports
918
+
919
+ The main entry point exports:
920
+
921
+ ```typescript
922
+ // Factory
923
+ createAgentSession
924
+
925
+ // Auth and Models
926
+ AuthStorage
927
+ ModelRegistry
928
+ discoverAuthStorage
929
+ discoverModels
930
+
931
+ // Discovery
932
+ discoverSkills
933
+ discoverHooks
934
+ discoverCustomTools
935
+ discoverContextFiles
936
+ discoverSlashCommands
937
+
938
+ // Helpers
939
+ loadSettings
940
+ buildSystemPrompt
941
+
942
+ // Session management
943
+ SessionManager
944
+ SettingsManager
945
+
946
+ // Built-in tools (use process.cwd())
947
+ codingTools
948
+ readOnlyTools
949
+ readTool, bashTool, editTool, writeTool
950
+ grepTool, findTool, lsTool
951
+
952
+ // Tool factories (for custom cwd)
953
+ createCodingTools
954
+ createReadOnlyTools
955
+ createReadTool, createBashTool, createEditTool, createWriteTool
956
+ createGrepTool, createFindTool, createLsTool
957
+
958
+ // Types
959
+ type CreateAgentSessionOptions
960
+ type CreateAgentSessionResult
961
+ type CustomTool
962
+ type HookFactory
963
+ type Skill
964
+ type FileSlashCommand
965
+ type Settings
966
+ type SkillsSettings
967
+ type Tool
968
+ ```
969
+
970
+ For hook types, import from the hooks subpath:
971
+
972
+ ```typescript
973
+ import type {
974
+ HookAPI,
975
+ HookMessage,
976
+ HookFactory,
977
+ HookEventContext,
978
+ HookCommandContext,
979
+ ToolCallEvent,
980
+ ToolResultEvent,
981
+ } from "@oh-my-pi/pi-coding-agent/hooks";
982
+ ```
983
+
984
+ For message utilities:
985
+
986
+ ```typescript
987
+ import { isHookMessage, createHookMessage } from "@oh-my-pi/pi-coding-agent";
988
+ ```
989
+
990
+ For config utilities:
991
+
992
+ ```typescript
993
+ import { getAgentDir } from "@oh-my-pi/pi-coding-agent/config";
994
+ ```