pi-ca-leash 0.11.1 → 0.12.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 (39) hide show
  1. package/README.md +66 -14
  2. package/RELEASE_NOTES.md +71 -0
  3. package/extensions/command-drivers.ts +4 -4
  4. package/extensions/index.ts +52 -16
  5. package/extensions/model-catalog.ts +40 -7
  6. package/extensions/prompts/peer-start-tool.md +1 -1
  7. package/extensions/prompts/runtime-models-tool.md +2 -2
  8. package/extensions/prompts/subagent-run-tool.md +1 -1
  9. package/extensions/prompts/team-spawn-tool.md +1 -1
  10. package/extensions/runtime-driver.ts +27 -6
  11. package/extensions/runtime-safety.ts +9 -1
  12. package/extensions/tool-inputs.ts +5 -4
  13. package/node_modules/@pi-claude-code-agent/intercom-bridge/dist/bridge.js +18 -4
  14. package/node_modules/@pi-claude-code-agent/intercom-bridge/dist/bridge.js.map +1 -1
  15. package/node_modules/@pi-claude-code-agent/intercom-bridge/package.json +2 -2
  16. package/node_modules/@pi-claude-code-agent/runtime/dist/config.d.ts +26 -0
  17. package/node_modules/@pi-claude-code-agent/runtime/dist/config.js +104 -0
  18. package/node_modules/@pi-claude-code-agent/runtime/dist/config.js.map +1 -0
  19. package/node_modules/@pi-claude-code-agent/runtime/dist/driver-config.js +6 -1
  20. package/node_modules/@pi-claude-code-agent/runtime/dist/driver-config.js.map +1 -1
  21. package/node_modules/@pi-claude-code-agent/runtime/dist/drivers/claude-cli.d.ts +30 -0
  22. package/node_modules/@pi-claude-code-agent/runtime/dist/drivers/claude-cli.js +209 -0
  23. package/node_modules/@pi-claude-code-agent/runtime/dist/drivers/claude-cli.js.map +1 -0
  24. package/node_modules/@pi-claude-code-agent/runtime/dist/drivers/codex-cli.d.ts +1 -0
  25. package/node_modules/@pi-claude-code-agent/runtime/dist/drivers/codex-cli.js +7 -4
  26. package/node_modules/@pi-claude-code-agent/runtime/dist/drivers/codex-cli.js.map +1 -1
  27. package/node_modules/@pi-claude-code-agent/runtime/dist/drivers/pi-coding-agent.d.ts +34 -0
  28. package/node_modules/@pi-claude-code-agent/runtime/dist/drivers/pi-coding-agent.js +280 -0
  29. package/node_modules/@pi-claude-code-agent/runtime/dist/drivers/pi-coding-agent.js.map +1 -0
  30. package/node_modules/@pi-claude-code-agent/runtime/dist/index.d.ts +4 -0
  31. package/node_modules/@pi-claude-code-agent/runtime/dist/index.js +3 -0
  32. package/node_modules/@pi-claude-code-agent/runtime/dist/index.js.map +1 -1
  33. package/node_modules/@pi-claude-code-agent/runtime/dist/runtime.js +23 -2
  34. package/node_modules/@pi-claude-code-agent/runtime/dist/runtime.js.map +1 -1
  35. package/node_modules/@pi-claude-code-agent/runtime/dist/types.d.ts +2 -1
  36. package/node_modules/@pi-claude-code-agent/runtime/package.json +1 -1
  37. package/node_modules/@pi-claude-code-agent/subagents-backend/package.json +2 -2
  38. package/node_modules/@pi-claude-code-agent/teams-backend/package.json +3 -3
  39. package/package.json +7 -5
package/README.md CHANGED
@@ -1,12 +1,17 @@
1
1
  # pi-ca-leash
2
2
 
3
+ > [!WARNING]
4
+ > **Claude Code auth caveat:** the default `claude-sdk` runtime path actively sends prompts and follow-up messages through `@anthropic-ai/claude-agent-sdk`, including resumed peer sessions. The optional `claude-cli` runtime path avoids that SDK package and shells out to `claude -p`, but it is still non-interactive Claude Code message sending. Anthropic's current Claude Code legal/authentication docs say OAuth subscription credentials are intended for ordinary Claude Code and native Anthropic app use, while developers building products or services with the Agent SDK should use API key authentication through Claude Console or a supported cloud provider. Do not use this extension to route Free, Pro, or Max subscription credentials on behalf of other users.
5
+ >
6
+ > Read-only/local features such as dashboard state, peer history browsing, local persistence, Git operations, and the experimental `codex-cli` runtime path are separate from Claude Agent SDK message sending.
7
+
3
8
  Harness-aware Claude Code and Codex CLI extension for pi.
4
9
 
5
10
  Claude Code and Codex CLI are more than model endpoints. They are coding harnesses with their own tool loops, session semantics, and increasingly harness-optimized models. `pi-ca-leash` treats them that way.
6
11
 
7
12
  Pi stays in the brain seat — like a human coordinating multiple coding agents. It can start long-lived workers, hand them scoped tasks, wait for results, inspect what they did, and decide what happens next.
8
13
 
9
- Claude is the default and most complete path today. Codex works too, but is still experimental and not parity-complete.
14
+ Claude is the default and most complete path today. `claude-cli` is available as an optional local CLI-backed Claude path. Codex works too, but is still experimental and not parity-complete.
10
15
 
11
16
  ## What it adds
12
17
 
@@ -59,7 +64,7 @@ Once peer mode is active, you can often ask for this in natural language instead
59
64
 
60
65
  ## Install
61
66
 
