@saccolabs/pi-claude-cli 0.4.15 → 0.4.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -100,10 +100,17 @@ timeout (CLI-side tools can be silent on stdout for minutes).
100
100
  `PI_CLAUDE_CLI_SYSTEM_PROMPT` chooses whose system prompt the subprocess
101
101
  runs under. It is read per spawn, so a host can change it between sessions.
102
102
 
103
- | Value | Behaviour |
104
- | -------------------- | ------------------------------------------------------------------------- |
105
- | `claude` _(default)_ | `--append-system-prompt`: pi's prompt layers on top of Claude Code's own. |
106
- | `pi` | `--system-prompt`: pi's prompt replaces Claude Code's entirely. |
103
+ | Value | Behaviour |
104
+ | -------------------- | ------------------------------------------------------------------------------ |
105
+ | `claude` _(default)_ | `--append-system-prompt-file`: pi's prompt layers on top of Claude Code's own. |
106
+ | `pi` | `--system-prompt-file`: pi's prompt replaces Claude Code's entirely. |
107
+
108
+ The `-file` suffix matters: `--system-prompt` / `--append-system-prompt`
109
+ (unsuffixed) take a **literal string**, not a path. Passing a temp-file path
110
+ to the unsuffixed flag makes the path itself the prompt — pi's instructions
111
+ never reach the model, silently, with no error. This shipped unnoticed since
112
+ the provider's system-prompt support was first added; see the correction
113
+ below.
107
114
 
108
115
  `minimal` is accepted as an alias for `pi`, `append` for `claude`; anything
109
116
  unrecognised falls back to the default rather than failing a session.
@@ -127,7 +134,7 @@ restyles its prompt so the `Available tools:` / `Guidelines:` anchors are
127
134
  missing, the prompt passes through untouched rather than being mangled.
128
135
 
129
136
  The system prompt goes on **every** spawn, not just the session-creating one:
130
- the CLI does not keep `--system-prompt` across `--resume`, and a resumed
137
+ the CLI does not keep `--system-prompt-file` across `--resume`, and a resumed
131
138
  session without it silently reverts to Claude Code's default prompt from turn
132
139
  2 onwards. Because an identical prefix is what keeps the prompt cache warm,
133
140
  the prompt a session was created with is stored in the sidecar
@@ -135,6 +142,18 @@ the prompt a session was created with is stored in the sidecar
135
142
  verbatim rather than rebuilt. A change to the mode therefore takes effect on
136
143
  the next new session, not the current one.
137
144
 
