one-code-extension 0.1.4 → 0.3.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 (300) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +200 -172
  3. package/agents/explore.md +9 -6
  4. package/agents/general-purpose.md +1 -1
  5. package/agents/plan.md +6 -4
  6. package/docs/guide/README.md +52 -0
  7. package/docs/guide/bring-your-claude-code-setup.md +126 -0
  8. package/docs/guide/configuration.md +171 -0
  9. package/docs/guide/differences-from-claude-code.md +150 -0
  10. package/docs/guide/doctor.md +86 -0
  11. package/docs/guide/hooks.md +109 -0
  12. package/docs/guide/installation.md +124 -0
  13. package/docs/guide/permissions-modes-and-auto-mode.md +450 -0
  14. package/docs/guide/providers-and-models.md +194 -0
  15. package/docs/guide/reference.md +224 -0
  16. package/docs/guide/sessions-and-context.md +190 -0
  17. package/docs/guide/skills-plugins-and-mcp.md +176 -0
  18. package/docs/guide/subagents-and-workflows.md +193 -0
  19. package/docs/guide/tasks-and-background-work.md +111 -0
  20. package/docs/guide/terminal-interface.md +155 -0
  21. package/docs/guide/tools.md +175 -0
  22. package/docs/guide/troubleshooting.md +175 -0
  23. package/extensions/ask-user/index.ts +65 -71
  24. package/extensions/ask-user/questions.ts +15 -28
  25. package/extensions/ask-user/widget.ts +533 -0
  26. package/extensions/auto-mode/actions.ts +9 -26
  27. package/extensions/auto-mode/classifier-prompt.ts +127 -0
  28. package/extensions/auto-mode/classifier.ts +305 -227
  29. package/extensions/auto-mode/config.ts +279 -77
  30. package/extensions/auto-mode/defaults.ts +17 -60
  31. package/extensions/auto-mode/instructions.ts +2 -1
  32. package/extensions/auto-mode/model-picker.ts +53 -31
  33. package/extensions/auto-mode/model-select.ts +153 -82
  34. package/extensions/auto-mode/paths.ts +13 -1
  35. package/extensions/auto-mode/pause.ts +8 -0
  36. package/extensions/auto-mode/prompt.ts +205 -238
  37. package/extensions/auto-mode/recoverability.ts +229 -0
  38. package/extensions/auto-mode/rules.ts +92 -75
  39. package/extensions/auto-mode/safety-floor.ts +43 -12
  40. package/extensions/auto-mode/sensitive.ts +11 -0
  41. package/extensions/auto-mode/setup-run.ts +245 -0
  42. package/extensions/auto-mode/setup.ts +235 -0
  43. package/extensions/auto-mode/shell-analysis.ts +332 -26
  44. package/extensions/auto-mode/transcript.ts +102 -0
  45. package/extensions/background/index.ts +256 -43
  46. package/extensions/background/monitor-batch.ts +58 -0
  47. package/extensions/background/registry.ts +9 -0
  48. package/extensions/background/wakeup.ts +45 -0
  49. package/extensions/bash/background.ts +47 -22
  50. package/extensions/bash/guards.ts +229 -0
  51. package/extensions/bash/index.ts +81 -19
  52. package/extensions/branding/index.ts +44 -18
  53. package/extensions/branding/startup.ts +23 -8
  54. package/extensions/claude-compat/index.ts +17 -2
  55. package/extensions/claude-context/index.ts +41 -12
  56. package/extensions/clear/index.ts +27 -0
  57. package/extensions/compaction/fit.ts +121 -0
  58. package/extensions/compaction/index.ts +176 -71
  59. package/extensions/compaction/prompt.ts +21 -1
  60. package/extensions/context-budget/budget.ts +61 -0
  61. package/extensions/context-budget/index.ts +66 -0
  62. package/extensions/context-management/index.ts +40 -16
  63. package/extensions/doctor/build.ts +226 -0
  64. package/extensions/doctor/cli.ts +99 -0
  65. package/extensions/doctor/compat.ts +532 -0
  66. package/extensions/doctor/dependencies.ts +186 -0
  67. package/extensions/doctor/fix-prompt.ts +125 -0
  68. package/extensions/doctor/index.ts +308 -0
  69. package/extensions/doctor/models.ts +231 -0
  70. package/extensions/doctor/presets.ts +208 -0
  71. package/extensions/doctor/report.ts +189 -0
  72. package/extensions/doctor/update-lookup.ts +46 -0
  73. package/extensions/doctor/viewer.ts +124 -0
  74. package/extensions/effort/index.ts +41 -4
  75. package/extensions/effort/slider.ts +33 -2
  76. package/extensions/file-tracker/index.ts +143 -20
  77. package/extensions/file-tracker/replay.ts +46 -0
  78. package/extensions/file-tracker/tracker.ts +51 -4
  79. package/extensions/footer/footer-line.ts +207 -0
  80. package/extensions/footer/index.ts +152 -0
  81. package/extensions/footer/pr.ts +53 -0
  82. package/extensions/hooks/executor.ts +57 -20
  83. package/extensions/hooks/formatter-notice.ts +76 -0
  84. package/extensions/hooks/index.ts +314 -73
  85. package/extensions/hooks/matcher.ts +35 -1
  86. package/extensions/hooks/plugin-hooks.ts +3 -3
  87. package/extensions/hooks/protocol.ts +58 -0
  88. package/extensions/hooks/subagent-bridge.ts +77 -0
  89. package/extensions/hooks/trust.ts +15 -4
  90. package/extensions/init/index.ts +26 -0
  91. package/extensions/init/prompt.ts +40 -0
  92. package/extensions/interrupted/index.ts +35 -0
  93. package/extensions/interrupted/line.ts +9 -0
  94. package/extensions/lib/abort.ts +15 -0
  95. package/extensions/lib/agent-loader.ts +183 -0
  96. package/extensions/lib/anthropic-payload.ts +15 -0
  97. package/extensions/lib/atomic-write.ts +56 -0
  98. package/extensions/lib/bridge-watch.ts +20 -0
  99. package/extensions/lib/cache-retention.ts +60 -0
  100. package/extensions/lib/capability-index.ts +466 -0
  101. package/extensions/lib/claude-context.ts +318 -27
  102. package/extensions/lib/claude-settings.ts +64 -0
  103. package/extensions/lib/consent-preview.ts +30 -0
  104. package/extensions/lib/deferred.ts +144 -13
  105. package/extensions/lib/favorites.ts +43 -0
  106. package/extensions/lib/fetch-timeout.ts +15 -0
  107. package/extensions/lib/frontmatter.ts +31 -0
  108. package/extensions/lib/git.ts +44 -2
  109. package/extensions/lib/hook-gate.ts +90 -0
  110. package/extensions/lib/interrupt.ts +94 -0
  111. package/extensions/lib/mcp-overrides.ts +61 -0
  112. package/extensions/lib/mcp-share.ts +25 -0
  113. package/extensions/lib/mcp-status.ts +34 -0
  114. package/extensions/lib/memory.ts +41 -6
  115. package/extensions/lib/model-facts.generated.json +2480 -0
  116. package/extensions/lib/model-facts.ts +162 -0
  117. package/extensions/lib/model-policy.ts +145 -189
  118. package/extensions/lib/model-tier.ts +480 -64
  119. package/extensions/lib/model-unusable.ts +37 -0
  120. package/extensions/lib/notifications.ts +320 -1
  121. package/extensions/lib/one-code-settings.ts +63 -0
  122. package/extensions/lib/original-command.ts +71 -0
  123. package/extensions/lib/package-version.ts +31 -0
  124. package/extensions/lib/paths.ts +39 -4
  125. package/extensions/lib/permission-gate.ts +192 -0
  126. package/extensions/lib/persisted-output.ts +18 -0
  127. package/extensions/lib/pi-ai-estimate.ts +160 -0
  128. package/extensions/lib/pi-version.ts +1 -1
  129. package/extensions/lib/plan-mode-channels.ts +11 -0
  130. package/extensions/lib/plugin-overrides.ts +24 -0
  131. package/extensions/lib/plugin-root.ts +44 -0
  132. package/extensions/lib/plugins.ts +233 -54
  133. package/extensions/lib/prefix-warm-gate.ts +157 -0
  134. package/extensions/lib/process-tree.ts +56 -0
  135. package/extensions/lib/reminders.ts +321 -68
  136. package/extensions/lib/scratchpad.ts +11 -8
  137. package/extensions/lib/session-lifecycle.ts +28 -0
  138. package/extensions/lib/settings-channels.ts +14 -0
  139. package/extensions/lib/shell-tasks.ts +54 -0
  140. package/extensions/lib/skill-overrides.ts +86 -0
  141. package/extensions/lib/skill-scan.ts +110 -0
  142. package/extensions/lib/text-width.ts +267 -0
  143. package/extensions/lib/tui-render.ts +281 -54
  144. package/extensions/lib/usage-bus.ts +75 -0
  145. package/extensions/lib/usage-tracker.ts +67 -0
  146. package/extensions/lib/worktree-isolation.ts +170 -0
  147. package/extensions/lsp/client.ts +69 -12
  148. package/extensions/lsp/format.ts +12 -2
  149. package/extensions/lsp/index.ts +273 -84
  150. package/extensions/lsp/install-hints.ts +43 -0
  151. package/extensions/lsp/keep-alive.ts +19 -0
  152. package/extensions/lsp/plugin-servers.ts +331 -0
  153. package/extensions/lsp/watcher.ts +157 -0
  154. package/extensions/mcp/announce.ts +99 -0
  155. package/extensions/mcp/client.ts +181 -22
  156. package/extensions/mcp/config.ts +55 -24
  157. package/extensions/mcp/index.ts +586 -86
  158. package/extensions/mcp/oauth/browser.ts +26 -0
  159. package/extensions/mcp/oauth/callback.ts +104 -0
  160. package/extensions/mcp/oauth/flow.ts +68 -0
  161. package/extensions/mcp/oauth/provider.ts +147 -0
  162. package/extensions/mcp/oauth/store.ts +86 -0
  163. package/extensions/mcp/panel/keys.ts +34 -0
  164. package/extensions/mcp/panel/model.ts +62 -0
  165. package/extensions/mcp/panel/render.ts +141 -0
  166. package/extensions/mcp/panel/state.ts +108 -0
  167. package/extensions/mcp/schema.ts +83 -6
  168. package/extensions/mcp/trust.ts +340 -0
  169. package/extensions/memory/entries.ts +163 -0
  170. package/extensions/memory/index.ts +119 -2
  171. package/extensions/memory/open-external.ts +97 -0
  172. package/extensions/memory/panel.ts +124 -0
  173. package/extensions/model-default/index.ts +74 -0
  174. package/extensions/notebook/index.ts +36 -18
  175. package/extensions/notebook/notebook.ts +110 -17
  176. package/extensions/permissions/index.ts +1012 -247
  177. package/extensions/permissions/matcher.ts +488 -57
  178. package/extensions/permissions/modes.ts +55 -7
  179. package/extensions/permissions/project-trust.ts +81 -0
  180. package/extensions/permissions/protected-paths.ts +16 -3
  181. package/extensions/permissions/rule-prose.ts +79 -0
  182. package/extensions/permissions/session-grant.ts +91 -0
  183. package/extensions/permissions/settings.ts +112 -33
  184. package/extensions/permissions/subagent-gate.ts +57 -0
  185. package/extensions/plan-mode/index.ts +143 -33
  186. package/extensions/plan-mode/reminder.ts +16 -19
  187. package/extensions/plan-mode/viewer.ts +40 -31
  188. package/extensions/plugins/counts.ts +68 -0
  189. package/extensions/plugins/index.ts +496 -32
  190. package/extensions/plugins/install/install.ts +167 -0
  191. package/extensions/plugins/install/paths.ts +23 -0
  192. package/extensions/plugins/install/registry.ts +72 -0
  193. package/extensions/plugins/marketplace/git.ts +103 -0
  194. package/extensions/plugins/marketplace/official.ts +36 -0
  195. package/extensions/plugins/marketplace/parse.ts +94 -0
  196. package/extensions/plugins/marketplace/registry.ts +60 -0
  197. package/extensions/plugins/marketplace/sync.ts +146 -0
  198. package/extensions/plugins/marketplace/types.ts +128 -0
  199. package/extensions/plugins/panel/keys.ts +52 -0
  200. package/extensions/plugins/panel/render.ts +315 -0
  201. package/extensions/plugins/panel/rows.ts +230 -0
  202. package/extensions/plugins/panel/state.ts +333 -0
  203. package/extensions/recap/index.ts +215 -0
  204. package/extensions/recap/prompt.ts +44 -0
  205. package/extensions/recap/scheduler.ts +87 -0
  206. package/extensions/search-tools/index.ts +0 -0
  207. package/extensions/search-tools/tools.ts +7 -5
  208. package/extensions/skill/index.ts +360 -34
  209. package/extensions/skill/invoke.ts +185 -0
  210. package/extensions/skill/listing.ts +21 -0
  211. package/extensions/skill/panel/keys.ts +41 -0
  212. package/extensions/skill/panel/render.ts +91 -0
  213. package/extensions/skill/panel/state.ts +115 -0
  214. package/extensions/spinner/index.ts +110 -0
  215. package/extensions/spinner/line.ts +51 -0
  216. package/extensions/spinner/verbs.ts +201 -0
  217. package/extensions/subagents/agents.ts +88 -44
  218. package/extensions/subagents/default-model.ts +62 -32
  219. package/extensions/subagents/delegation-steer.ts +23 -0
  220. package/extensions/subagents/hand-back-review.ts +67 -0
  221. package/extensions/subagents/index.ts +1545 -346
  222. package/extensions/subagents/live-runs.ts +293 -0
  223. package/extensions/subagents/model-select.ts +252 -82
  224. package/extensions/subagents/outcome.ts +90 -0
  225. package/extensions/subagents/panel-keys.ts +41 -0
  226. package/extensions/subagents/panel-render.ts +357 -0
  227. package/extensions/subagents/panel-widget.ts +330 -0
  228. package/extensions/subagents/pending-claim.ts +45 -0
  229. package/extensions/subagents/prose.ts +105 -0
  230. package/extensions/subagents/runner.ts +674 -0
  231. package/extensions/subagents/runs.ts +68 -1
  232. package/extensions/subagents/send-to-main-tool.ts +55 -0
  233. package/extensions/subagents/session-turns.ts +138 -0
  234. package/extensions/subagents/shell-panel.ts +198 -0
  235. package/extensions/subagents/usage.ts +16 -4
  236. package/extensions/subagents/worktree.ts +13 -0
  237. package/extensions/system-prompt/environment.ts +5 -3
  238. package/extensions/system-prompt/git-status.ts +93 -0
  239. package/extensions/system-prompt/index.ts +23 -1
  240. package/extensions/system-prompt/template.ts +34 -4
  241. package/extensions/system-prompt/tiers/common.ts +31 -6
  242. package/extensions/system-prompt/tiers/low.ts +13 -3
  243. package/extensions/system-prompt/tiers/mid.ts +21 -8
  244. package/extensions/system-reminder/index.ts +53 -9
  245. package/extensions/tasks/index.ts +65 -16
  246. package/extensions/tasks/store.ts +76 -3
  247. package/extensions/tool-search/announce.ts +42 -0
  248. package/extensions/tool-search/index.ts +136 -13
  249. package/extensions/turn-duration/index.ts +60 -0
  250. package/extensions/turn-duration/line.ts +22 -0
  251. package/extensions/turn-duration/span.ts +41 -0
  252. package/extensions/turn-duration/verbs.ts +24 -0
  253. package/extensions/web/backends.ts +421 -0
  254. package/extensions/web/index.ts +178 -21
  255. package/extensions/web-fetch/index.ts +74 -18
  256. package/extensions/web-fetch/summarize.ts +1 -1
  257. package/extensions/workflow/agent-session.ts +182 -112
  258. package/extensions/workflow/globals.ts +129 -106
  259. package/extensions/workflow/index.ts +343 -28
  260. package/extensions/workflow/records.ts +118 -0
  261. package/extensions/workflow/run-manager.ts +80 -31
  262. package/extensions/workflow/saved-workflows.ts +2 -1
  263. package/extensions/workflow/script-worker.mjs +110 -0
  264. package/extensions/workflow/types.ts +74 -8
  265. package/extensions/workflow/viewer.ts +562 -0
  266. package/extensions/workflow/vm-runtime.ts +118 -22
  267. package/extensions/workflow/widget.ts +126 -18
  268. package/extensions/worktree/guards.ts +240 -0
  269. package/extensions/worktree/index.ts +30 -5
  270. package/extensions/worktree/rewrite.ts +32 -16
  271. package/package.json +20 -10
  272. package/skills/code-review/SKILL.md +165 -0
  273. package/skills/fewer-permission-prompts/SKILL.md +61 -0
  274. package/skills/security-review/SKILL.md +178 -0
  275. package/skills/simplify/SKILL.md +70 -0
  276. package/themes/{one-code-light.json → onecode-light.json} +6 -1
  277. package/themes/{one-code.json → onecode.json} +6 -1
  278. package/types/app.d.ts +8 -1
  279. package/types/community-packages.d.ts +45 -2
  280. package/docs/decisions/auto-mode.md +0 -526
  281. package/docs/decisions/branding.md +0 -127
  282. package/docs/decisions/code-review-remediation.md +0 -106
  283. package/docs/decisions/compaction.md +0 -140
  284. package/docs/decisions/distribution.md +0 -168
  285. package/docs/decisions/hooks.md +0 -64
  286. package/docs/decisions/lsp.md +0 -58
  287. package/docs/decisions/mcp.md +0 -104
  288. package/docs/decisions/memory-state.md +0 -170
  289. package/docs/decisions/model-policy.md +0 -126
  290. package/docs/decisions/modes.md +0 -178
  291. package/docs/decisions/skills-plugins.md +0 -56
  292. package/docs/decisions/subagents-workflows.md +0 -225
  293. package/docs/decisions/system-prompt.md +0 -98
  294. package/docs/decisions/tools.md +0 -407
  295. package/docs/decisions/tui.md +0 -217
  296. package/docs/decisions.md +0 -148
  297. package/extensions/subagents/child.ts +0 -414
  298. package/extensions/subagents/rpc-turns.ts +0 -123
  299. package/extensions/todo/index.ts +0 -133
  300. package/extensions/workflow/permission-gate.ts +0 -71
