one-code-extension 0.1.3 → 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.
- package/LICENSE +20 -0
- package/README.md +200 -172
- package/agents/explore.md +9 -6
- package/agents/general-purpose.md +1 -1
- package/agents/plan.md +6 -4
- package/docs/guide/README.md +52 -0
- package/docs/guide/bring-your-claude-code-setup.md +126 -0
- package/docs/guide/configuration.md +171 -0
- package/docs/guide/differences-from-claude-code.md +150 -0
- package/docs/guide/doctor.md +86 -0
- package/docs/guide/hooks.md +109 -0
- package/docs/guide/installation.md +124 -0
- package/docs/guide/permissions-modes-and-auto-mode.md +450 -0
- package/docs/guide/providers-and-models.md +194 -0
- package/docs/guide/reference.md +224 -0
- package/docs/guide/sessions-and-context.md +190 -0
- package/docs/guide/skills-plugins-and-mcp.md +176 -0
- package/docs/guide/subagents-and-workflows.md +193 -0
- package/docs/guide/tasks-and-background-work.md +111 -0
- package/docs/guide/terminal-interface.md +155 -0
- package/docs/guide/tools.md +175 -0
- package/docs/guide/troubleshooting.md +175 -0
- package/extensions/ask-user/index.ts +65 -71
- package/extensions/ask-user/questions.ts +15 -28
- package/extensions/ask-user/widget.ts +533 -0
- package/extensions/auto-mode/actions.ts +9 -26
- package/extensions/auto-mode/classifier-prompt.ts +127 -0
- package/extensions/auto-mode/classifier.ts +305 -227
- package/extensions/auto-mode/config.ts +279 -77
- package/extensions/auto-mode/defaults.ts +17 -60
- package/extensions/auto-mode/instructions.ts +2 -1
- package/extensions/auto-mode/model-picker.ts +53 -31
- package/extensions/auto-mode/model-select.ts +153 -82
- package/extensions/auto-mode/paths.ts +13 -1
- package/extensions/auto-mode/pause.ts +8 -0
- package/extensions/auto-mode/prompt.ts +205 -238
- package/extensions/auto-mode/recoverability.ts +229 -0
- package/extensions/auto-mode/rules.ts +92 -75
- package/extensions/auto-mode/safety-floor.ts +43 -12
- package/extensions/auto-mode/sensitive.ts +11 -0
- package/extensions/auto-mode/setup-run.ts +245 -0
- package/extensions/auto-mode/setup.ts +235 -0
- package/extensions/auto-mode/shell-analysis.ts +332 -26
- package/extensions/auto-mode/transcript.ts +102 -0
- package/extensions/background/index.ts +256 -43
- package/extensions/background/monitor-batch.ts +58 -0
- package/extensions/background/registry.ts +9 -0
- package/extensions/background/wakeup.ts +45 -0
- package/extensions/bash/background.ts +47 -22
- package/extensions/bash/guards.ts +229 -0
- package/extensions/bash/index.ts +81 -19
- package/extensions/branding/index.ts +44 -18
- package/extensions/branding/startup.ts +23 -8
- package/extensions/claude-compat/index.ts +17 -2
- package/extensions/claude-context/index.ts +41 -12
- package/extensions/clear/index.ts +27 -0
- package/extensions/compaction/fit.ts +121 -0
- package/extensions/compaction/index.ts +176 -71
- package/extensions/compaction/prompt.ts +21 -1
- package/extensions/context-budget/budget.ts +61 -0
- package/extensions/context-budget/index.ts +66 -0
- package/extensions/context-management/index.ts +40 -16
- package/extensions/doctor/build.ts +226 -0
- package/extensions/doctor/cli.ts +99 -0
- package/extensions/doctor/compat.ts +532 -0
- package/extensions/doctor/dependencies.ts +186 -0
- package/extensions/doctor/fix-prompt.ts +125 -0
- package/extensions/doctor/index.ts +308 -0
- package/extensions/doctor/models.ts +231 -0
- package/extensions/doctor/presets.ts +208 -0
- package/extensions/doctor/report.ts +189 -0
- package/extensions/doctor/update-lookup.ts +46 -0
- package/extensions/doctor/viewer.ts +124 -0
- package/extensions/effort/index.ts +41 -4
- package/extensions/effort/slider.ts +33 -2
- package/extensions/file-tracker/index.ts +143 -20
- package/extensions/file-tracker/replay.ts +46 -0
- package/extensions/file-tracker/tracker.ts +51 -4
- package/extensions/footer/footer-line.ts +207 -0
- package/extensions/footer/index.ts +152 -0
- package/extensions/footer/pr.ts +53 -0
- package/extensions/hooks/executor.ts +57 -20
- package/extensions/hooks/formatter-notice.ts +76 -0
- package/extensions/hooks/index.ts +314 -73
- package/extensions/hooks/matcher.ts +35 -1
- package/extensions/hooks/plugin-hooks.ts +3 -3
- package/extensions/hooks/protocol.ts +58 -0
- package/extensions/hooks/subagent-bridge.ts +77 -0
- package/extensions/hooks/trust.ts +15 -4
- package/extensions/init/index.ts +26 -0
- package/extensions/init/prompt.ts +40 -0
- package/extensions/interrupted/index.ts +35 -0
- package/extensions/interrupted/line.ts +9 -0
- package/extensions/lib/abort.ts +15 -0
- package/extensions/lib/agent-loader.ts +183 -0
- package/extensions/lib/anthropic-payload.ts +15 -0
- package/extensions/lib/atomic-write.ts +56 -0
- package/extensions/lib/bridge-watch.ts +20 -0
- package/extensions/lib/cache-retention.ts +60 -0
- package/extensions/lib/capability-index.ts +466 -0
- package/extensions/lib/claude-context.ts +318 -27
- package/extensions/lib/claude-settings.ts +64 -0
- package/extensions/lib/consent-preview.ts +30 -0
- package/extensions/lib/deferred.ts +144 -13
- package/extensions/lib/favorites.ts +43 -0
- package/extensions/lib/fetch-timeout.ts +15 -0
- package/extensions/lib/frontmatter.ts +31 -0
- package/extensions/lib/git.ts +44 -2
- package/extensions/lib/hook-gate.ts +90 -0
- package/extensions/lib/interrupt.ts +94 -0
- package/extensions/lib/mcp-overrides.ts +61 -0
- package/extensions/lib/mcp-share.ts +25 -0
- package/extensions/lib/mcp-status.ts +34 -0
- package/extensions/lib/memory.ts +41 -6
- package/extensions/lib/model-facts.generated.json +2480 -0
- package/extensions/lib/model-facts.ts +162 -0
- package/extensions/lib/model-policy.ts +145 -189
- package/extensions/lib/model-tier.ts +480 -64
- package/extensions/lib/model-unusable.ts +37 -0
- package/extensions/lib/notifications.ts +320 -1
- package/extensions/lib/one-code-settings.ts +63 -0
- package/extensions/lib/original-command.ts +71 -0
- package/extensions/lib/package-version.ts +31 -0
- package/extensions/lib/paths.ts +39 -4
- package/extensions/lib/permission-gate.ts +192 -0
- package/extensions/lib/persisted-output.ts +18 -0
- package/extensions/lib/pi-ai-estimate.ts +160 -0
- package/extensions/lib/pi-version.ts +1 -1
- package/extensions/lib/plan-mode-channels.ts +11 -0
- package/extensions/lib/plugin-overrides.ts +24 -0
- package/extensions/lib/plugin-root.ts +44 -0
- package/extensions/lib/plugins.ts +233 -54
- package/extensions/lib/prefix-warm-gate.ts +157 -0
- package/extensions/lib/process-tree.ts +56 -0
- package/extensions/lib/reminders.ts +321 -68
- package/extensions/lib/scratchpad.ts +11 -8
- package/extensions/lib/session-lifecycle.ts +28 -0
- package/extensions/lib/settings-channels.ts +14 -0
- package/extensions/lib/shell-tasks.ts +54 -0
- package/extensions/lib/skill-overrides.ts +86 -0
- package/extensions/lib/skill-scan.ts +110 -0
- package/extensions/lib/text-width.ts +267 -0
- package/extensions/lib/tui-render.ts +281 -54
- package/extensions/lib/usage-bus.ts +75 -0
- package/extensions/lib/usage-tracker.ts +67 -0
- package/extensions/lib/worktree-isolation.ts +170 -0
- package/extensions/lsp/client.ts +69 -12
- package/extensions/lsp/format.ts +12 -2
- package/extensions/lsp/index.ts +273 -84
- package/extensions/lsp/install-hints.ts +43 -0
- package/extensions/lsp/keep-alive.ts +19 -0
- package/extensions/lsp/plugin-servers.ts +331 -0
- package/extensions/lsp/watcher.ts +157 -0
- package/extensions/mcp/announce.ts +99 -0
- package/extensions/mcp/client.ts +181 -22
- package/extensions/mcp/config.ts +55 -24
- package/extensions/mcp/index.ts +586 -86
- package/extensions/mcp/oauth/browser.ts +26 -0
- package/extensions/mcp/oauth/callback.ts +104 -0
- package/extensions/mcp/oauth/flow.ts +68 -0
- package/extensions/mcp/oauth/provider.ts +147 -0
- package/extensions/mcp/oauth/store.ts +86 -0
- package/extensions/mcp/panel/keys.ts +34 -0
- package/extensions/mcp/panel/model.ts +62 -0
- package/extensions/mcp/panel/render.ts +141 -0
- package/extensions/mcp/panel/state.ts +108 -0
- package/extensions/mcp/schema.ts +83 -6
- package/extensions/mcp/trust.ts +340 -0
- package/extensions/memory/entries.ts +163 -0
- package/extensions/memory/index.ts +119 -2
- package/extensions/memory/open-external.ts +97 -0
- package/extensions/memory/panel.ts +124 -0
- package/extensions/model-default/index.ts +74 -0
- package/extensions/notebook/index.ts +36 -18
- package/extensions/notebook/notebook.ts +110 -17
- package/extensions/permissions/index.ts +1012 -247
- package/extensions/permissions/matcher.ts +488 -57
- package/extensions/permissions/modes.ts +55 -7
- package/extensions/permissions/project-trust.ts +81 -0
- package/extensions/permissions/protected-paths.ts +16 -3
- package/extensions/permissions/rule-prose.ts +79 -0
- package/extensions/permissions/session-grant.ts +91 -0
- package/extensions/permissions/settings.ts +112 -33
- package/extensions/permissions/subagent-gate.ts +57 -0
- package/extensions/plan-mode/index.ts +143 -33
- package/extensions/plan-mode/reminder.ts +16 -19
- package/extensions/plan-mode/viewer.ts +40 -31
- package/extensions/plugins/counts.ts +68 -0
- package/extensions/plugins/index.ts +496 -32
- package/extensions/plugins/install/install.ts +167 -0
- package/extensions/plugins/install/paths.ts +23 -0
- package/extensions/plugins/install/registry.ts +72 -0
- package/extensions/plugins/marketplace/git.ts +103 -0
- package/extensions/plugins/marketplace/official.ts +36 -0
- package/extensions/plugins/marketplace/parse.ts +94 -0
- package/extensions/plugins/marketplace/registry.ts +60 -0
- package/extensions/plugins/marketplace/sync.ts +146 -0
- package/extensions/plugins/marketplace/types.ts +128 -0
- package/extensions/plugins/panel/keys.ts +52 -0
- package/extensions/plugins/panel/render.ts +315 -0
- package/extensions/plugins/panel/rows.ts +230 -0
- package/extensions/plugins/panel/state.ts +333 -0
- package/extensions/recap/index.ts +215 -0
- package/extensions/recap/prompt.ts +44 -0
- package/extensions/recap/scheduler.ts +87 -0
- package/extensions/search-tools/index.ts +0 -0
- package/extensions/search-tools/tools.ts +7 -5
- package/extensions/skill/index.ts +360 -34
- package/extensions/skill/invoke.ts +185 -0
- package/extensions/skill/listing.ts +21 -0
- package/extensions/skill/panel/keys.ts +41 -0
- package/extensions/skill/panel/render.ts +91 -0
- package/extensions/skill/panel/state.ts +115 -0
- package/extensions/spinner/index.ts +110 -0
- package/extensions/spinner/line.ts +51 -0
- package/extensions/spinner/verbs.ts +201 -0
- package/extensions/subagents/agents.ts +88 -44
- package/extensions/subagents/default-model.ts +62 -32
- package/extensions/subagents/delegation-steer.ts +23 -0
- package/extensions/subagents/hand-back-review.ts +67 -0
- package/extensions/subagents/index.ts +1545 -346
- package/extensions/subagents/live-runs.ts +293 -0
- package/extensions/subagents/model-select.ts +252 -82
- package/extensions/subagents/outcome.ts +90 -0
- package/extensions/subagents/panel-keys.ts +41 -0
- package/extensions/subagents/panel-render.ts +357 -0
- package/extensions/subagents/panel-widget.ts +330 -0
- package/extensions/subagents/pending-claim.ts +45 -0
- package/extensions/subagents/prose.ts +105 -0
- package/extensions/subagents/runner.ts +674 -0
- package/extensions/subagents/runs.ts +68 -1
- package/extensions/subagents/send-to-main-tool.ts +55 -0
- package/extensions/subagents/session-turns.ts +138 -0
- package/extensions/subagents/shell-panel.ts +198 -0
- package/extensions/subagents/usage.ts +16 -4
- package/extensions/subagents/worktree.ts +13 -0
- package/extensions/system-prompt/environment.ts +5 -3
- package/extensions/system-prompt/git-status.ts +93 -0
- package/extensions/system-prompt/index.ts +23 -1
- package/extensions/system-prompt/template.ts +34 -4
- package/extensions/system-prompt/tiers/common.ts +31 -6
- package/extensions/system-prompt/tiers/low.ts +13 -3
- package/extensions/system-prompt/tiers/mid.ts +21 -8
- package/extensions/system-reminder/index.ts +53 -9
- package/extensions/tasks/index.ts +65 -16
- package/extensions/tasks/store.ts +76 -3
- package/extensions/tool-search/announce.ts +42 -0
- package/extensions/tool-search/index.ts +136 -13
- package/extensions/turn-duration/index.ts +60 -0
- package/extensions/turn-duration/line.ts +22 -0
- package/extensions/turn-duration/span.ts +41 -0
- package/extensions/turn-duration/verbs.ts +24 -0
- package/extensions/web/backends.ts +421 -0
- package/extensions/web/index.ts +178 -21
- package/extensions/web-fetch/index.ts +74 -18
- package/extensions/web-fetch/summarize.ts +1 -1
- package/extensions/workflow/agent-session.ts +182 -112
- package/extensions/workflow/globals.ts +129 -106
- package/extensions/workflow/index.ts +343 -28
- package/extensions/workflow/records.ts +118 -0
- package/extensions/workflow/run-manager.ts +80 -31
- package/extensions/workflow/saved-workflows.ts +2 -1
- package/extensions/workflow/script-worker.mjs +110 -0
- package/extensions/workflow/types.ts +74 -8
- package/extensions/workflow/viewer.ts +562 -0
- package/extensions/workflow/vm-runtime.ts +118 -22
- package/extensions/workflow/widget.ts +126 -18
- package/extensions/worktree/guards.ts +240 -0
- package/extensions/worktree/index.ts +30 -5
- package/extensions/worktree/rewrite.ts +32 -16
- package/package.json +20 -10
- package/skills/code-review/SKILL.md +165 -0
- package/skills/fewer-permission-prompts/SKILL.md +61 -0
- package/skills/security-review/SKILL.md +178 -0
- package/skills/simplify/SKILL.md +70 -0
- package/themes/{one-code-light.json → onecode-light.json} +6 -1
- package/themes/{one-code.json → onecode.json} +6 -1
- package/types/app.d.ts +8 -1
- package/types/community-packages.d.ts +45 -2
- package/docs/decisions/auto-mode.md +0 -526
- package/docs/decisions/branding.md +0 -127
- package/docs/decisions/code-review-remediation.md +0 -106
- package/docs/decisions/compaction.md +0 -140
- package/docs/decisions/distribution.md +0 -168
- package/docs/decisions/hooks.md +0 -64
- package/docs/decisions/lsp.md +0 -58
- package/docs/decisions/mcp.md +0 -104
- package/docs/decisions/memory-state.md +0 -170
- package/docs/decisions/model-policy.md +0 -126
- package/docs/decisions/modes.md +0 -178
- package/docs/decisions/skills-plugins.md +0 -56
- package/docs/decisions/subagents-workflows.md +0 -225
- package/docs/decisions/system-prompt.md +0 -98
- package/docs/decisions/tools.md +0 -407
- package/docs/decisions/tui.md +0 -202
- package/docs/decisions.md +0 -148
- package/extensions/subagents/child.ts +0 -414
- package/extensions/subagents/rpc-turns.ts +0 -123
- package/extensions/todo/index.ts +0 -133
- 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.
|