62
- This npm package is available again, but it comes with a large caveat: the Claude-backed runtime path actively sends messages through Anthropic's Agent SDK. Read the Agent SDK auth notice below before using it.
67
+ Read the Claude Code auth caveat at the top of this README before using a Claude-backed runtime path.
63
68
 
64
69
  Install from npm:
65
70
 
@@ -70,7 +75,7 @@ pi install npm:pi-ca-leash
70
75
  Pin an explicit version when needed:
71
76
 
72
77
  ```bash
73
- pi install npm:pi-ca-leash@0.11.1
78
+ pi install npm:pi-ca-leash@0.12.0
74
79
  ```
75
80
 
76
81
  Local checkout install:
@@ -96,20 +101,60 @@ pi install /absolute/path/to/pi-ca-leash
96
101
 
97
102
  `npm install` runs the workspace build through `prepare`, so local development and git-based installs have package `dist/` files available.
98
103
 
99
- ### Agent SDK Auth Notice
100
-
101
- The `claude-sdk` runtime path actively sends prompts and follow-up messages through `@anthropic-ai/claude-agent-sdk`, including resumed peer sessions. Anthropic's current Claude Code legal/authentication docs say OAuth subscription credentials are intended for ordinary Claude Code and native Anthropic app use, while developers building products or services with the Agent SDK should use API key authentication through Claude Console or a supported cloud provider. Do not use this extension to route Free, Pro, or Max subscription credentials on behalf of other users.
102
-
103
- Read-only/local features such as dashboard state, peer history browsing, local persistence, Git operations, and the experimental `codex-cli` runtime path are separate from Claude Agent SDK message sending.
104
-
105
- Use Codex as the default runtime driver for newly started peers:
104
+ Use another default runtime driver for newly started peers:
106
105
 
107
106
  ```bash
107
+ PI_CLAUDE_RUNTIME_DRIVER=claude-cli pi
108
108
  PI_CLAUDE_RUNTIME_DRIVER=codex-cli pi
109
109
  ```
110
110
 
111
111
  Persisted peers keep their recorded driver.
112
112
 
113
+ ## Configuration
114
+
115
+ Driver choice can be set per call, by environment, or by config file. Precedence is:
116
+
117
+ 1. explicit method/tool/command driver, such as `peer_start(..., driver: "claude-cli")` or `/peer start task | claude-cli`
118
+ 2. `PI_CLAUDE_RUNTIME_DRIVER`
119
+ 3. config file `defaultDriver`
120
+ 4. built-in default `claude-sdk`
121
+
122
+ Config files are JSON and are merged in this order:
123
+
124
+ 1. global XDG config: `$XDG_CONFIG_HOME/pi-ca-leash/config.json`, or `~/.config/pi-ca-leash/config.json`
125
+ 2. repository-local config: `.pi-ca-leash/config.json`
126
+ 3. explicit override path from `PI_CA_LEASH_CONFIG`
127
+
128
+ Example:
129
+
130
+ ```json
131
+ {
132
+ "defaultDriver": "claude-cli",
133
+ "drivers": {
134
+ "claude-cli": {
135
+ "executable": "/opt/homebrew/bin/claude",
136
+ "permissionMode": "bypassPermissions"
137
+ },
138
+ "codex-cli": {
139
+ "executable": "/opt/homebrew/bin/codex"
140
+ }
141
+ }
142
+ }
143
+ ```
144
+
145
+ `claude-cli` runs local Claude Code in print mode (`claude -p --output-format stream-json`) and resumes follow-up peer messages with `--resume <session-id>`. `claude-sdk` remains available and is still the default unless you choose another driver.
146
+
147
+ ## SDK Usage
148
+
149
+ This repo also ships reusable SDK packages for programmatic use:
150
+
151
+ - `@pi-claude-code-agent/runtime` for driver-backed sessions, status, events, transcripts, and normalized result usage
152
+ - `@pi-claude-code-agent/intercom-bridge` for named long-lived peers and managed-peer orchestration
153
+ - `@pi-claude-code-agent/subagents-backend` for persisted bounded local runs
154
+ - `@pi-claude-code-agent/teams-backend` for persistent local teammate records
155
+
156
+ Token usage is exposed as per-result-event data, not as an automatic session total. SDK consumers should sum selected `RuntimeEvent.type === "result"` events themselves when they need cumulative accounting. See `docs/token-usage-reporting.md` for the adapter/backend matrix and example SDK summing pattern.
157
+
113
158
  ## Try this first
114
159
 
115
160
  Inside pi:
@@ -123,9 +168,10 @@ Inside pi:
123
168
  /peer dashboard advanced
124
169
  ```
125
170
 
126
- If you want Codex-backed peers, inspect the bundled Codex catalog first:
171
+ If you want driver-specific peers, inspect the bundled catalog first:
127
172
 
128
173
  ```text
174
+ /peer models claude-cli
129
175
  /peer models codex-cli
