@counterposition/skill-pi 0.1.0 → 0.2.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.
@@ -1,6 +1,6 @@
1
1
  # SDK
2
2
 
3
- The SDK lets you embed Pi programmatically in Node.js applications via `createAgentSession()`.
3
+ The SDK embeds Pi in Node.js applications via `createAgentSession()`.
4
4
 
5
5
  ## Installation
6
6
 
@@ -11,167 +11,147 @@ npm install @mariozechner/pi-coding-agent
11
11
  ## Quick Start
12
12
 
13
13
  ```typescript
14
- import { createAgentSession } from "@mariozechner/pi-coding-agent";
14
+ import {
15
+ AuthStorage,
16
+ createAgentSession,
17
+ ModelRegistry,
18
+ SessionManager,
19
+ } from "@mariozechner/pi-coding-agent";
15
20
 
16
- const { session } = await createAgentSession();
21
+ const authStorage = AuthStorage.create();
22
+ const modelRegistry = ModelRegistry.create(authStorage);
23
+
24
+ const { session } = await createAgentSession({
25
+ sessionManager: SessionManager.inMemory(),
26
+ authStorage,
27
+ modelRegistry,
28
+ });
17
29
 
18
30
  session.subscribe((event) => {
19
- if (event.type === "message_update" && event.delta?.type === "text_delta") {
20
- process.stdout.write(event.delta.text);
21
- }
22
- if (event.type === "agent_end") {
23
- console.log("\nDone.");
31
+ if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
32
+ process.stdout.write(event.assistantMessageEvent.delta);
24
33
  }
25
34
  });
26
35
 
27
- await session.prompt("List all TypeScript files in the current directory");
36
+ await session.prompt("What files are in the current directory?");
28
37
  ```
29
38
 
30
- Run with: `npx tsx my-script.ts`
39
+ Run with `npx tsx my-script.ts`.
31
40
 
32
- ## Factory Options
33
-
34
- ```typescript
35
- const { session } = await createAgentSession({
36
- // Authentication
37
- authStorage: new AuthStorage({ path: "~/.pi/agent/auth.json" }),
38
-
39
- // Model configuration
40
- modelRegistry: new ModelRegistry(),
41
- model: getModel("anthropic", "claude-sonnet-4-20250514"),
42
- thinkingLevel: "medium",
43
-
44
- // Working directory
45
- cwd: process.cwd(),
46
-
47
- // Agent config directory
48
- agentDir: "~/.pi/agent",
49
-
50
- // Tools (built-in presets or custom)
51
- tools: codingTools(), // Default: read, bash, edit, write
52
- // tools: readOnlyTools(), // read, grep, find, ls
53
- // tools: allTools(), // All seven built-in tools
54
-
55
- // Resource discovery
56
- resourceLoader: new DefaultResourceLoader(),
57
-
58
- // Extensions (inline factories)
59
- extensionFactories: [
60
- (pi) => {
61
- pi.on("agent_start", async () => { /* ... */ });
62
- },
63
- ],
64
-
65
- // Session persistence
66
- sessionManager: SessionManager.create("path/to/session.jsonl"),
67
- // sessionManager: SessionManager.inMemory(), // No persistence
68
-
69
- // Settings
70
- settings: new SettingsManager({ /* ... */ }),
71
-
72
- // System prompt
73
- systemPrompt: "Custom system prompt",
74
- });
75
- ```
41
+ **Important:** `ModelRegistry` no longer has a public constructor. Use `ModelRegistry.create(authStorage, modelsJsonPath?)` for file-backed registries or `ModelRegistry.inMemory(authStorage)` for built-in models only.
76
42
 
77
43
  ## Key Imports
78
44
 
79
45
  ```typescript
80
46
  import {
81
- createAgentSession,
82
- // Auth & config
83
47
  AuthStorage,
48
+ createAgentSession,
49
+ createCodingTools,
50
+ createReadOnlyTools,
51
+ DefaultResourceLoader,
84
52
  ModelRegistry,
85
- SettingsManager,
86
53
  SessionManager,
87
- DefaultResourceLoader,
88
- // Tools
89
- codingTools,
90
- readOnlyTools,
91
- allTools,
92
- readTool,
93
- bashTool,
94
- editTool,
95
- writeTool,
96
- grepTool,
97
- findTool,
98
- lsTool,
99
- // Models
100
- getModel,
101
54
  } from "@mariozechner/pi-coding-agent";
55
+ import { getModel } from "@mariozechner/pi-ai";
102
56
  ```
103
57
 