@@ -1,56 +0,0 @@
1
- # Skills & plugins
2
-
3
- Part of [Decisions](../decisions.md).
4
-
5
- ## Skills and plugins
6
-
7
- **The `skill` tool.** pi's own skill mechanism lists skills in the system prompt
8
- and expects the model to `read` the SKILL.md path. Claude Code instead exposes a
9
- `Skill` tool that returns the instructions as a tool result, which is what makes
10
- `/skill-name` invocation work. `extensions/skill/` adds that: it indexes what pi
11
- already discovered (via `before_agent_start`'s `systemPromptOptions.skills`,
12
- rather than rediscovering) plus plugin skills, and returns the body with the
13
- skill's own path so relative `references/` and `scripts/` remain readable.
14
-
15
- **Plugins.** `extensions/plugins/` reads `~/.claude/plugins/installed_plugins.json`
16
- and wires each plugin's resources in, namespaced the way Claude Code namespaces
17
- them so two plugins can both ship a `commit`:
18
-
19
- | Plugin directory | Becomes |
20
- |---|---|
21
- | `agents/*.md` | subagents, as `<plugin>:<agent>` |
22
- | `skills/<name>/SKILL.md` | skills, as `<plugin>:<skill>` |
23
- | `commands/*.md` | slash commands, as `/<plugin>:<command>` |
24
- | `.mcp.json` | MCP servers |
25
-
26
- Command templates get full Claude Code expansion: `$ARGUMENTS`, `$@`, positional
27
- `$1`, and **`` !`command` `` substitution**, which is what makes plugin commands
28
- like `commit` work — the template gathers `git status` and `git diff` before the
29
- model sees the prompt. The expanded text is delivered as a user turn.
30
-
31
- Verified against a real installation (7 plugins): 7 namespaced agents, 3 skills
32
- listed and invocable, 7 commands registered, 2 MCP configs picked up, and
33
- `/commit-commands:commit` expanded with live git output embedded.
34
-
35
- Three findings from this work, each of which had been silently wrong:
36
-
37
- 1. **Module state is not shared between extension files.** Under jiti each
38
- extension gets its own module instance, so a shared registry singleton written
39
- by one extension reads as *empty* in another — no error, just nothing. The
40
- deferred-tool registry only worked because its data crossed via the event bus.
41
- Plugin discovery is therefore a function each consumer calls for itself
42
- (`discoverPlugins`, memoised per module).
43
- 2. **Real frontmatter is not always valid YAML.** pi's parser threw
44
- "Nested mappings are not allowed in compact mappings" on a genuine plugin
45
- agent whose unquoted `description:` contained `: `, and our `catch` dropped the
46
- whole definition — the file lost this way was, aptly,
47
- `silent-failure-hunter.md`. `parseAgentFile` now falls back to line-wise
48
- extraction. Also: `model: inherit` means "use the session model", not a model
49
- id.
50
- 3. **Never gate a loader behind a permission prompt.** The `skill` tool was
51
- blocked by our own permission system in non-interactive runs, and the same
52
- applied to `tool_search` — which would have made every deferred tool
53
- unreachable by default. Both are now auto-allowed along with `lsp_diagnostics`
54
- and `list_mcp_resources`; network egress and MCP calls still ask. This class of
55
- bug was invisible because earlier end-to-end tests all ran with
56
- `--dangerously-skip-permissions`.
@@ -1,225 +0,0 @@
1
- # Subagents & workflows
2
-
3
- Part of [Decisions](../decisions.md).
4
-
5
- ## Subagents: what matches Claude Code and what does not
6
-
7
- `extensions/subagents/` is our own (see the rejection of `pi-subagents` in
8
- [`distribution.md`](distribution.md#community-packages-adopted-where-they-work)).
9
- Agent definitions use Claude Code's markdown-plus-frontmatter format (`name`,
10
- `description`, `tools`, `model`), discovered lowest-to-highest precedence from
11
- the catalog bundled in this package (`agents/`), then `~/.claude/agents`, then
12
- `<project>/.claude/agents` — so an existing Claude Code agent file overrides a
13
- bundled one of the same name.
14
-
15
- **Bundled catalog.** Three definitions mirroring Claude Code's built-ins:
16
- `general-purpose` (full tool set), `explore` (read-only fan-out search),
17
- and `plan` (read-only architect). Claude Code's other built-ins are
18
- Anthropic-product specific (`claude-code-guide`, `statusline-setup`) and are not
19
- reproduced.
20
-
21
- **Implemented, verified live:**
22
-
23
- - Parallel runs, four concurrent.
24
- - Per-call `model` and `thinking` overrides (the agent file's frontmatter is the
25
- default). Verified a child running as `gpt-5.4` while the session ran 5.5.
26
- - **`agent: "fork"`** — a child that inherits the caller's full conversation.
27
- This is a flag, not an implementation: pi's `--fork <session file>` clones a
28
- session, and `ctx.sessionManager.getSessionFile()` gives us the path. Verified
29
- by planting a codeword in the parent transcript and having the forked child
30
- recite it. Requires a persisted session; `--no-session` returns a clear error.
31
- - **`isolation: "worktree"`** — `git worktree add` at HEAD on a throwaway branch,
32
- the child runs with that as cwd, and the worktree is removed afterwards *only
33
- if the agent changed nothing*; otherwise it is kept and its path reported so
34
- the work can be reviewed or merged. Verified: an agent's edit landed in the
35
- worktree, the main tree stayed clean, the dirty worktree survived, and a
36
- read-only run's worktree was cleaned up.
37
-
38
- - **`run_in_background: true`** — detached runs. The child spawns as a resident
39
- `--mode rpc` process, the tool returns a task id immediately, output is spooled
40
- to `<sessionDir>/subagents/<taskId>/output.log`, and completion is delivered as
41
- a system notification (pi's `sendMessage` with `deliverAs: "followUp"`). Managed
42
- with `task_output`/`task_stop` (`extensions/background/`); the run registry lives
43
- in `runs.ts`. Killed on `session_shutdown`, not handed across `/reload`.
44
- - **`send_message`** — reaches a resident background agent *live* (steered into
45
- its current turn, or a fresh turn when idle) or resumes a finished agent from
46
- its session file; a child can also `send_message {to: "main"}` to report
47
- mid-run. See `index.ts` and `rpc-turns.ts`.
48
-
49
- **Sharp edge (fixed 2026-08-07):** a run that omits `agent`/`tasks` but carries
50
- run options (`task`, `run_in_background`, a model override, …) now returns an
51
- explicit "no `agent` given" error instead of silently dumping the agent catalog.
52
- The old fallback conflated browse-intent with a run that forgot its agent; a
53
- weaker model (observed on deepseek-v4-flash) read the catalog as a non-sequitur
54
- and invented a wrong cause. `action:"list"` and a truly bare call still show the
55
- catalog.
56
-
57
- **Not implemented:** `isolation: "remote"`, which has no local equivalent.
58
-
59
- ## Permission modes and subagents
60
-
61
- Permission mode lives in the permissions extension and is exported to child
62
- processes via `CC_PERMISSION_MODE`; a child (marked by `PI_SUBAGENT_CHILD=1`)
63
- inherits it unless a flag overrides. Plan mode is enforced twice on purpose —
64
- the `tool_call` gate blocks mutations, and an every-turn `<system-reminder>`
65
- tells the model not to attempt them.
66
-
67
- ## Subagent model selection: resolved in the parent, advertised by reminder
68
-
69
- The subagent tool had the same model-selection faults the classifier was just
70
- cured of, with higher stakes: the `model` field (per-call, or `.claude/agents`
71
- frontmatter) was passed as a raw string to the child's `pi --model`, whose fuzzy
72
- matcher substring-matches across **every configured provider** — so
73
- `model: "sonnet"`, which is what real agent files and `CLAUDE_CODE_SUBAGENT_MODEL`
74
- say, resolved to an effectively arbitrary provider. A fork child inherits the
75
- parent's whole transcript, so the silent crossing ships the entire conversation.
76
- There was also no default knob (Claude Code's `CLAUDE_CODE_SUBAGENT_MODEL` was
77
- ignored, including from the settings `env` block) and no fallback (an
78
- unavailable model just failed the run in the child, its warning invisible).
79
-
80
- Resolution now happens in the parent (`subagents/model-select.ts`), against the
81
- real registry, and the child is spawned with a concrete `provider/id`:
82
-
83
- - **Aliases stay contained.** `sonnet|opus|haiku|fable` resolve by name within
84
- the session's provider (and upstream vendor on gateways), preferring undated
85
- ids; off-family ("sonnet" on Groq) the session model serves and the parent
86
- says so. `inherit` is the session model.
87
- - **Exact references resolve anywhere, never silently.** Naming a model is
88
- choosing it — but a provider crossing is announced, because the user
89
- configuring a key for a provider is not the user choosing to send this
90
- conversation there.
91
- - **Precedence:** per-call `model` > agent frontmatter > `subagentModel`
92
- setting > `CLAUDE_CODE_SUBAGENT_MODEL` (real env, then user/managed settings
93
- `env` block — project scope deliberately unread, same containment as
94
- `autoMode`) > session model. A bad *configured* value degrades to the session
95
- model with a notice naming the knob; only a bad *per-call* value errors,
96
- because the model that wrote it gets the menu and can retry.
97
- - **Passing the session model explicitly is itself a fix**: a child spawned with
98
- no `--model` picks pi's saved default, not the parent's current model, so a
99
- mid-session ctrl+p switch silently desynced children before.
100
-
101
- **The menu.** The main model needs to know what values are valid — Claude Code
102
- solves this with a static enum, possible only because it is single-provider. A
103
- tool-schema listing was rejected: the menu depends on the session model, which
104
- changes mid-session, and a schema rebuild throws away the whole cached prefix. A
105
- static schema line names the alias vocabulary; the catalog itself rides in a
106
- **keyed every-turn reminder** (`subagent-models`), which survives compaction by
107
- construction (reminders are transient per-request injections, never in the
108
- session file) and is replaced on `model_select`, so the next LLM call — even
109
- mid-turn — carries the update. Gateway catalogs (OpenRouter: 300+) are curated,
110
- not dumped: vendor-contained, `:batch`/`:free`/unpriced filtered, dated
111
- duplicates collapsed, capped at a handful of lines — safe because the menu is
112
- advertising, not a whitelist; resolution accepts unlisted models, and the
113
- reminder says so. The "nothing price-picked may lead" rule deliberately does
114
- not apply here: a cheap classifier fails open, a cheap subagent just does
115
- mediocre reviewed work, so price-ranked suggestions with prices shown are fine.
116
-
117
- Workflow's `agent()` shares the resolver (it used pi's `resolveCliModel` —
118
- same cross-provider fuzzy matching, in-process), keeping its `":high"` effort
119
- suffix and surfacing notices as run-log events. The banner shows
120
- `subagents <model>` when the resolved default differs from the session model
121
- (when it doesn't, the model line already says it); the banner's own model line
122
- also follows `model_select` now instead of freezing at startup.
123
-
124
- Verified live: the banner shows `subagents sonnet-5` from this machine's
125
- `CLAUDE_CODE_SUBAGENT_MODEL: "sonnet"` settings-env entry (previously ignored);
126
- the reminder appears in the captured provider request with the resolved default
127
- and prices; and a real `subagent` run spawned its child on
128
- `anthropic/claude-sonnet-5`, resolved from the alias in the parent.
129
-
130
- ## Workflow tool (ultracode orchestration)
131
-
132
- `docs/plan.md` originally scoped Claude Code's `Workflow` tool out as
133
- "Anthropic-server-backed, no local equivalent". That was wrong on both counts:
134
- the tool contract is fully knowable (script with a leading pure-literal
135
- `export const meta`, `agent()`/`parallel()`/`pipeline()`/`phase()`/`log()`/
136
- `args`/`budget` globals, background runs, `resumeFromRunId` journal replay),
137
- and QuintinShaw's `pi-dynamic-workflows` (npm, MIT) proves every piece runs
138
- fine on pi's public SDK. Adopting that package was considered and rejected —
139
- its tool surface diverges from Claude Code (model tiers, a verify/judgePanel
140
- quality stdlib, different parameter names) and it is a fifty-module dependency
141
- we would not control. `extensions/workflow/` reimplements the Claude Code
142
- contract natively in eleven modules, borrowing three proven mechanics from it:
143
- the acorn meta-lift (parse once, literal-walk the meta object so no code runs
144
- to extract it, splice the export out, wrap the rest in an async IIFE whose
145
- completion value `vm.runInContext` returns — this is what makes top-level
146
- `await` and bare `return` work), in-process subagents, and positional-index
147
- journal replay.
148
-
149
- Subagents are in-process `createAgentSession()` calls with
150
- `SessionManager.inMemory()`, not `pi --mode json` children like the subagent
151
- tool: a workflow can spawn hundreds of agents, and per-spawn process overhead
152
- plus JSONL re-parsing is pure waste when the SDK hands back typed events and
153
- `getSessionStats()`. One `ModelRuntime` and one `DefaultResourceLoader`
154
- (`noExtensions: true`) are built per run and shared across every agent —
155
- building the loader per agent re-runs every installed extension factory, and
156
- `noExtensions` also structurally blocks recursive orchestration. The sharp
157
- edge found during design: `noExtensions` drops One Code's permissions extension
158
- inside subagents too, so every bash/edit would run ungated. The fix relies on
159
- `DefaultResourceLoader` always loading explicitly passed `extensionFactories`
160
- even under `noExtensions`: `permission-gate.ts` reattaches a fail-closed inline
161
- gate reusing the pure permissions matcher (deny rules win; explicit allows
162
- allow; edits auto-allow, matching Claude Code's acceptEdits-for-subagents; an
163
- "ask" outcome becomes a deny, because no prompt UI exists inside an agent()
164
- call).
165
-
166
- `acorn` became the package's first parser dependency (runtime `dependencies`,
167
- not dev — consumers jiti-load raw .ts, so devDependencies never install).
168
- Zero-dep, ~hundreds of KB; TypeScript's own parser would have meant shipping
169
- tens of MB. The vm context is a determinism guard for resume replay
170
- (`Math.random`/`Date.now`/argless `new Date()` throw; a Proxy on the vm
171
- realm's own `Date` intercepts `now` and zero-arg construction), NOT a security
172
- sandbox — the injected `agent()` does real host work regardless. Background
173
- runs are the default (tool returns a runId; the report arrives via
174
- `pi.sendMessage(..., { deliverAs: "followUp", triggerTurn: true })`) and are
175
- deliberately killed on `session_shutdown` rather than handed off across
176
- `/reload`: the journal under `<sessionDir>/workflows/<runId>/` makes an
177
- aborted run cheap to resume with `resumeFromRunId`, which replays the longest
178
- prefix of agent() calls whose positional index and sha256(prompt+behavioral
179
- opts) still match. `parallel()` invokes all thunks synchronously before
180
- awaiting precisely so those indexes are deterministic under concurrency.
181
-
182
- Opt-in works the way Claude Code's does, which is a system-reminder and not
183
- model intuition: `pi.on("input")` matches `\bultracode\b` and emits a
184
- next-turn reminder on `one-code:system-reminder` ("The user included the keyword
185
- … use the workflow tool"), while the tool description carries the standing
186
- gate ("ONLY call when the user has explicitly opted in… a task that would
187
- merely benefit from a workflow does not count"). The description itself is
188
- ported from Claude Code's rather than summarised: its authoring guidance —
189
- pipeline-by-default with the barrier smell test, the canonical
190
- review→adversarially-verify pipeline, the quality-pattern catalogue, the
191
- "scale to what the user asked for" sizing rule — is what actually makes a
192
- model write good scripts, so trimming it would cost the feature more than the
193
- tokens save.
194
-
195
- `workflow` joins `subagent` in `AUTO_ALLOWED_TOOLS`. Found by running it: the
196
- first live `-p` run was blocked outright ("permission required but this session
197
- is non-interactive"), which would make the tool unusable headlessly. The note
198
- already next to `subagent` states the reasoning — orchestration is safe to
199
- *launch* because each spawned child enforces tool permissions itself — and it
200
- applies here more strongly, since a workflow script cannot touch the
201
- filesystem, network, or shell at all; only its agents can, and they run behind
202
- the gate above. A second live finding: that gate must exempt
203
- `structured_output`, the tool the runtime injects for schema'd calls. Without
204
- the exemption it fell to the fail-closed branch, every `schema` agent call
205
- returned null after burning its retries, and the run still reported success
206
- with a null hole in the result.
207
-
208
- Verified: 51 unit tests over the pure modules (meta lift/rejects, wrap
209
- round-trip through a real vm, limiter cap, parallel/pipeline null semantics,
210
- callIndex determinism under out-of-order completion, replay
211
- prefix/gap/carry-forward, gate allow/deny/ask-as-deny/internal-tool against
212
- fixture settings files) and `tsc --noEmit` clean, plus live runs against
213
- claude-haiku-4-5. Harness level (tmux, `-e` on this package): the tool reaches
214
- the provider payload and the arming reminder with it (confirmed in a
215
- `CC_E2E_LOG` capture); a sync run streamed phase/agent progress through
216
- `onUpdate` and returned `red+blue` from a two-agent `parallel()`; a background
217
- run of a saved `.claude/workflows/greet.js` returned its runId immediately and
218
- delivered `[workflow-result]` as a follow-up message; `/workflows` listed both
219
- the finished run and the saved workflow; the banner showed a `workflows`
220
- section. Runtime level: a three-call script (parallel fan-out plus a schema'd
221
- synthesis) journaled all three calls, and re-running it with `resumeFromRunId`
222
- replayed the whole prefix in 11ms with zero live calls and an identical
223
- result. Gate integration: with `deny: ["Bash(touch:*)"]`, a subagent told to
224
- run `touch pwned.txt` reported "Denied by permission rules (rule:
225
- Bash(touch:*))", `echo done` succeeded, and no file was created.
@@ -1,98 +0,0 @@
1
- # System prompt
2
-
3
- Part of [Decisions](../decisions.md).
4
-
5
- ## System prompt: per-turn `before_agent_start`, not a static override
6
-
7
- `DefaultResourceLoader.systemPromptOverride` requires SDK composition (which
8
- would mean re-implementing pi's CLI) and is fixed at resource-load time. The
9
- `before_agent_start` event hands us `systemPromptOptions` every turn, reflecting
10
- the currently active tool set — needed because plan mode and deferred loading
11
- change it. The environment block is cached per (cwd, model) so the prompt stays
12
- byte-identical across turns and provider prompt caching still pays off.
13
-
14
- ## System prompt tiered by model capability (2026-08-07)
15
-
16
- One Code shipped one system prompt to every model, written in the lean register.
17
- That register is a *frontier optimization*, not a neutral default: captured Claude
18
- Code payloads show CC tiers the prompt by model — Haiku gets ~29k chars of system
19
- prompt (a 51-line identity block, an explicit `# Doing tasks`, a `# Text output`
20
- communication section, the long XML memory spec) plus ~16k more chars of tool
21
- descriptions, while Opus 4.8/5 get ~8k and a 10-line identity block. Anthropic's
22
- "context engineering for Claude 5" post confirms the mechanism: they removed 80%+
23
- of CC's prompt for Claude-5-gen models with no measured loss. Opus 4.8 and Opus 5
24
- prompts are near-identical, so the axis is **capability tier, not version**.
25
-
26
- For a package whose whole point is "runs on any provider," a single lean prompt is
27
- the wrong default: One Code's non-frontier audience is the long tail of local/cheap
28
- models *weaker than Haiku*, and the lean prompt under-instructs them (skills go
29
- unused — the exact concern that prompted this — no todo discipline, over/under-
30
- action). So the prompt is selected by a 3-way tier, resolved in
31
- `system-prompt`'s `before_agent_start` from `ctx.model` (re-derived every turn;
32
- the model can change mid-session, same discipline as `context-management`):
33
-
34
- - **frontier** — Anthropic first-party Opus/Fable ≥ 4.8 and Sonnet ≥ 5. The old
35
- lean prompt, **byte-identical** to pre-tiering (the frontier bundle is the old
36
- constants; splitting identity/security into two sections re-joins on "\n\n"),
37
- so the common Opus/Sonnet-5 case has zero regression.
38
- - **mid** — other Anthropic (Haiku, Sonnet < 5, Opus 4.1–4.7) and capable
39
- non-Anthropic (GPT-5, Gemini Pro, Grok…). The verbose Claude-Code-Haiku register.
40
- - **low** — small/cheap/local/unknown. Bespoke, most explicit: adds a
41
- "make changes with tools, not prose" correction, an act-vs-answer rule, tool
42
- discipline with an explicit skill nudge, per-task playbooks, and symmetric
43
- anti-over/under-action closers.
44
-
45
- Classification (`extensions/lib/model-tier.ts`) obeys the auto-mode convention:
46
- **no id-substring lead-matching.** The only id parsing is structural version
47
- parsing on first-party Anthropic ids — a namespace we control — adapted from
48
- pi-ai's `defaultSupportsToolReferences`. It is version parse, **not price**,
49
- because cost is non-monotonic: `claude-opus-4-1` ($15/M) costs more than
50
- `opus-4-8`/`opus-5` ($5/M), so a price ranking would call the older model more
51
- "frontier." For every other provider the decision rests on price + containment
52
- (reusing `pricedInput`/`modelIdentity`, non-positive prices treated as *unpriced*,
53
- not free) with a name hint only as corroboration. Three refinements were forced
54
- by the real catalogs and a test:
55
-
56
- - **Delimited name tokens.** A bare `/mini/` matches inside "ge**mini**", which
57
- would have dragged *every* Gemini model (pro and base, not just flash) to low.
58
- Both the low-tier hint (flash/mini/nano/small/lite/instant) and the capability
59
- hint are matched as delimited tokens (`(?:^|[-/.])…(?:[-/.]|$)`). Caught by the
60
- `gemini-3-pro-preview` test, not by inspection — worth remembering that a
61
- substring hint over a real catalog is a latent misclassifier.
62
- - **"pro" is a capability-up signal.** In the catalogs "pro" only ever marks the
63
- flagship variant (`deepseek-v4-pro`, `gemini-3-pro`, `gpt-5-pro`), so a
64
- "pro"-class name keeps a model in mid even when it is cheap or unpriced —
65
- otherwise `deepseek-v4-pro` ($0.435) would fall to low on the price backstop.
66
- - **Unknown → low.** An unclassifiable/unpriced model gets maximum scaffolding
67
- by default (the user's call): mis-tiering the prompt is low-stakes and
68
- asymmetric — a lean prompt on a weak model fails silently, a verbose prompt on
69
- a strong one merely wastes tokens. The name hint is also deliberately narrower
70
- than model-policy's `NAME_HINTS`, which counts haiku/sonnet as "small" for
71
- cheap-model *selection*; a gateway-proxied `…/claude-sonnet-5` reaching the
72
- non-Anthropic branch must not be demoted on its name.
73
-
74
- `CC_PROMPT_TIER=frontier|mid|low` forces a tier (env only, never project settings
75
- — a repo must not silently downgrade its own scaffolding, the `autoMode`
76
- reasoning). Caching is unaffected: tier is a pure function of the model, folded
77
- into the existing `${cwd}|${modelLine}|${tier}` env-cache key, so the prompt stays
78
- byte-stable per model across turns.
79
-
80
- **opencode was studied and its mechanism rejected.** It solves the same problem
81
- with per-model prompt files (`session/system.ts::provider()`) selected by raw
82
- `model.api.id` substring matching — the exact anti-pattern One Code avoids. We took
83
- its *content* (the low-tier scaffolding above is lifted from `default.txt`/
84
- `kimi.txt`) and its insight that decoding params are a separate per-model dial,
85
- not its selection logic.
86
-
87
- **Not done, on purpose.** (1) pi's built-in tool descriptions are not tiered — CC
88
- puts a lot of its tiering there (Bash 10k vs 1.4k chars) but pi owns those
89
- snippets; a `toolSnippets` override is separate future work. (2) Per-model
90
- sampling params (`temperature`/`top_p`), which opencode tunes independently of
91
- prompt text, are logged as future work in `handoff.md` rather than folded in, to
92
- keep this change prompt-only.
93
-
94
- **Related: a named agent keeps its own prompt.** `before_agent_start` returns
95
- early when `systemPromptOptions.customPrompt` is set, so a named
96
- `.claude/agents/*.md` agent (or a `--system-prompt` launch) keeps its own prompt
97
- instead of having it clobbered by the tiered One Code prompt — pi's own builder
98
- already honours `customPrompt` verbatim.