130
176
  ```
131
177
 
@@ -150,6 +196,10 @@ Primary slash-command surface:
150
196
  /peer init
151
197
  /peer dashboard
152
198
  /peer dashboard advanced
199
+ /peer dashboard hide
200
+ /peer dashboard show
201
+ /peer hide
202
+ /peer show
153
203
  /peer start <prompt>
154
204
  /peer start <prompt> | <driver> | <model>
155
205
  /peer start <name> | <prompt>
@@ -157,7 +207,7 @@ Primary slash-command surface:
157
207
  /peer ask <name> | <message>
158
208
  /peer send <name> | <message>
159
209
  /peer list
160
- /peer models [claude-sdk|codex-cli] [all|advanced|verbose]
210
+ /peer models [claude-sdk|claude-cli|codex-cli] [all|advanced|verbose]
161
211
  /peer history <name> [cursor] [limit]
162
212
  /peer interrupt <name>
163
213
  /peer stop <name>
@@ -205,7 +255,7 @@ PI_CA_LEASH_ENABLE_LEGACY_COMMANDS=1 PI_CLAUDE_ENABLE_ADVANCED_COMMANDS=1 pi
205
255
 
206
256
  ## Behavior
207
257
 
208
- The extension is lazy. Loading it registers commands and tools, but it does not start the Peers widget, background monitor, or intercom transport checks immediately. `/peer` with no args opens the dashboard and activates peer mode. `/peer init` also activates the peer workflow, adds the one-time orchestration guide to the main agent context, and shows the user a compact command cheat sheet as a user-only UI notification. The first actionable `/peer` command, such as `/peer models`, `/peer dashboard`, `/peer list`, or `/peer start`, also activates it and adds that agent guide once. `/peer help` and `/peer about` stay passive and show user-only UI notifications. `/peer about` reports the installed package version, package root, state root, default driver, and session mode.
258
+ The extension is lazy. Loading it registers commands and tools, but it does not start the Peers widget, background monitor, or intercom transport checks immediately. `/peer` with no args opens the dashboard and activates peer mode. `/peer init` also activates the peer workflow, adds the one-time orchestration guide to the main agent context, and shows the user a compact command cheat sheet as a user-only UI notification. The first actionable `/peer` command, such as `/peer models`, `/peer dashboard`, `/peer list`, or `/peer start`, also activates it and adds that agent guide once. `/peer help` and `/peer about` stay passive and show user-only UI notifications. `/peer about` reports the installed package version, package root, state root, default driver, and session mode. `/peer dashboard hide` (or `/peer hide`) clears the compact Peers widget for the current session without stopping peers or disabling completion relays; `/peer dashboard show` (or `/peer show`) restores it.
209
259
 
210
260
  Peers are asynchronous workers. The main agent should start a peer, continue useful work, and wait for the automatic peer completion, blocked, or failure relay. It should not poll `peer_list`, `peer_history`, or repeated `peer_ask` just to see whether the peer is done. When a peer returns, the main agent still owns verification, synthesis, and the final answer.
211
261
 
@@ -230,8 +280,9 @@ Result: managed peers created by another extension can show up in the live `/pee
230
280
 
231
281
  Runtime driver notes:
232
282
  - `claude-sdk` is the default and most complete path
283
+ - `claude-cli` shells out to local `claude -p --output-format stream-json`; it avoids importing the Agent SDK package, but still uses Claude Code non-interactively
233
284
  - `codex-cli` is supported, but still experimental and not parity-complete
234
- - `PI_CLAUDE_RUNTIME_DRIVER=codex-cli` changes the default for newly started peers
285
+ - `PI_CLAUDE_RUNTIME_DRIVER=claude-cli` or `PI_CLAUDE_RUNTIME_DRIVER=codex-cli` changes the default for newly started peers
235
286
  - `/peer models` and LLM-callable `runtime_models` show a short recommended model list by default, including advisory use cases
236
287
  - `/peer models ... all` and `runtime_models(verbose: true)` expose the full bundled Lanista-derived model catalog
237
288
  - LLM-callable `peer_start`, `peer_ask`, and `peer_send` can pass explicit model ids
@@ -256,6 +307,7 @@ Useful docs that should remain current:
256
307
  - `ARCHITECTURE.md`
257
308
  - `KNOWN_LIMITS.md`
258
309
  - `CHANGELOG.md`
310
+ - `RELEASE_NOTES.md`
259
311
  - `DEVELOPMENT.md`
260
312
  - `AGENTS.md`
261
313
 
@@ -0,0 +1,71 @@
1
+ # Release Notes
2
+
3
+ ## Unreleased
4
+
5
+ This release adds a second Claude-backed runtime path while keeping the existing Agent SDK path intact.
6
+
7
+ ### Claude CLI runtime
8
+
9
+ - Added `claude-cli`, an optional runtime driver that runs local Claude Code through `claude -p --output-format stream-json`.
10
+ - Follow-up peer messages resume the same Claude Code session with `--resume <session-id>`.
11
+ - `claude-cli` shares the existing Anthropic model catalog and alias handling used by `claude-sdk`.
12
+ - `claude-sdk` remains available and stays the built-in default.
13
+
14
+ Use it per peer:
15
+
16
+ ```text
17
+ /peer start reviewer | Review this repo briefly. | claude-cli
18
+ ```
19
+
20
+ Or as the default for new peers:
21
+
22
+ ```bash
23
+ PI_CLAUDE_RUNTIME_DRIVER=claude-cli pi
24
+ ```
25
+
26
+ ### Configuration
27
+
28
+ Driver defaults and executable overrides can now come from config files as well as environment variables and method/tool parameters.
29
+
30
+ Precedence:
31
+
32
+ 1. explicit method, tool, or command driver
33
+ 2. `PI_CLAUDE_RUNTIME_DRIVER`
34
+ 3. config file `defaultDriver`
35
+ 4. built-in default `claude-sdk`
36
+
37
+ Config files are merged in this order:
38
+
39
+ 1. `$XDG_CONFIG_HOME/pi-ca-leash/config.json` or `~/.config/pi-ca-leash/config.json`
40
+ 2. `.pi-ca-leash/config.json` in the repository
41
+ 3. `PI_CA_LEASH_CONFIG`
42
+
43
+ Example:
44
+
45
+ ```json
46
+ {
47
+ "defaultDriver": "claude-cli",
48
+ "drivers": {
49
+ "claude-cli": {
50
+ "executable": "/opt/homebrew/bin/claude",
51
+ "permissionMode": "bypassPermissions"
52
+ },
53
+ "codex-cli": {
54
+ "executable": "/opt/homebrew/bin/codex"
55
+ }
56
+ }
57
+ }
58
+ ```
59
+
60
+ ### Codex CLI permissions
61
+
62
+ - `codex-cli` now maps `permissionMode: "bypassPermissions"` to Codex's unsandboxed automation flag for fresh and resumed peer runs.
63
+ - Other accepted Codex permission modes keep the existing `--full-auto` behavior.
64
+
65
+ ### Auth Caveat
66
+
67
+ The top-level README warning now distinguishes the two Claude-backed paths:
68
+
69
+ - `claude-sdk` sends messages through `@anthropic-ai/claude-agent-sdk`.
70
+ - `claude-cli` avoids importing that SDK package and shells out to `claude -p`.
71
+ - Both are still non-interactive Claude Code message-sending paths, so users must understand their authentication mode and applicable Anthropic terms before using them.
@@ -61,7 +61,7 @@ export function parsePeerStartCommandInput(args: string): ParsedPeerStartCommand
61
61
  }