104
- ## Event Types
58
+ ## Core Options
105
59
 
106
60
  ```typescript
107
- session.subscribe((event) => {
108
- switch (event.type) {
109
- // Streaming
110
- case "message_start": // New assistant message begins
111
- case "message_update": // Text/thinking/tool-call delta
112
- case "message_end": // Assistant message complete (includes full message)
113
-
114
- // Tool execution
115
- case "tool_execution_start": // Tool begins (toolCallId, toolName)
116
- case "tool_execution_update": // Partial tool output
117
- case "tool_execution_end": // Tool complete (toolCallId, result)
118
-
119
- // Lifecycle
120
- case "agent_start": // Agent begins processing
121
- case "agent_end": // Agent finishes
122
- case "turn_start": // New LLM turn
123
- case "turn_end": // LLM turn complete
124
-
125
- // System
126
- case "auto_compaction_start":
127
- case "auto_compaction_end":
128
- case "auto_retry_start":
129
- case "auto_retry_end":
130
- }
61
+ const cwd = "/path/to/project";
62
+ const authStorage = AuthStorage.create();
63
+ const modelRegistry = ModelRegistry.create(authStorage);
64
+
65
+ const { session } = await createAgentSession({
66
+ cwd,
67
+ agentDir: "~/.pi/agent",
68
+ authStorage,
69
+ modelRegistry,
70
+ model: getModel("anthropic", "claude-sonnet-4-20250514"),
71
+ thinkingLevel: "medium",
72
+ scopedModels: [
73
+ { model: getModel("anthropic", "claude-sonnet-4-20250514"), thinkingLevel: "high" },
74
+ ],
75
+ tools: createCodingTools(cwd),
76
+ resourceLoader: new DefaultResourceLoader(),
77
+ sessionManager: SessionManager.inMemory(),
131
78
  });
132
79
  ```
133
80
 
134
- ## Session Methods
81
+ Notes:
82
+
83
+ - `cwd` and `agentDir` control default resource discovery when using `DefaultResourceLoader`.
84
+ - If you provide a custom `cwd` **and** explicit built-in tools, use `createCodingTools(cwd)` / `createReadOnlyTools(cwd)` so paths resolve against that cwd.
85
+ - `DefaultResourceLoader` loads extensions, skills, prompt templates, themes, and context files. If you replace it, `cwd` and `agentDir` no longer drive resource discovery.
86
+
87
+ ## Prompting & Queueing
135
88
 
136
89
  ```typescript
137
- // Send a prompt
138
- await session.prompt("Do something");
90
+ await session.prompt("Review the current directory");
139
91
 
140
- // Queue message during active streaming
141
- session.steer("Actually, do this instead"); // Interrupts current tool execution
142
- session.followUp("After you're done, also..."); // Queued until agent finishes
92
+ // During streaming, choose how the new prompt should queue.
93
+ await session.prompt("Stop and do this instead", { streamingBehavior: "steer" });
94
+ await session.prompt("After you finish, also check tests", { streamingBehavior: "followUp" });
143
95
 
144
- // Control
145
- session.abort(); // Cancel current generation
146
- await session.waitForIdle(); // Wait until agent is idle
96
+ await session.steer("Use a smaller diff");
97
+ await session.followUp("Summarize the changes afterward");
98
+ ```
147
99
 
148
- // Model
149
- session.setModel(getModel("openai", "gpt-4o"));
150
- session.setThinkingLevel("high");
151
- session.cycleModel();
100
+ `prompt()` expands file-based prompt templates. During active streaming, calling it without `streamingBehavior` throws.
152
101
 
153
- // Compaction
154
- await session.compact();
102
+ ## Session Surface
155
103
 
156
- // State
157
- const messages = session.getMessages();
158
- const state = session.getState();
104
+ ```typescript
105
+ await session.newSession();
106
+ await session.switchSession("/path/to/session.jsonl");
107
+ await session.fork("entry-id");
108
+ await session.navigateTree("entry-id", { summarize: true });
109
+ await session.compact("Summarize design decisions only");
110
+
111
+ await session.abort();
112
+ await session.agent.waitForIdle();
113
+ session.dispose();
159
114
  ```
160
115
 
161
- ## Run Modes
116
+ Useful state:
117
+
118
+ - `session.sessionFile` / `session.sessionId`
119
+ - `session.agent.state.messages`
120
+ - `session.model`
121
+ - `session.thinkingLevel`
162
122
 
163
- For non-SDK usage, Pi provides run mode functions:
123
+ ## Events
164
124
 