145
+ > **Correction (2026-08-29).** Both bullets above named the unsuffixed flags
146
+ > until this date. They were wrong the whole time the provider has supported a
147
+ > system prompt: `--system-prompt` / `--append-system-prompt` take a literal
148
+ > string, and the provider was handing them a temp-file path. That path string
149
+ > either became the entire "system prompt" (`pi` mode) or got appended as
150
+ > noise Claude Code's model ignored (`claude` mode) — either way, pi's actual
151
+ > instructions never reached the model, on ANY turn, since the very first spawn.
152
+ > Fixed by switching to `--system-prompt-file` / `--append-system-prompt-file`,
153
+ > which take a path. See
154
+ > [pidex's write-up](https://github.com/agustinsacco/pidex/blob/main/specs/log/2026-08-29-claude-cli-lifecycle-verification.md)
155
+ > for the live before/after.
156
+
138
157
  ## License
139
158
 
140
159
  MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saccolabs/pi-claude-cli",
3
- "version": "0.4.15",
3
+ "version": "0.4.16",
4
4
  "description": "Pi coding agent extension that routes LLM calls through the Claude Code CLI",
5
5
  "main": "index.ts",
6
6
  "keywords": [
@@ -22,8 +22,9 @@ import {
22
22
  *
23
23
  * @param modelId - The model ID to pass via --model flag
24
24
  * @param systemPrompt - Optional system prompt. In `claude` mode it is appended
25
- * to Claude Code's own via --append-system-prompt; in `pi` mode it replaces
26
- * it via --system-prompt. See src/system-prompt-mode.ts.
25
+ * to Claude Code's own via --append-system-prompt-file; in `pi` mode it
26
+ * replaces it via --system-prompt-file. The `-file` suffix is required: the
27
+ * unsuffixed flags take a literal string. See src/system-prompt-mode.ts.
27
28
  * @param options - Optional cwd, AbortSignal, effort level and prompt mode
28
29
  * @returns The spawned ChildProcess with piped stdin/stdout/stderr
29
30
  */
@@ -98,8 +99,16 @@ export function spawnClaude(
98
99
  }
99
100
 
100
101
  if (systemPrompt) {
101
- // Write system prompt to a temp file to avoid ENAMETOOLONG on Windows.
102
- // Both flags accept a file path or literal text.
102
+ // Write the system prompt to a temp file and pass the FILE flags.
103
+ //
104
+ // `--system-prompt` / `--append-system-prompt` take a literal string, NOT
105
+ // a path: handing them a path makes the path itself the system prompt, so
106
+ // pi's instructions never reach the model and the session silently runs on
107
+ // Claude Code's defaults. Verified on claude 2.1.231 — with a path the
108
+ // model denied having the codename its prompt assigned; with
109
+ // `--system-prompt-file` it answered correctly. The file variants also keep
110
+ // the prompt off the command line, which is what avoids ENAMETOOLONG on
111
+ // Windows.
103
112
  //
104
113
  // Keyed by CLI session, not just pid: the prompt goes on every spawn
105
114
  // (see provider.ts), and pi can run two turns of one process at once —
@@ -113,7 +122,7 @@ export function spawnClaude(
113
122
  // pi's on top of it. See src/system-prompt-mode.ts for the trade-off.
114
123
  const mode = options?.systemPromptMode ?? DEFAULT_SYSTEM_PROMPT_MODE;
115
124
  args.push(
116
- mode === "pi" ? "--system-prompt" : "--append-system-prompt",
125
+ mode === "pi" ? "--system-prompt-file" : "--append-system-prompt-file",
117
126
  tmpFile,
118
127
  );
119
128
  }
@@ -409,10 +409,11 @@ export function rewritePiToolSections(systemPrompt: string): string {
409
409
  * appending AGENTS.md content if found (walking up from cwd, then global fallback).
410
410
  * Sanitizes .pi references to .claude for Claude Code compatibility.
411
411
  *
412
- * In `pi` mode the caller passes the prompt to `--system-prompt`, replacing
413
- * Claude Code's own, so pi's tool sections are rewritten into Claude Code's
414
- * names first. In `claude` mode the prompt is appended to Claude Code's and
415
- * pi's wording is left exactly as pi wrote it.
412
+ * In `pi` mode the caller passes the prompt to `--system-prompt-file`,
413
+ * replacing Claude Code's own, so pi's tool sections are rewritten into Claude
414
+ * Code's names first. In `claude` mode the prompt is appended to Claude
415
+ * Code's (`--append-system-prompt-file`) and pi's wording is left exactly as
416
+ * pi wrote it.
416
417
  */
417
418
  export function buildSystemPrompt(
418
419
  context: { systemPrompt?: string; messages: any[] },
@@ -2,12 +2,16 @@
2
2
  * Which system prompt the Claude CLI subprocess runs under.
3
3
  *
4
4
  * `claude` (the default) appends pi's prompt to Claude Code's own via
5
- * `--append-system-prompt`. Everything the CLI normally knows about its
5
+ * `--append-system-prompt-file`. Everything the CLI normally knows about its
6
6
  * built-in tools stays in place, and pi's instructions ride on top.
7
7
  *
8
- * `pi` replaces Claude Code's prompt outright via `--system-prompt`, leaving
9
- * only pi's — the point of a minimal harness being that it does not inherit
10
- * another agent's preamble.
8
+ * `pi` replaces Claude Code's prompt outright via `--system-prompt-file`,
9
+ * leaving only pi's — the point of a minimal harness being that it does not
10
+ * inherit another agent's preamble.
11
+ *
12
+ * The `-file` suffix is not optional: the unsuffixed flags take a literal
13
+ * string, and passing them a path (as this provider did until 2026-08-29)
14
+ * makes the path itself the prompt, silently. See process-manager.ts.
11
15
  *
12
16
  * Sizing, measured rather than assumed: in a real session the CLI's fixed
13
17
  * cached prefix sat at 17,475 tokens. That is Claude Code's system prompt