62
62
  const driver = parseRuntimeDriverName(parts[2]);
63
63
  if (!driver) {
64
- throw new Error("driver must be claude-sdk or codex-cli when using a driver-aware peer start form");
64
+ throw new Error("driver must be claude-sdk, claude-cli, or codex-cli when using a driver-aware peer start form");
65
65
  }
66
66
  return {
67
67
  name: parts[0],
@@ -72,7 +72,7 @@ export function parsePeerStartCommandInput(args: string): ParsedPeerStartCommand
72
72
  }
73
73
  const driver = parseRuntimeDriverName(parts[2]);
74
74
  if (!driver) {
75
- throw new Error("driver must be claude-sdk or codex-cli when using <name> | <prompt> | <driver> | <model>");
75
+ throw new Error("driver must be claude-sdk, claude-cli, or codex-cli when using <name> | <prompt> | <driver> | <model>");
76
76
  }
77
77
  return {
78
78
  name: parts[0],
@@ -94,7 +94,7 @@ export function parseSubagentRunCommandInput(args: string): ParsedSubagentRunCom
94
94
  }
95
95
  const driver = parseRuntimeDriverName(parts[0]);
96
96
  if (!driver) {
97
- throw new Error("driver must be claude-sdk or codex-cli when using <driver> | <task>");
97
+ throw new Error("driver must be claude-sdk, claude-cli, or codex-cli when using <driver> | <task>");
98
98
  }
99
99
  return {
100
100
  driver,
@@ -116,7 +116,7 @@ export function parseTeamSpawnCommandInput(args: string): ParsedTeamSpawnCommand
116
116
  }
117
117
  const driver = parseRuntimeDriverName(maybeDriver);
118
118
  if (!driver) {
119
- throw new Error("driver must be claude-sdk or codex-cli when using <name> | <prompt> | <driver>");
119
+ throw new Error("driver must be claude-sdk, claude-cli, or codex-cli when using <name> | <prompt> | <driver>");
120
120
  }