165
125
  ```typescript
166
- import { runPrintMode, runRpcMode, InteractiveMode } from "@mariozechner/pi-coding-agent";
126
+ session.subscribe((event) => {
127
+ switch (event.type) {
128
+ case "message_update":
129
+ if (event.assistantMessageEvent.type === "text_delta") {
130
+ process.stdout.write(event.assistantMessageEvent.delta);
131
+ }
132
+ break;
133
+ case "tool_execution_start":
134
+ case "tool_execution_update":
135
+ case "tool_execution_end":
136
+ case "agent_start":
137
+ case "agent_end":
138
+ case "turn_start":
139
+ case "turn_end":
140
+ case "queue_update":
141
+ case "compaction_start":
142
+ case "compaction_end":
143
+ case "auto_retry_start":
144
+ case "auto_retry_end":
145
+ break;
146
+ }
147
+ });
148
+ ```
167
149
 
168
- // Print mode (single-shot)
169
- await runPrintMode(session, { outputFormat: "text" }); // or "json"
150
+ ## Resource Loader Hooks
170
151
 
171
- // RPC mode (JSON-RPC over stdin/stdout)
172
- await runRpcMode(session);
152
+ `DefaultResourceLoader` supports overrides for extensions, skills, prompts, themes, and context files. Common patterns:
173
153
 
174
- // Interactive mode (full TUI)
175
- const mode = new InteractiveMode(session);
176
- await mode.start();
177
- ```
154
+ - Add inline extension factories
155
+ - Override `agentsFiles` to inject virtual `AGENTS.md` content
156
+ - Add custom skills or prompt templates without touching disk
157
+ - Share an event bus between the host app and loaded extensions
@@ -1,170 +1,192 @@
1
1
  # Settings
2
2
 
3
- Pi uses hierarchical JSON configuration. Project settings (`.pi/settings.json`) merge over global settings (`~/.pi/agent/settings.json`). Nested objects are deep-merged; project values override global for the same key.
3
+ Pi uses JSON settings files with project settings overriding global settings:
4
4
 
5
- Edit settings directly or use `/settings` in interactive mode.
5
+ | Location | Scope |
6
+ |----------|-------|
7
+ | `~/.pi/agent/settings.json` | Global |
8
+ | `.pi/settings.json` | Project |
6
9
 
7
- ## Complete Settings Reference
10
+ Edit JSON directly or use `/settings` for common interactive options.
8
11
 
9
- ### Model & Thinking
12
+ ## Model & Thinking
10
13
 
11
14
  ```json
12
15
  {
13
- "provider": "anthropic", // Default provider name
14
- "model": "claude-sonnet-4-20250514", // Default model ID
15
- "thinkingLevel": "medium", // "off" | "minimal" | "low" | "medium" | "high" | "xhigh"
16
- "thinkingLevelBudget": null, // Custom token budget per thinking level (overrides defaults)
17
- "modelCyclePatterns": ["claude-*", "gpt-4o"] // Glob patterns for Ctrl+P model cycling
16
+ "defaultProvider": "anthropic",
17
+ "defaultModel": "claude-sonnet-4-20250514",
18
+ "defaultThinkingLevel": "medium",
19
+ "hideThinkingBlock": false,
20
+ "thinkingBudgets": {
21
+ "minimal": 1024,
22
+ "low": 4096,
23
+ "medium": 10240,
24
+ "high": 32768
25
+ }
18
26
  }
19
27
  ```
20
28
 
21
- ### Compaction
29
+ - Thinking levels: `"off"`, `"minimal"`, `"low"`, `"medium"`, `"high"`, `"xhigh"`
30
+ - `hideThinkingBlock` hides visible thinking output in the UI
31
+
32
+ ## UI & Display
22
33
 
23
34
  ```json
24
35
  {
25
- "compaction": {
26
- "enabled": true, // Enable auto-compaction
27
- "reserveTokens": 16384, // Tokens to reserve for new responses
28
- "keepRecentTokens": 20000 // Recent tokens to keep uncompacted
29
- }
36
+ "theme": "dark",
37
+ "quietStartup": false,
38
+ "collapseChangelog": false,
39
+ "doubleEscapeAction": "tree",
40
+ "treeFilterMode": "default",
41
+ "editorPaddingX": 0,
42
+ "autocompleteMaxVisible": 5,
43
+ "showHardwareCursor": false
30
44
  }
31
45
  ```
32
46
 
33
- ### Branch Summary
47
+ - `doubleEscapeAction`: `"tree"`, `"fork"`, or `"none"`
48
+ - `treeFilterMode`: `"default"`, `"no-tools"`, `"user-only"`, `"labeled-only"`, or `"all"`
49
+
50
+ ## Compaction, Branch Summary, Retry
34
51
 
35
52
  ```json
36
53
  {
54
+ "compaction": {
55
+ "enabled": true,
56
+ "reserveTokens": 16384,
57
+ "keepRecentTokens": 20000
58
+ },
37
59
  "branchSummary": {
38
- "enabled": true, // Summarize when switching branches via /tree
39
- "maxTokens": 4096, // Max tokens for summary
40
- "skipPrompt": false // Skip confirmation prompt
60
+ "reserveTokens": 16384,
61
+ "skipPrompt": false
62
+ },
63
+ "retry": {
64
+ "enabled": true,
65
+ "maxRetries": 3,
66
+ "baseDelayMs": 2000,
67
+ "maxDelayMs": 60000
41
68
  }
42
69
  }
43
70
  ```
44
71
 
45
- ### Retry
72
+ Notes:
46
73
 
47
- ```json
48
- {
49
- "retry": {
50
- "maxRetries": 3, // Max automatic retries on transient errors
51
- "initialDelayMs": 2000, // First retry delay
52
- "maxDelayMs": 60000 // Max delay (exponential backoff)
53
- }
54
- }
55
- ```
74
+ - `retry.maxDelayMs = 0` disables the cap on server-requested retry delays.
75
+ - `branchSummary.skipPrompt` skips the confirmation step when navigating with `/tree`.
56
76
 
57
- ### Message Delivery
77
+ ## Message Delivery
58
78
 
59
79
  ```json
60
80
  {
61
- "steeringMode": "all", // "all" | "one-at-a-time" — how steer messages are delivered
62
- "followUpMode": "all", // "all" | "one-at-a-time" — how follow-up messages are delivered
63
- "transport": "auto" // "sse" | "websocket" | "auto"
81
+ "steeringMode": "one-at-a-time",
82
+ "followUpMode": "one-at-a-time",
83
+ "transport": "sse"
64
84
  }
65
85
  ```
66
86
 
67
- ### Terminal & Images
87
+ - `steeringMode` and `followUpMode`: `"all"` or `"one-at-a-time"`
88
+ - `transport`: `"sse"`, `"websocket"`, or `"auto"`
89
+
90
+ ## Terminal, Images, and Shell
68
91
 
69
92
  ```json
70
93
  {
71
94
  "terminal": {
72
- "showImages": true, // Display images in terminal
73
- "maxImageWidth": 2000, // Max image dimensions for resizing
74
- "maxImageHeight": 2000
95
+ "showImages": true,
96
+ "clearOnShrink": false
75
97
  },
76
- "image": {
77
- "autoResize": true // Auto-resize large images before sending to LLM
78
- }
98
+ "images": {
99
+ "autoResize": true,
100
+ "blockImages": false
101
+ },
102
+ "shellPath": "/bin/bash",
103
+ "shellCommandPrefix": "",
104
+ "npmCommand": ["mise", "exec", "node@20", "--", "npm"]
79
105
  }
80
106
  ```
81
107
 
82
- ### Shell
108
+ - `npmCommand` is argv-style and is used for npm lookup/install operations, including git-package installs.
83
109
 
84
- ```json
85
- {
86
- "shellPath": "/bin/bash", // Custom shell path (Windows: "C:\\...\\bash.exe")
87
- "shellCommandPrefix": "", // Prefix prepended to every bash command
88
- "npmCommand": "npm" // npm, pnpm, yarn, bun
89
- }
90
- ```
91
-
92
- ### UI
110
+ ## Sessions, Model Cycling, Markdown
93
111
 
94
112
  ```json
95
113
  {
96
- "theme": "dark", // "dark" | "light" | custom theme name
97
- "showStartupBanner": true, // Show banner on startup
98
- "editorPadding": 1, // Lines of padding in editor
99
- "showAutoComplete": true, // Show autocomplete suggestions
100
- "cursorStyle": "block" // "block" | "underline" | "bar"
114
+ "sessionDir": ".pi/sessions",
115
+ "enabledModels": ["claude-*", "gpt-4o", "gemini-2*"],
116
+ "markdown": {
117
+ "codeBlockIndent": " "
118
+ }
101
119
  }