121
121
  return {
122
122
  name: name ?? "",
@@ -78,6 +78,8 @@ const EXTENSION_VERSION = String((extensionRequire("../package.json") as { versi
78
78
  const STATE_DIR_NAME = ".pi-ca-leash";
79
79
  const BACKGROUND_POLL_INTERVAL_MS = 5_000;
80
80
  const BACKGROUND_REFRESH_MIN_INTERVAL_MS = 3_000;
81
+ const RUNTIME_DRIVER_ENUM = ["claude-sdk", "claude-cli", "codex-cli", "pi-coding-agent"] as const;
82
+ const RUNTIME_DRIVER_USAGE = "claude-sdk, claude-cli, or codex-cli";
81
83
  const DEFAULT_SNOOZE_MINUTES = 15;
82
84
 
83
85
  interface DashboardSnapshot {
@@ -142,15 +144,17 @@ interface ExtensionLogEntryInput {
142
144
  let dashboardContextRef: ExtensionContext | ExtensionCommandContext | undefined;
143
145
  let operatorContextRef: ExtensionContext | ExtensionCommandContext | undefined;
144
146
  let lastWidgetSignature: string | undefined;
147
+ let peerDashboardHidden = false;
145
148
 
146
149
  export default async function piCaLeashExtension(pi: ExtensionAPI) {
147
150
  const cwd = process.cwd();
148
151
  const rootDir = resolve(cwd, STATE_DIR_NAME);
149
152
  const attentionLedgerPath = resolve(rootDir, "extension", "attention-ledger.json");
150
- const runtimeDriverConfig = resolveExtensionRuntimeDriverConfig();
153
+ const runtimeDriverConfig = resolveExtensionRuntimeDriverConfig(process.env, cwd);
151
154
  const runtime = new ClaudeCodeRuntime({
152
155
  storageDir: resolve(rootDir, "runtime"),
153
156
  defaultDriver: runtimeDriverConfig.defaultDriver,
157
+ config: runtimeDriverConfig.config,
154
158
  });
155
159
  const bridge = new ClaudeRuntimeIntercomBridge({
156
160
  runtime,
@@ -188,7 +192,7 @@ export default async function piCaLeashExtension(pi: ExtensionAPI) {
188
192
  async function startPeerWithoutWaiting(input: {
189
193
  name: string;
190
194
  prompt: string;
191
- driver?: "claude-sdk" | "codex-cli";
195
+ driver?: (typeof RUNTIME_DRIVER_ENUM)[number];
192
196
  cwd?: string;
193
197
  model?: string;
194
198
  permissionMode?: "default" | "acceptEdits" | "plan" | "dontAsk" | "bypassPermissions";
@@ -547,7 +551,7 @@ export default async function piCaLeashExtension(pi: ExtensionAPI) {
547
551
  parameters: {
548
552
  type: "object",
549
553
  properties: {
550
- driver: { type: "string", enum: ["claude-sdk", "codex-cli"], description: "Optional runtime driver to filter the model catalog." },
554
+ driver: { type: "string", enum: [...RUNTIME_DRIVER_ENUM], description: "Optional runtime driver to filter the model catalog." },
551
555
  verbose: { type: "boolean", description: "When true, include every model from the bundled catalog instead of the short recommended list." },
552
556
  },
553
557
  additionalProperties: false,
@@ -556,7 +560,7 @@ export default async function piCaLeashExtension(pi: ExtensionAPI) {
556
560
  const input = params as { driver?: unknown; verbose?: unknown };
557
561
  const driver = input.driver == null ? undefined : parseRuntimeDriverName(input.driver);
558
562
  if (input.driver != null && !driver) {
559
- throw new Error("driver must be claude-sdk or codex-cli");
563
+ throw new Error(`driver must be ${RUNTIME_DRIVER_USAGE}`);
560
564
  }
561
565
  const verbose = input.verbose === true;
562
566
  const catalogs = modelCatalogsForDriver(driver);
@@ -631,7 +635,7 @@ export default async function piCaLeashExtension(pi: ExtensionAPI) {
631
635
  properties: {
632
636
  prompt: { type: "string", description: "Task or role prompt for the peer." },
633
637
  name: { type: "string", description: "Optional explicit peer name." },
634
- driver: { type: "string", enum: ["claude-sdk", "codex-cli"], description: "Optional runtime driver for this peer. Defaults to the extension startup driver." },
638
+ driver: { type: "string", enum: [...RUNTIME_DRIVER_ENUM], description: "Optional runtime driver for this peer. Defaults to the extension startup driver." },
635
639
  model: { type: "string", description: "Optional model to use for this peer session." },
636
640
  cwd: { type: "string", description: "Optional working directory for the peer. Relative paths resolve from the current pi working directory." },
637
641
  },
@@ -650,7 +654,7 @@ export default async function piCaLeashExtension(pi: ExtensionAPI) {
650
654
  throw new Error("prompt required");
651
655
  }
652
656
  if (input.driver != null && !driver) {
653
- throw new Error("driver must be claude-sdk or codex-cli");
657
+ throw new Error(`driver must be ${RUNTIME_DRIVER_USAGE}`);
654
658
  }
655
659
  const effectiveDriver = driver ?? runtimeDriverConfig.defaultDriver;
656
660
  const modelSelection = resolveRuntimeModelSelection(effectiveDriver, model);
@@ -1137,7 +1141,7 @@ export default async function piCaLeashExtension(pi: ExtensionAPI) {
1137
1141
  task: { type: "string", description: "Task for the delegated run." },
1138
1142
  name: { type: "string", description: "Optional agent name for this run." },
1139
1143
  prompt: { type: "string", description: "Optional agent prompt. Defaults to a concise delegated-worker prompt." },
1140
- driver: { type: "string", enum: ["claude-sdk", "codex-cli"], description: "Optional runtime driver for this run." },
1144
+ driver: { type: "string", enum: [...RUNTIME_DRIVER_ENUM], description: "Optional runtime driver for this run." },
1141
1145
  model: { type: "string", description: "Optional model override for this run." },
1142
1146
  cwd: { type: "string", description: "Optional working directory for this run. Relative paths resolve from the current pi working directory." },
1143
1147
  async: { type: "boolean", description: "Launch as background run and return immediately." },
@@ -1300,7 +1304,7 @@ export default async function piCaLeashExtension(pi: ExtensionAPI) {
1300
1304
  properties: {
1301
1305
  name: { type: "string", description: "Teammate name." },
1302
1306
  prompt: { type: "string", description: "Teammate bootstrap prompt." },
1303
- driver: { type: "string", enum: ["claude-sdk", "codex-cli"], description: "Optional runtime driver for this teammate." },
1307
+ driver: { type: "string", enum: [...RUNTIME_DRIVER_ENUM], description: "Optional runtime driver for this teammate." },
1304
1308
  model: { type: "string", description: "Optional model override." },
1305
1309
  cwd: { type: "string", description: "Optional working directory. Relative paths resolve from the current pi working directory." },
1306
1310
  },
@@ -1539,7 +1543,21 @@ export default async function piCaLeashExtension(pi: ExtensionAPI) {
1539
1543
 
1540
1544
  async function handleDashboardCommand(args: string, ctx: ExtensionCommandContext, command: string): Promise<void> {
1541
1545
  await activatePeerMode(ctx, { command, reason: "Peer mode activated" });
1542
- const advanced = args.trim().toLowerCase() === "advanced";
1546
+ const normalizedArgs = args.trim().toLowerCase();
1547
+ if (["hide", "off", "close", "clear", "minimize", "minimise"].includes(normalizedArgs)) {
1548
+ peerDashboardHidden = true;
1549
+ ctx.ui.setWidget("peer-dashboard", undefined);
1550
+ ctx.ui.notify("Peers widget hidden. Use /peer dashboard show to restore it.", "info");
1551
+ return;
1552
+ }
1553
+ if (["show", "on", "open", "restore"].includes(normalizedArgs)) {
1554
+ peerDashboardHidden = false;
1555
+ lastWidgetSignature = undefined;
1556
+ const data = await refreshDashboard(ctx, runtime, bridge, subagents, teams, dashboardState, attentionLedger, "Peers widget restored");
1557
+ ctx.ui.notify(`Peers widget restored (${data.peers.length} peer${data.peers.length === 1 ? "" : "s"}).`, "info");
1558
+ return;
1559
+ }
1560
+ const advanced = normalizedArgs === "advanced";
1543
1561
  await syncAttentionLedger();
1544
1562
  const data = await refreshDashboard(ctx, runtime, bridge, subagents, teams, dashboardState, attentionLedger);
1545
1563
  const health = getPeerFirstHealth(data.snapshot.peerRows, data.snapshot.transportDegraded);
@@ -1901,7 +1919,7 @@ export default async function piCaLeashExtension(pi: ExtensionAPI) {
1901
1919
  `/${command} ask <name> | <message>`,
1902
1920
  `/${command} send <name> | <message>`,
1903
1921
  `/${command} list`,
1904
- `/${command} models [claude-sdk|codex-cli] [all|advanced|verbose]`,
1922
+ `/${command} models [claude-sdk|claude-cli|codex-cli] [all|advanced|verbose]`,
1905
1923
  `/${command} history <name> [cursor] [limit]`,
1906
1924
  `/${command} interrupt <name>`,
1907
1925
  `/${command} stop <name>`,
@@ -1910,7 +1928,7 @@ export default async function piCaLeashExtension(pi: ExtensionAPI) {
1910
1928
  "Driver/model forms",
1911
1929
  `/${command} start <prompt> | <driver> | <model>`,
1912
1930
  `/${command} start <name> | <prompt> | <driver> | <model>`,
1913
- "drivers: claude-sdk, codex-cli",
1931
+ `drivers: ${RUNTIME_DRIVER_USAGE}`,
1914
1932
  "model aliases: sonnet, opus, haiku, mini, spark; exact ids are shown by /peer models",
1915
1933
  "",
1916
1934
  "Version/environment",
@@ -1938,7 +1956,7 @@ export default async function piCaLeashExtension(pi: ExtensionAPI) {
1938
1956
  });
1939
1957
  }
1940
1958
 
1941
- registerExtensionCommand(pi, "peer", "Peer dashboard and controls. Args: [about|init|dashboard|start|ask|send|list|models|history|interrupt|stop] ...", async (args, ctx) => {
1959
+ registerExtensionCommand(pi, "peer", "Peer dashboard and controls. Args: [about|init|dashboard [hide|show|advanced]|start|ask|send|list|models|history|interrupt|stop] ...", async (args, ctx) => {
1942
1960
  const trimmed = args.trim();
1943
1961
  if (!trimmed) {
1944
1962
  await activatePeerMode(ctx, { command: "peer", showGuide: true, reason: "Peer mode activated" });
@@ -1965,6 +1983,16 @@ export default async function piCaLeashExtension(pi: ExtensionAPI) {
1965
1983
  await activatePeerMode(ctx, { command: "peer dashboard", showGuide: true, reason: "Peer mode activated" });
1966
1984
  await handleDashboardCommand(rest, ctx, "peer dashboard");
1967
1985
  return;
1986
+ case "hide":
1987
+ case "minimize":
1988
+ case "minimise":
1989
+ await activatePeerMode(ctx, { command: "peer dashboard hide", showGuide: true, reason: "Peer mode activated" });
1990
+ await handleDashboardCommand("hide", ctx, "peer dashboard hide");
1991
+ return;
1992
+ case "show":
1993
+ await activatePeerMode(ctx, { command: "peer dashboard show", showGuide: true, reason: "Peer mode activated" });
1994
+ await handleDashboardCommand("show", ctx, "peer dashboard show");
1995
+ return;
1968
1996
  case "start":
1969
1997
  await activatePeerMode(ctx, { command: "peer start", showGuide: true, reason: "Peer mode activated" });
1970
1998
  await handlePeerStartCommand(rest, ctx, "peer start");
@@ -2425,6 +2453,10 @@ async function refreshDashboard(
2425
2453
 
2426
2454
  if (!process.argv.includes("--no-session")) {
2427
2455
  ctx.ui.setStatus(EXTENSION_NAME, undefined);
2456
+ if (peerDashboardHidden) {
2457
+ ctx.ui.setWidget("peer-dashboard", undefined);
2458
+ return data;
2459
+ }
2428
2460
  const newSignature = computeWidgetSignature({
2429
2461
  peerRows: data.snapshot.peerRows.filter(isPeerVisibleInWidget),
2430
2462
  transportDegraded: data.snapshot.transportDegraded,
@@ -2683,7 +2715,7 @@ function completePeerCommand(prefix: string, names: Set<string>): AutocompleteIt
2683
2715
  }
2684
2716
  if (subcommand === "models") {
2685
2717
  const trimmed = restParts.join(" ").trim();
2686
- const items = ["claude-sdk", "codex-cli"]
2718
+ const items = [...RUNTIME_DRIVER_ENUM]
2687
2719
  .filter((driver) => trimmed.length === 0 || driver.startsWith(trimmed))
2688
2720
  .map((driver) => ({ value: driver, label: driver }));
2689
2721
  return items.length > 0 ? items : null;
@@ -2972,8 +3004,8 @@ function formatAttentionReport(attention: AttentionView[]): string {
2972
3004
  );
2973
3005
  }
2974
3006
 
2975
- function parsePeerModelsArgs(args: string): { driver?: "claude-sdk" | "codex-cli"; verbose: boolean } {
2976
- let driver: "claude-sdk" | "codex-cli" | undefined;
3007
+ function parsePeerModelsArgs(args: string): { driver?: (typeof RUNTIME_DRIVER_ENUM)[number]; verbose: boolean } {
3008
+ let driver: (typeof RUNTIME_DRIVER_ENUM)[number] | undefined;
2977
3009
  let verbose = false;
2978
3010
  for (const token of args.trim().split(/\s+/).filter(Boolean)) {
2979
3011
  const parsedDriver = parseRuntimeDriverName(token);
@@ -2985,7 +3017,7 @@ function parsePeerModelsArgs(args: string): { driver?: "claude-sdk" | "codex-cli
2985
3017
  verbose = true;
2986
3018
  continue;
2987
3019
  }
2988
- throw new Error("usage: /peer models [claude-sdk|codex-cli] [all|advanced|verbose]");
3020
+ throw new Error("usage: /peer models [claude-sdk|claude-cli|codex-cli] [all|advanced|verbose]");
2989
3021
  }
2990
3022
  return { driver, verbose };
2991
3023
  }
@@ -3173,9 +3205,13 @@ function compactModel(model: string): string {
3173
3205
  function compactDriver(driver: string): string {
3174
3206
  switch (driver) {
3175
3207
  case "claude-sdk":
3208
+ return "sdk";
3209
+ case "claude-cli":
3176
3210
  return "claude";
3177
3211
  case "codex-cli":
3178
3212
  return "codex";
3213
+ case "pi-coding-agent":
3214
+ return "pi-ca";
3179
3215
  default:
3180
3216
  return driver.length > 7 ? `${driver.slice(0, 6)}…` : driver;
3181
3217
  }
@@ -13,7 +13,7 @@ export interface RuntimeModelCatalogEntry {
13
13
 
14
14
  export interface RuntimeDriverModelCatalog {
15
15
  driver: RuntimeDriverName;
16
- provider: "anthropic" | "openai-codex";
16
+ provider: "anthropic" | "openai-codex" | "pi-ai";
17
17
  defaultModel: string;
18
18
  aliases: Record<string, string>;
19
19
  recommendations: RuntimeModelRecommendation[];
@@ -39,7 +39,7 @@ export interface RuntimeModelSelection {
39
39
 
40
40
  const LANISTA_SOURCE = "lanista agents anthropic/codex";
41
41
 
42
- export const RUNTIME_MODEL_CATALOGS: Record<RuntimeDriverName, RuntimeDriverModelCatalog> = {
42
+ export const RUNTIME_MODEL_CATALOGS: Record<string, RuntimeDriverModelCatalog> = {
43
43
  "claude-sdk": {
44
44
  driver: "claude-sdk",
45
45
  provider: "anthropic",
@@ -108,7 +108,7 @@ export const RUNTIME_MODEL_CATALOGS: Record<RuntimeDriverName, RuntimeDriverMode
108
108
  { id: "gpt-5.2", name: "GPT-5.2", contextWindow: 272000, maxTokens: 128000, reasoning: true, inputModalities: ["text", "image"], inputCostPerMillion: 1.75, outputCostPerMillion: 14 },
109
109
  { id: "gpt-5.2-codex", name: "GPT-5.2 Codex", contextWindow: 272000, maxTokens: 128000, reasoning: true, inputModalities: ["text", "image"], inputCostPerMillion: 1.75, outputCostPerMillion: 14 },
110
110
  { id: "gpt-5.3-codex", name: "GPT-5.3 Codex", contextWindow: 272000, maxTokens: 128000, reasoning: true, inputModalities: ["text", "image"], inputCostPerMillion: 1.75, outputCostPerMillion: 14 },
111
- { id: "gpt-5.3-codex-spark", name: "GPT-5.3 Codex Spark", contextWindow: 128000, maxTokens: 128000, reasoning: true, inputModalities: ["text"], inputCostPerMillion: 0, outputCostPerMillion: 0 },
111
+ { id: "gpt-5.3-codex-spark", name: "GPT-5.3 Codex Spark", contextWindow: 128000, maxTokens: 128000, reasoning: true, inputModalities: ["text"], inputCostPerMillion: 3.5, outputCostPerMillion: 28 },
112
112
  { id: "gpt-5.4", name: "GPT-5.4", contextWindow: 272000, maxTokens: 128000, reasoning: true, inputModalities: ["text", "image"], inputCostPerMillion: 2.5, outputCostPerMillion: 15 },
113
113
  { id: "gpt-5.4-mini", name: "GPT-5.4 Mini", contextWindow: 272000, maxTokens: 128000, reasoning: true, inputModalities: ["text", "image"], inputCostPerMillion: 0.75, outputCostPerMillion: 4.5 },
114
114
  { id: "gpt-5.5", name: "GPT-5.5", contextWindow: 272000, maxTokens: 128000, reasoning: true, inputModalities: ["text", "image"], inputCostPerMillion: 5, outputCostPerMillion: 30 },
@@ -118,18 +118,26 @@ export const RUNTIME_MODEL_CATALOGS: Record<RuntimeDriverName, RuntimeDriverMode
118
118
 
119
119
  export function modelCatalogsForDriver(driver?: RuntimeDriverName): RuntimeDriverModelCatalog[] {
120
120
  if (driver) {
121
- return [RUNTIME_MODEL_CATALOGS[driver]];
121
+ return [catalogForDriver(driver)];
122
122
  }
123
- return [RUNTIME_MODEL_CATALOGS["claude-sdk"], RUNTIME_MODEL_CATALOGS["codex-cli"]];
123
+ // claude-cli intentionally omitted: the driver is unstable in practice
124
+ // (sticky-session / non-interactive output issues), so it is not part of
125
+ // the recommended runtime surface. Callers that explicitly request it
126
+ // via catalogForDriver("claude-cli") will throw.
127
+ return [
128
+ catalogForDriver("claude-sdk"),
129
+ catalogForDriver("codex-cli"),
130
+ catalogForDriver("pi-coding-agent"),
131
+ ];
124
132
  }
125
133
 
126
134
  export function findRuntimeModel(driver: RuntimeDriverName, model: string): RuntimeModelCatalogEntry | undefined {
127
135
  const normalized = model.trim();
128
- return RUNTIME_MODEL_CATALOGS[driver].models.find((entry) => entry.id === normalized);
136
+ return catalogForDriver(driver).models.find((entry) => entry.id === normalized);
129
137
  }
130
138
 
131
139
  export function resolveRuntimeModelSelection(driver: RuntimeDriverName, model?: string): RuntimeModelSelection {
132
- const catalog = RUNTIME_MODEL_CATALOGS[driver];
140
+ const catalog = catalogForDriver(driver);
133
141
  const requestedModel = model?.trim() || undefined;
134
142
  if (!requestedModel) {
135
143
  return {
@@ -168,6 +176,31 @@ export function resolveRuntimeModelSelection(driver: RuntimeDriverName, model?:
168
176
  };
169
177
  }
170
178
 
179
+ function catalogForDriver(driver: RuntimeDriverName): RuntimeDriverModelCatalog {
180
+ if (driver === "claude-cli") {
181
+ throw new Error(
182
+ "claude-cli driver is no longer supported by the runtime model catalog " +
183
+ "(driver retired due to sticky-session / non-interactive output issues). " +
184
+ "Use claude-sdk for Claude models.",
185
+ );
186
+ }
187
+ if (driver === "pi-coding-agent") {
188
+ // pi-coding-agent routes through pi-ai, which only proxies gpt-* models
189
+ // in our environment. Inherit the codex-cli catalog so recommendations
190
+ // and model entries advertise the actually-supported set.
191
+ const base = RUNTIME_MODEL_CATALOGS["codex-cli"]!;
192
+ return {
193
+ ...base,
194
+ driver,
195
+ provider: "pi-ai",
196
+ cli: "pi",
197
+ flag: "pi --model <provider>/<id>",
198
+ source: `${base.source}; shared with codex-cli catalog (pi-coding-agent routes through pi-ai to gpt-* models)`,
199
+ };
200
+ }
201
+ return RUNTIME_MODEL_CATALOGS[driver]!;
202
+ }
203
+
171
204
  export function describeModelSelection(driver: RuntimeDriverName, model?: string): string | undefined {
172
205
  return resolveRuntimeModelSelection(driver, model).note;
173
206
  }
@@ -1,7 +1,7 @@
1
1
  Start a long-lived runtime-backed peer for delegated work. Returns peer name, state, session id, driver, model, cwd, and latest visible peer reply when available.
2
2
  - Use `peer_start` when you want a reusable long-lived peer instead of solving the task in the current turn.
3
3
  - Pass `name` only when you need a stable explicit peer name; otherwise let the tool auto-name from prompt.
4
- - Pass `driver` when you need to force `claude-sdk` or `codex-cli` for this peer instead of using the extension default.
4
+ - Pass `driver` when you need to force `claude-sdk`, `claude-cli`, or `codex-cli` for this peer instead of using the extension default.
5
5
  - Call `runtime_models` first when you need the supported model ids for a driver.
6
6
  - Pass `model` and `cwd` when you need a specific model and working directory.
7
7
  - Keep bootstrap prompts scoped. If the tool reports a prompt size warning, start a smaller peer and point it at files instead of pasting large context.
@@ -1,6 +1,6 @@
1
- Inspect available model ids for claude-sdk and codex-cli before passing a model override to peer_start, peer_ask, subagent_run, or team_spawn.
1
+ Inspect available model ids for claude-sdk, claude-cli, and codex-cli before passing a model override to peer_start, peer_ask, subagent_run, or team_spawn.
2
2
  - Use `runtime_models` before choosing a non-default model.
3
- - Use `driver` to narrow results to `claude-sdk` or `codex-cli`.
3
+ - Use `driver` to narrow results to `claude-sdk`, `claude-cli`, or `codex-cli`.
4
4
  - Default output is a short recommended list with advisory use cases; pass `verbose: true` only when you need every bundled model id.
5
5
  - The report includes supported shorthand aliases. For example, Claude aliases such as `sonnet`, `opus`, and `haiku` are resolved to concrete model ids before launch.
6
6
  - Catalog entries are advisory; provider and CLI entitlements can drift, so unknown model ids are passed through to the runtime.
@@ -1,6 +1,6 @@
1
1
  Run a delegated subagent task through the local backend. Supports driver, model, cwd, and optional async execution.
2
2
  - Use `subagent_run` when you need a bounded delegated run instead of a reusable peer.
3
- - Pass `driver` to force `claude-sdk` or `codex-cli` for this run instead of using the extension default.
3
+ - Pass `driver` to force `claude-sdk`, `claude-cli`, or `codex-cli` for this run instead of using the extension default.
4
4
  - Call `runtime_models` first when you need the supported model ids for a driver.
5
5
  - Pass `async: true` when you want to launch a background run and inspect it later with `subagent_status` or `subagent_list`.
6
6
  - Keep delegated tasks bounded. If the tool reports a prompt size warning, split the run into smaller slices.
@@ -1,5 +1,5 @@
1
1
  Spawn a persistent teammate when you want a named worker you can task or message repeatedly.
2
2
  - Use `team_spawn` for a persistent named worker, not for one-off bounded work.
3
- - Pass `driver` to force `claude-sdk` or `codex-cli` for this teammate instead of using the extension default.
3
+ - Pass `driver` to force `claude-sdk`, `claude-cli`, or `codex-cli` for this teammate instead of using the extension default.
4
4
  - Call `runtime_models` first when you need the supported model ids for a driver.
5
5
  - Keep the teammate bootstrap prompt compact; give detailed work through later `team_task` or `team_message` calls.