102
120
  ```
103
121
 
104
- ### Sessions
122
+ Precedence for session storage is:
105
123
 
106
- ```json
107
- {
108
- "sessionDir": null // Custom session storage path (default: ~/.pi/agent/sessions/)
109
- }
110
- ```
124
+ 1. `--session-dir`
125
+ 2. `sessionDir` in settings
126
+ 3. Extension `session_directory` hooks
111
127
 
112
- ### Resources
128
+ ## Resources
113
129
 
114
- Load extensions, skills, prompts, and themes from paths or packages:
130
+ These settings control what Pi loads from disk or packages:
115
131
 
116
132
  ```json
117
133
  {
118
- "extensions": [
119
- "~/.pi/agent/extensions/my-ext.ts",
120
- "npm:@foo/pi-extensions"
121
- ],
122
- "skills": [
123
- ".pi/skills/my-skill",
124
- "npm:@foo/pi-skills"
125
- ],
126
- "prompts": [
127
- "~/.pi/agent/prompts/"
128
- ],
129
- "themes": [
130
- "npm:@foo/pi-themes"
134
+ "packages": [
135
+ "npm:@foo/pi-tools",
136
+ {
137
+ "source": "git:github.com/user/repo@v1",
138
+ "skills": ["brave-search"],
139
+ "extensions": []
140
+ }
131
141
  ],
132
- "customPackages": [
133
- "npm:@foo/pi-package@1.0.0",
134
- "git:github.com/user/repo",
135
- "./local/path"
136
- ]
142
+ "extensions": ["./extensions/my-ext.ts"],
143
+ "skills": ["./skills", "../.claude/skills"],
144
+ "prompts": ["./prompts"],
145
+ "themes": ["./themes"],
146
+ "enableSkillCommands": true
137
147
  }
138
148
  ```
139
149
 
140
- ### Resource Pattern Matching
150
+ Notes:
151
+
152
+ - Paths in `~/.pi/agent/settings.json` resolve relative to `~/.pi/agent`.
153
+ - Paths in `.pi/settings.json` resolve relative to `.pi`.
154
+ - `packages` loads npm/git/local Pi packages.
155
+ - `extensions`, `skills`, `prompts`, and `themes` are for local files/directories.
156
+ - `enableSkillCommands` controls `/skill:name` registration.
141
157
 
142
- Resources support include/exclude patterns:
158
+ ## Include / Exclude Patterns
159
+
160
+ Arrays support filtering:
143
161
 
144
162
  ```json
145
163
  {
146
164
  "skills": [
147
- "npm:@foo/pi-skills", // Include all skills from package
148
- "!secret-skill", // Exclude by name
149
- "+override-skill", // Force-include (overrides exclusions)
150
- "-unwanted-skill" // Force-exclude (overrides inclusions)
165
+ "./skills",
166
+ "!legacy-skill",
167
+ "+must-load-skill",
168
+ "-blocked-skill"
151
169
  ]
152
170
  }
153
171
  ```
154
172
 
173
+ - `!pattern` excludes glob matches
174
+ - `+path` force-includes an exact path
175
+ - `-path` force-excludes an exact path
176
+
155
177
  ## Environment Variables
156
178
 
157
179
  | Variable | Effect |
158
180
  |----------|--------|
159
- | `PI_CODING_AGENT_DIR` | Override global config directory (default: `~/.pi/agent/`) |
160
- | `PI_OFFLINE` | Disable package updates and tool downloads |
161
- | `ANTHROPIC_API_KEY` | Anthropic API key |
162
- | `OPENAI_API_KEY` | OpenAI API key |
163
- | Additional provider env vars | See `references/providers.md` |
164
-
165
- ## Editing Tips
166
-
167
- - Use `/settings` in interactive mode for a guided editor
168
- - Project settings are committed to version control (`.pi/settings.json`) for team sharing
169
- - Global settings (`~/.pi/agent/settings.json`) are personal
170
- - Settings reload on next agent start — no restart needed for most changes
181
+ | `PI_CODING_AGENT_DIR` | Override the global agent directory |
182
+ | `PI_PACKAGE_DIR` | Override package storage directory |
183
+ | `PI_SKIP_VERSION_CHECK` | Skip startup version checks |
184
+ | `PI_CACHE_RETENTION` | Use extended prompt-cache retention where supported |
185
+ | `VISUAL`, `EDITOR` | External editor for `Ctrl+G` |
186
+ | Provider API key env vars | See `references/providers.md` |
187
+
188
+ ## Practical Notes
189
+
190
+ - Project settings are good for shared package/resource configuration.
191
+ - Global settings are better for personal credentials, UI preferences, and model defaults.
192
+ - Nested objects are merged; project keys override the same global keys.