@jaybeeuu/agent-cortex 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/CHANGELOG.md +387 -0
  2. package/README.md +33 -13
  3. package/agents/README.md +22 -10
  4. package/agents/plan/agent.md +2 -2
  5. package/agents/ralph/agent.md +126 -88
  6. package/agents/ralph/claude/frontmatter.json +3 -3
  7. package/agents/ralph/claude/wake.md +46 -0
  8. package/agents/ralph/pi/{polling.md → wake.md} +35 -20
  9. package/agents/ralph-plan/agent.md +23 -11
  10. package/bin/agent-cortex.mjs +66 -4
  11. package/bin/installers/claude.mjs +182 -68
  12. package/bin/installers/pi.mjs +200 -24
  13. package/extensions/agent-guardrails/README.md +1 -1
  14. package/extensions/agent-guardrails/guardrails.ts +1 -1
  15. package/extensions/agent-guardrails/index.ts +1 -1
  16. package/extensions/agent-modes/discover.test.ts +2 -2
  17. package/hooks/claude/scripts/notify.mjs +8 -1
  18. package/lib/cli.mjs +91 -2
  19. package/package.json +27 -3
  20. package/scripts/check-changeset.mjs +4 -0
  21. package/scripts/check-no-sync.mjs +5 -1
  22. package/scripts/lib/compose-agent.mjs +69 -9
  23. package/scripts/lib/fs.mjs +10 -2
  24. package/scripts/lib/migrate.mjs +736 -0
  25. package/scripts/lib/release-gates.mjs +21 -1
  26. package/scripts/lib/skill-frontmatter.mjs +23 -6
  27. package/scripts/lib/skill-links.mjs +52 -0
  28. package/scripts/lib/verify-worker-tree.mjs +25 -0
  29. package/scripts/resolve-publish-command.mjs +4 -0
  30. package/skills/engineering/design-an-interface/SKILL.md +3 -3
  31. package/skills/engineering/grill-with-docs/SKILL.md +3 -5
  32. package/skills/engineering/improve-codebase-architecture/SKILL.md +5 -4
  33. package/skills/engineering/tdd/SKILL.md +5 -7
  34. package/skills/engineering/technical-direction/SKILL.md +5 -5
  35. package/skills/planning/classify-bead/REFERENCE.md +3 -3
  36. package/skills/planning/classify-bead/SKILL.md +14 -9
  37. package/skills/planning/classify-bead/scripts/classify-bead.mjs +5 -4
  38. package/skills/planning/create-task/REFERENCE.md +52 -3
  39. package/skills/planning/create-task/SKILL.md +70 -26
  40. package/skills/planning/create-task/scripts/{create-chores.ts → create-chores.mjs} +48 -23
  41. package/skills/planning/flesh-out-idea/REFERENCE.md +116 -0
  42. package/skills/planning/flesh-out-idea/SKILL.md +146 -0
  43. package/skills/planning/prd-to-tasks/REFERENCE.md +54 -5
  44. package/skills/planning/prd-to-tasks/SKILL.md +22 -16
  45. package/skills/planning/record-idea/FORMAT.md +66 -17
  46. package/skills/planning/record-idea/SKILL.md +48 -24
  47. package/skills/planning/request-refactor-plan/SKILL.md +4 -4
  48. package/skills/planning/spec-to-tickets/SKILL.md +5 -5
  49. package/skills/planning/write-a-prd/SKILL.md +8 -9
  50. package/skills/planning/write-a-ticket/SKILL.md +4 -6
  51. package/skills/productivity/bd-tool/SKILL.md +15 -10
  52. package/skills/productivity/grill-me/SKILL.md +5 -0
  53. package/skills/productivity/init-beads/SKILL.md +3 -3
  54. package/skills/productivity/migration/REFERENCE.md +227 -0
  55. package/skills/productivity/migration/SKILL.md +188 -0
  56. package/skills/productivity/validate-agent-dir/scripts/{validate-agent-dir.ts → validate-agent-dir.mjs} +49 -28
  57. package/skills/productivity/write-a-skill/SKILL.md +5 -5
  58. package/skills/review/maintain-agent-docs/SKILL.md +5 -7
  59. package/skills/review/refactor-skill/SKILL.md +4 -3
  60. package/skills/review/review-security/SKILL.md +3 -5
  61. package/skills/style/style-code/SKILL.md +5 -10
  62. package/skills/style/style-comms/SKILL.md +5 -7
  63. package/skills/style/style-documentation/SKILL.md +5 -6
  64. package/skills/style/style-tests/SKILL.md +5 -7
  65. package/skills/workflow/git-workflow/SKILL.md +28 -4
  66. package/skills/workflow/hitl-collab/SKILL.md +4 -6
  67. package/skills/workflow/plan/SKILL.md +41 -30
  68. package/skills/workflow/ralph/REFERENCE.md +182 -51
  69. package/skills/workflow/ralph/SKILL.md +89 -50
  70. package/skills/workflow/run-pipeline-stage/SKILL.md +72 -71
  71. package/skills/workflow/run-pipeline-stage/playbooks/code.md +11 -0
  72. package/skills/workflow/run-pipeline-stage/playbooks/document.md +12 -0
  73. package/skills/workflow/run-pipeline-stage/playbooks/fix.md +12 -0
  74. package/skills/workflow/run-pipeline-stage/playbooks/review.md +11 -0
  75. package/skills/workflow/run-pipeline-stage/playbooks/verify.md +13 -0
  76. package/skills/workflow/run-pipeline-stage/prompts/stage-runner.md +73 -1
  77. package/token-map.README.md +9 -4
  78. package/token-map.json +13 -6
  79. package/.agents/skills/style-versioning/SKILL.md +0 -172
  80. package/.changeset/README.md +0 -8
  81. package/.changeset/config.json +0 -11
  82. package/.github/workflows/ci.yml +0 -302
  83. package/.junie/guidelines.md +0 -87
  84. package/.junie/mcp/mcp.json +0 -10
  85. package/AGENTS.md +0 -153
  86. package/agents/ralph/claude/polling.md +0 -31
  87. package/agents-native/ralph.md +0 -203
  88. package/docs/claude-hooks.md +0 -144
  89. package/docs/commit-signing.md +0 -231
  90. package/docs/ideas/auto-model-selection.md +0 -75
  91. package/docs/ideas/ban-content-assertion-tests.md +0 -75
  92. package/docs/ideas/bead-progress-notes-for-session-resumption.md +0 -75
  93. package/docs/ideas/classify-beads-via-deterministic-script-with-agent-fallback.md +0 -70
  94. package/docs/ideas/ctx-alias-version-and-update-commands.md +0 -65
  95. package/docs/ideas/ctx-feedback-command-for-capturing-ideas-from-any-machine.md +0 -67
  96. package/docs/ideas/dedicated-review-tests-skill.md +0 -71
  97. package/docs/ideas/deployment-beads-for-post-merge-pipelines.md +0 -36
  98. package/docs/ideas/design-and-delivery-as-separate-bead-trees/design-and-delivery-as-separate-bead-trees.md +0 -99
  99. package/docs/ideas/enable-signed-commit-enforcement-changesets-bot-commits-must-be-signed.md +0 -42
  100. package/docs/ideas/extension-manifests.md +0 -121
  101. package/docs/ideas/improve-pi-system-prompt.md +0 -43
  102. package/docs/ideas/map-every-cortex-tool-to-a-real-pi-equivalent.md +0 -95
  103. package/docs/ideas/model-selector.md +0 -40
  104. package/docs/ideas/pi-task-memory.md +0 -34
  105. package/docs/ideas/qa-extension.md +0 -43
  106. package/docs/ideas/record-idea-implementation-questions.md +0 -68
  107. package/docs/ideas/record-ideas-as-beads.md +0 -115
  108. package/docs/ideas/self-flushing-session.md +0 -72
  109. package/docs/ideas/state-in-beads-not-md.md +0 -69
  110. package/docs/ideas/subagent-visibility.md +0 -72
  111. package/docs/ideas/task-session-context.local.md +0 -95
  112. package/docs/ideas/task-session-context.md +0 -89
  113. package/docs/ideas/test-data-creation-helpers.md +0 -92
  114. package/docs/ideas/test-planning-stage-bead-in-feature-planning.md +0 -68
  115. package/docs/ideas/unified-ci-pipeline.md +0 -28
  116. package/docs/ideas/unify-the-ticket-and-task-decomposition-workflows.md +0 -71
  117. package/docs/ideas/worktree-housekeeping-for-closed-beads.md +0 -39
  118. package/docs/inspirations.md +0 -33
  119. package/docs/research/disable-model-invocation.md +0 -82
  120. package/docs/research/gas-city-research.md +0 -256
  121. package/docs/research/skill-design-research.md +0 -286
  122. package/docs/research/skill-improvements-analysis.md +0 -117
  123. package/docs/research/skill-patterns-research.md +0 -24
  124. package/docs/skills/skill-anatomy.md +0 -200
  125. package/docs/technical-direction/harness-config.md +0 -177
  126. package/docs/technical-direction/migration-execution-labels.md +0 -177
  127. package/docs/user-preferences.md +0 -17
  128. package/extensions/agent-guardrails/tsconfig.json +0 -12
  129. package/extensions/agent-modes/tsconfig.json +0 -12
  130. package/extensions/output-style/tsconfig.json +0 -12
  131. package/extensions/session-start/tsconfig.json +0 -12
  132. package/extensions/skill-stats/pnpm-lock.yaml +0 -329
  133. package/extensions/skill-stats/tsconfig.json +0 -12
  134. package/extensions/subagent/agents/planner.md +0 -37
  135. package/extensions/subagent/agents/reviewer.md +0 -35
  136. package/extensions/subagent/agents/scout.md +0 -50
  137. package/extensions/subagent/agents/worker.md +0 -24
  138. package/extensions/subagent/prompts/implement-and-review.md +0 -10
  139. package/extensions/subagent/prompts/implement.md +0 -10
  140. package/extensions/subagent/prompts/scout-and-plan.md +0 -9
  141. package/extensions/subagent/tsconfig.json +0 -12
  142. package/pi/keybindings.json +0 -3
  143. package/pi/settings.json +0 -34
  144. package/pnpm-workspace.yaml +0 -14
  145. package/skills/planning/create-task/scripts/package.json +0 -14
  146. package/skills/planning/create-task/scripts/pnpm-lock.yaml +0 -342
  147. package/skills/planning/create-task/scripts/tsconfig.json +0 -12
  148. package/skills/planning/record-idea/scripts/new-idea.sh +0 -89
  149. package/skills/productivity/validate-agent-dir/scripts/package.json +0 -15
  150. package/skills/productivity/validate-agent-dir/scripts/pnpm-lock.yaml +0 -329
  151. package/skills/productivity/validate-agent-dir/scripts/pnpm-workspace.yaml +0 -2
  152. package/skills/productivity/validate-agent-dir/scripts/tsconfig.json +0 -19
  153. package/skills/productivity/validate-agent-dir/scripts/validate-agent-dir.test.ts +0 -317
  154. package/skills/workflow/run-pipeline-stage/REFERENCE.md +0 -22
  155. package/skills/workflow/run-pipeline-stage/scripts/generate-progress.test.ts +0 -682
  156. package/skills/workflow/run-pipeline-stage/scripts/generate-progress.ts +0 -588
  157. package/skills/workflow/run-pipeline-stage/scripts/package.json +0 -15
  158. package/skills/workflow/run-pipeline-stage/scripts/pnpm-lock.yaml +0 -342
  159. package/skills/workflow/run-pipeline-stage/scripts/pnpm-workspace.yaml +0 -2
  160. package/skills/workflow/run-pipeline-stage/scripts/tsconfig.json +0 -12
  161. package/test/classify-bead.test.mjs +0 -277
  162. package/test/claude-installer.test.mjs +0 -308
  163. package/test/cli.test.mjs +0 -314
  164. package/test/create-chores.test.mjs +0 -85
  165. package/test/fake-bd.test.mjs +0 -72
  166. package/test/fs.test.mjs +0 -76
  167. package/test/helpers/fake-bd.mjs +0 -87
  168. package/test/helpers/fake-claude.mjs +0 -152
  169. package/test/helpers/fake-pi.mjs +0 -132
  170. package/test/installer.test.mjs +0 -806
  171. package/test/notify-hook.test.mjs +0 -63
  172. package/test/pending-gates.test.mjs +0 -147
  173. package/test/pi-installer.test.mjs +0 -785
  174. package/test/pi-register.test.mjs +0 -342
  175. package/test/pi-sweep.test.mjs +0 -619
  176. package/test/release-gates.test.mjs +0 -190
  177. package/test/skill-frontmatter.test.mjs +0 -137
  178. package/test/verify-worker-tree.test.mjs +0 -120
@@ -1,203 +0,0 @@
1
- ---
2
- name: ralph
3
- description: "Run pending beads end-to-end with parallel background workers and an independent review gate: find ready work, implement each feature in its own worktree, review it, open a PR, then pause for human merge. Use when running the backlog autonomously with human approval points. Run me as the interactive main agent (claude --agent agent-cortex:ralph), not as a delegated subagent."
4
- tools: Agent, TaskList, TaskGet, TaskStop, SendMessage, Skill, Bash, Read, Grep, Glob
5
- ---
6
-
7
- You are Ralph, a parallel task-orchestration agent. You advance a backlog of beads through
8
- an implement → review → fix pipeline, running several features at once, each in its own git
9
- worktree, and pausing at human PR-merge gates. **You orchestrate only — you never write or
10
- edit code, tests, or docs yourself.** Workers do that; you dispatch them, react to their
11
- results, manage git/beads state, and open PRs.
12
-
13
- ## Golden rules
14
-
15
- - **Run as the interactive main agent.** If you detect you are running as a background or
16
- delegated subagent, stop and ask the user to re-run you with `claude --agent agent-cortex:ralph`.
17
- You must stay alive across turns to receive worker completions.
18
- - **Spawn workers with the `Agent` tool in the background** (the default). Each call returns
19
- immediately; you will be **re-invoked automatically when a worker completes** — its result
20
- is delivered to you. **Do not poll and do not `sleep`.** React to completions as they arrive.
21
- - **Never write code/tests/docs**, never edit bead files by hand (use `bd`), never auto-merge PRs.
22
- - **Derive all state** from beads, git, and the live task list — you keep no state file.
23
-
24
- ## Concurrency
25
-
26
- Keep at most **5 features in flight** at once (a feature is "in flight" from the moment you
27
- claim it until its PR is open or it is blocked). When a slot frees, promote the next AFK
28
- feature. Use `TaskList`/`TaskGet` to see which workers are still running.
29
-
30
- ## Classifying a bead
31
-
32
- Classification is a planning-stage concern: `create-task` invokes `classify-bead` when a bead is
33
- created, so by the time a bead reaches `bd ready` here it should already carry an
34
- `implementation-type` label. Check `bd label list <id>` **yourself** — never spawn
35
- `classify-bead` from the ralph loop:
36
-
37
- - `implementation-type:afk` present → **AFK**. Done.
38
- - `execution:hitl` (or the legacy `implementation-type:hitl`) present → **HITL**. Skip; record for the
39
- pending-action summary.
40
- - Neither present → treat as **NEEDS-REFINEMENT**: skip; record for the summary. A missing label
41
- here means the bead skipped planning-stage classification — flag it, don't classify inline.
42
-
43
- ## Initialization
44
-
45
- Run once at startup:
46
-
47
- 1. `bd prime` — hold the output for your own context.
48
- 2. Ensure `.agent-cortex/` and `.agent-cortex/worktrees/` are in `.gitignore` (append if missing,
49
- via `Bash`).
50
- 3. `bd ready` to list available work.
51
- 4. For each ready **feature/task** bead (ignore `chore` beads), check its classification per
52
- **Classifying a bead** above.
53
- 5. Read `maxFixRounds` from `${CLAUDE_PLUGIN_ROOT}/skills/create-task/pipeline.json` if present;
54
- otherwise default to **4**.
55
- 6. Dispatch up to 5 AFK features (see below). Then end your turn — you will be woken on the
56
- first completion. If there are zero AFK features but an open `lifecycle:feature-pr` gate is
57
- pending (see **Idle**), go straight to **Idle**.
58
-
59
- ## Dispatching a feature
60
-
61
- For each AFK feature `<id>`:
62
-
63
- 1. `bd update <id> --claim`.
64
- 2. Create the branch + worktree from `origin/main`:
65
- ```bash
66
- git fetch origin --quiet
67
- git worktree add ".agent-cortex/worktrees/<id>" -b "feature/<id>" origin/main
68
- ```
69
- Record the **absolute** worktree path (e.g. `$(git rev-parse --show-toplevel)/.agent-cortex/worktrees/<id>`).
70
- 3. Spawn a background **implementer** worker (see _Worker prompts_). Pass the bead id, its full
71
- description (`bd show <id>`), and the absolute worktree path.
72
-
73
- ## When an implementer worker completes
74
-
75
- Parse the worker's `RESULT` block.
76
-
77
- - `OUTCOME: BLOCKED` → `bd update <id> --status blocked --notes "<reason>"`, record it for the
78
- summary, remove the worktree, free the slot, promote the next AFK feature.
79
- - `OUTCOME: DONE` → spawn a background **independent reviewer** worker for `feature/<id>`
80
- (see _Worker prompts_). Pass the bead id, branch name, and worktree path.
81
-
82
- ## When a reviewer worker completes
83
-
84
- Parse the reviewer's `RESULT` block.
85
-
86
- - `REVIEW: APPROVED` →
87
- 1. Open/update the PR: `gh pr create --base main --head "feature/<id>" --title "<bead title>" --body "<summary + Closes bead id>"` (or `gh pr edit` if it exists).
88
- 2. Write the PR URL onto the feature's HITL PR-gate bead (the `lifecycle:feature-pr`
89
- child created during planning); if none exists, create one:
90
- `bd create "[<id>] PR review and merge" --type task --labels implementation-type:hitl,lifecycle:feature-pr` and dep it to `<id>`.
91
- 3. Report the PR URL in chat. Free the slot (the feature is now awaiting human merge — do
92
- **not** close the feature bead; the human closes the gate after merging). Promote the next
93
- AFK feature.
94
- - `REVIEW: CHANGES_REQUESTED` → check the fix cap:
95
- - Count prior fix rounds from the `fix-round:*` label on `<id>` (0 if none).
96
- - If `fix-round < maxFixRounds`: `bd tag <id> fix-round:<n+1>` and spawn a background
97
- **fix** worker with the reviewer's `CHANGES` verbatim. On its completion, treat it like an
98
- implementer completion (DONE → re-review; BLOCKED → block).
99
- - If `fix-round >= maxFixRounds`: `bd update <id> --status blocked --notes "max fix rounds reached"`,
100
- record it, remove the worktree, free the slot, promote the next AFK feature.
101
-
102
- After **every** completion, also run `bd ready`, check the classification of any newly-ready
103
- beads per **Classifying a bead**, and promote AFK features into free slots.
104
-
105
- ## Idle — pending human action / shutdown
106
-
107
- When no workers are running and no AFK features remain:
108
-
109
- - **PR gates pending** (open `lifecycle:feature-pr` beads on either HITL axis):
110
- `bd list -l lifecycle:feature-pr --label-any execution:hitl,implementation-type:hitl --limit 0`.
111
- This harness keys the pause on a gate being **open**, not unblocked, because its gates stay
112
- blocked for their whole life: `create-task` blocks each gate behind the feature's `document`
113
- chore, which no Claude ralph claims or closes, and the native route in _When a reviewer
114
- worker completes_ step 2 deps the gate onto the still-open feature bead. So never assume a gate
115
- here is blocked only by its own pipeline, and never treat "no unblocked gate" as "no human
116
- action owed" — that clears the loop with PRs unmerged. Run `bd dolt push`, then print a
117
- **Pending Human Action** table (bead id, title, PR URL, "review & merge, then `bd close <gate>`"),
118
- and **stop completely** — output nothing further. Do not poll. The user re-invokes you after
119
- merging; you will resume from `bd ready`. The pi harness uses the unblocked-gate predicate
120
- (`skills/workflow/ralph/scripts/pending-gates.mjs`); F10 (agnt-ctx-s5xd.10) unifies ralph's
121
- agent files — reconcile the two predicates there rather than half-migrating this one.
122
- - **Nothing pending**: run `bd dolt push`, print any recorded HITL / needs-refinement / blocked
123
- beads as tables, then print **All beads complete.**
124
-
125
- ## Worker prompts
126
-
127
- Spawn workers with the `Agent` tool, `subagent_type: general-purpose`, in the background. Fill
128
- in the placeholders. Each worker returns a `RESULT` block as its final message. Implementer and
129
- Reviewer keep the session's default model — they need full reasoning capability. The Fix worker
130
- below is spawned with `model: haiku`, since it only applies an already-specified, scoped list of
131
- changes rather than reasoning from scratch.
132
-
133
- ### Implementer
134
-
135
- ```
136
- You are implementing one unit of work in an isolated git worktree. Do ALL work in the
137
- worktree at: <ABS_WORKTREE_PATH>. cd there for shell commands and use absolute paths under it
138
- for file edits — do not touch any other checkout.
139
-
140
- Bead: <ID> — <TITLE>
141
- Full spec:
142
- <bd show OUTPUT>
143
-
144
- Instructions:
145
- - Use the `tdd` skill: write a failing test, make it pass, refactor. Repeat per behaviour.
146
- - Follow the `style-tests` and `style-code` skills.
147
- - Keep the change minimal and behaviour-driven; no speculative code.
148
- - Make the full test suite and linters pass in the worktree.
149
- - Only add/update docs when a decision, behaviour, or constraint genuinely needs recording
150
- (`style-documentation`).
151
- - Commit your work on the current branch (`feature/<ID>`) with a clear message.
152
-
153
- End with exactly this block:
154
- ---RESULT---
155
- BEAD: <ID>
156
- OUTCOME: DONE | BLOCKED
157
- SUMMARY: <one paragraph of what you did>
158
- FILES_CHANGED: <comma-separated paths, or "none">
159
- TESTS: <pass/fail counts or short status>
160
- BLOCKING_ISSUE: <why you're blocked, only if BLOCKED>
161
- ```
162
-
163
- ### Reviewer (independent)
164
-
165
- ```
166
- You are an independent reviewer. Do NOT modify code. Review the diff of branch feature/<ID>
167
- against origin/main in the worktree at <ABS_WORKTREE_PATH>.
168
-
169
- - Run the `code-review` skill and the `security-review` skill over the diff.
170
- - Judge correctness, security, tests, and adherence to the bead spec:
171
- <bd show OUTPUT>
172
-
173
- End with exactly this block:
174
- ---RESULT---
175
- BEAD: <ID>
176
- REVIEW: APPROVED | CHANGES_REQUESTED
177
- SUMMARY: <one paragraph>
178
- CHANGES: <numbered, specific, actionable required changes — only if CHANGES_REQUESTED>
179
- ```
180
-
181
- ### Fix
182
-
183
- Spawn with `model: haiku`. Same as the implementer prompt, but replace the Instructions with:
184
- ```
185
- - Apply ONLY the following reviewer-requested changes, minimally:
186
- <REVIEWER CHANGES>
187
- - Do not make unrelated changes. Keep tests and linters green. Commit on feature/<ID>.
188
- ```
189
-
190
- ## Constraints
191
-
192
- - **Always** run as the interactive main agent, never as a background subagent.
193
- - **Never** write, edit, or create source code, tests, or documentation yourself.
194
- - **Never** edit bead records except via `bd` commands.
195
- - **Never** poll or `sleep` — react to worker-completion wake-ups.
196
- - **Never** auto-merge PRs or close a feature bead before the human merges its PR.
197
- - **Max 5** features in flight; **max `maxFixRounds`** fix rounds per feature, then block it.
198
- - **Never** spawn a subagent just to check an existing `implementation-type` label — read it
199
- yourself via `bd label list`. **Never** spawn `classify-bead` from the ralph loop —
200
- classification is a planning-stage concern already handled by `create-task`. Only the Fix
201
- worker runs on `model: haiku`; Implementer and Reviewer keep the default model.
202
- - **Single-feature model only** for now: each feature branches from `origin/main` and PRs into
203
- `main`. (Multi-feature epic branches are not yet supported.)
@@ -1,144 +0,0 @@
1
- # Claude Code hooks — extension port audit
2
-
3
- The pi extensions in `extensions/` were audited for Claude Code equivalents.
4
- Implemented ports live in `hooks/claude/hooks.json` (copied verbatim into the
5
- materialised plugin as its `hooks.json`); support scripts live in
6
- `hooks/claude/scripts/` and are bundled into the plugin's `hooks/scripts/` by
7
- `bin/installers/claude.mjs` (referenced from hooks.json via `$CLAUDE_PLUGIN_ROOT`).
8
-
9
- Claude Code's hook model differs from PI's: hooks are shell commands fed a JSON
10
- payload on stdin, with events like `SessionStart`, `SessionEnd`, `Stop`,
11
- `SubagentStop`, and `Notification` — there is no `before_agent_start` /
12
- `agent_end` / `tool_call` extension API, no runtime tool registration, and no
13
- UI surface. Each decision below is grounded in the Claude Code hooks reference.
14
-
15
- | pi extension | Claude port | Decision |
16
- |---|---|---|
17
- | `session-start/` | `SessionStart` hook commands | **Port** (extended) |
18
- | `auto-name.ts` | — | **Reject** — built-in |
19
- | `agent-guardrails/` | — | **Reject** — pi-only (no system-prompt hook) |
20
- | `output-style/` | managed `CLAUDE.md` section | **Port** — user memory, not a hook |
21
- | `notify/` | `Notification` hook + `scripts/notify.mjs` | **Port** |
22
- | `skill-stats/` | — | **Reject** — no equivalent |
23
- | `subagent/` | — | **Reject** — native |
24
- | `agent-modes/` | — | **Reject** — no equivalent |
25
-
26
- ## `session-start/` → SessionStart (port)
27
-
28
- pi injects the project context files (AGENTS.md, `docs/user-preferences.md`)
29
- into every session; it lists no skills, since pi's system prompt already names
30
- every skill with its `SKILL.md` path. Claude Code already loads
31
- `AGENTS.md` natively and the existing SessionStart hook nudge ("Load AGENTS.md
32
- and active beads context…") plus the style-skill policy (PR #57) cover the
33
- context side. This bead closes the remaining gap: a skill-policy command listing
34
- the meta-skills (`using-agent-skills` for routing, `bd-tool` for beads context,
35
- `git-workflow` for branch/PR discipline). SessionStart command-hook stdout is
36
- added to Claude's context, so plain `echo` commands are the right shape —
37
- keep them fast and dependency-free. Skipped from the pi original: the dynamic
38
- file read of AGENTS.md/user-preferences.md, since Claude Code loads AGENTS.md
39
- itself and user-preferences.md is a pi-harness document.
40
-
41
- ## `auto-name.ts` → Reject (built-in)
42
-
43
- pi names sessions via a tiny side-model call on the first prompt. Claude Code
44
- already auto-generates descriptive session titles (visible in `claude --resume`;
45
- a background model request in interactive and headless/SDK sessions) and supports
46
- explicit naming via `--name` / `/rename`. A hook-based title generator would
47
- duplicate platform behaviour with an extra LLM call — rejected. (SessionStart
48
- hooks can also set `sessionTitle` in JSON output for the rare case where a
49
- custom title is genuinely needed.)
50
-
51
- ## `notify/` → Notification hook (port)
52
-
53
- pi notifies on `agent_end` for multi-turn/long tasks with a desktop notification
54
- + bell. Claude Code's native `Notification` event fires at the equivalent
55
- completion points and already carries `message`, `title`, and `notification_type`
56
- in the payload — and hooks emit desktop notifications by returning a
57
- `terminalSequence` JSON field (hooks have no controlling terminal; Claude Code
58
- emits the sequence itself, including inside tmux/screen).
59
-
60
- Implemented as a `Notification` hook with matcher
61
- `agent_completed|agent_needs_input|permission_prompt` invoking `scripts/notify.mjs`,
62
- which reads the payload from stdin and prints the OSC sequence for the detected
63
- terminal (Kitty OSC 99, iTerm2/Windows Terminal OSC 9, default urxvt/Ghostty/Warp
64
- OSC 777 — same detection as the pi `notify` extension). The Notification matcher
65
- is an **exact-string list** over the `notification_type` field; there are no
66
- `success`/`error` types (an earlier draft used that matcher, which silently never
67
- fired). The documented types are `permission_prompt`, `idle_prompt`, `auth_success`,
68
- `elicitation_dialog`, `elicitation_url_dialog`, `elicitation_complete`,
69
- `elicitation_response`, `agent_needs_input`, `agent_completed`,
70
- `quota_auto_resume_fired`, `quota_auto_resume_stale`, `quota_auto_resume_disabled`
71
- (the `agent_*` types require Claude Code v2.1.198+, the `quota_auto_resume_*`
72
- types v2.1.234+). The selection maps to pi's "task completed / failed / needs
73
- approval" semantics: `agent_completed` covers completion and failure ("finishes
74
- or fails"), `agent_needs_input` covers a background session waiting on input, and
75
- `permission_prompt` covers an awaited approval. Explicitly excluded as noise:
76
- `idle_prompt` (fires ~60s after every turn you don't answer within a minute — a
77
- desktop ping on every pause), `auth_success` and `quota_auto_resume_*` (not task
78
- events), and `elicitation_*` (dialog trivia). Skipped from the pi original: the LLM
79
- response summary (Claude's notification message is already the summary) and the tmux
80
- session:window.pane title (unavailable to hooks; the plugin title suffices).
81
-
82
- ## `agent-guardrails/` → Reject (pi-only)
83
-
84
- pi appends behavioural circuit-breakers (retry limits, check-in triggers,
85
- atomic-change discipline) to the system prompt once per user prompt via
86
- `before_agent_start` — which fires before the agent loop, so the block applies to
87
- every turn of that run. Claude Code has no hook that can modify the system prompt;
88
- its nearest surface, `SessionStart` `additionalContext`, injects conversation
89
- context rather than system instructions. The rules are harness-agnostic prose, so
90
- a future port could append them to the existing ported SessionStart hook — out of
91
- scope for this pi-first slice.
92
-
93
- ## `output-style/` → Port (managed CLAUDE.md section)
94
-
95
- pi appends the reply shape (action first, Simplified Technical English, restated
96
- context) to the system prompt through `before_agent_start`. Claude Code cannot
97
- modify the system prompt from a hook, so the installer writes the same block into
98
- the managed section of `~/.claude/CLAUDE.md` — Claude's user memory, loaded every
99
- session.
100
-
101
- The content is not copied into a Claude-side template: `extensions/output-style/
102
- output-style.md` is the single source, read by the pi extension at load and by the
103
- installer at install time. Re-running the install replaces only the text between
104
- the markers; personal memory text survives untouched. The installer never writes
105
- the block by appending to a `SessionStart` hook — memory is the right surface
106
- because the rules must hold for every turn, not just the first.
107
-
108
- ## `skill-stats/` → Reject (no equivalent)
109
-
110
- pi tracks skills loaded into the system prompt, `/skill:` invocations, SKILL.md
111
- reads, and turns, exposing a `/skill-stats` query. Claude Code exposes none of
112
- the required observability to hooks:
113
-
114
- - **No "loaded" event** — nothing fires when a skill enters context, and hooks
115
- never see system-prompt contents, so the primary "loaded" metric has no source.
116
- - **Partial invocation/read observability only** — `PreToolUse` on the `Skill`
117
- tool and `UserPromptExpansion` on slash commands would approximate
118
- invocations, and `PostToolUse` on `Read` would approximate skill reads, but
119
- the signals are fuzzy (Read covers any file; direct `/skill` typing bypasses
120
- `PreToolUse`).
121
- - **No query surface** — Claude Code plugin commands are markdown files, not
122
- scripts, so there is no equivalent of the pi `/skill-stats` command, and
123
- persistent state would live outside the plugin model.
124
-
125
- A half-observable port would diverge from the pi semantics and add moving parts
126
- for little signal. Rejected; Claude Code ships its own usage analytics
127
- (`/usage`, sessions list, statsig) if insights are needed.
128
-
129
- ## `subagent/` → Reject (native)
130
-
131
- pi's `subagent` tool spawns isolated `pi --mode json` processes. Claude Code has
132
- native subagents — the plugin already ships `~/.agent-cortex/claude/agents/*.md` (including
133
- `ralph`, `plan`, `strategy`, `ralph-plan`) executed via the built-in Agent/Task
134
- tools with per-session context isolation — so a hook-based workaround would be
135
- strictly worse.
136
-
137
- ## `agent-modes/` → Reject (no equivalent)
138
-
139
- pi switches system prompts + tool restrictions at runtime with a TUI mode
140
- selector. Claude Code exposes no hook or settings surface for dynamic
141
- tool-restriction/prompt-switching of the main agent; the closest equivalents are
142
- native (permission modes like plan mode configured via settings, and subagents
143
- — already covered above). The `--agent <name>` start flag is covered by
144
- `claude --agent` in newer versions. Rejected.
@@ -1,231 +0,0 @@
1
- # Commit signing
2
-
3
- GitHub has refused merges here with **"Merging is blocked — Commits must have verified
4
- signatures"**. The instinctive reading — "agents don't sign, so of course" — is wrong:
5
- agent and human commits on this repo are GPG-signed and verified. The unsigned commits
6
- are the ones `github-actions[bot]` writes, and only because `GITHUB_TOKEN` cannot hold a
7
- signing key. This note records what is actually signed, what the API says about
8
- enforcement, and the release policy that follows.
9
-
10
- ## What is signed, and what is not
11
-
12
- The agent environment signs automatically. Global git config has `commit.gpgsign=true`
13
- and the secret key `DF657A88675E4AF8F7D65192A8F2E11DE960BE54` (Josh Bickley-Wallace,
14
- the `noreply` address) is present, so every commit an agent makes is signed without any
15
- per-commit step. Verified against the API:
16
-
17
- | Commit | Author | `verification` |
18
- |---|---|---|
19
- | `63f3bef` (PR #181 head) | jaybeeuu | `verified=true reason=valid` |
20
- | `7f99e4c` (PR #182 head) | jaybeeuu | `verified=true reason=valid` |
21
- | `9443f55` (PR #168 head) | github-actions[bot] | `verified=false reason=unsigned` |
22
-
23
- `changesets/action` commits as `github-actions[bot]` using `secrets.GITHUB_TOKEN`, and
24
- GitHub does not sign commits made with a token. That is a property of the token, not a
25
- missing configuration step — no amount of workflow YAML changes it.
26
-
27
- Landed history looks uniformly `valid` for a different reason: the commit the merge creates
28
- is signed by GitHub. `dd347471b1`, the commit that landed PR #161 ("chore: version
29
- packages", authored by `github-actions[bot]`), has `committer=GitHub` and
30
- `verification.verified=true reason=valid`. The bot's unsigned branch commit never reached
31
- `main`; the squash commit GitHub created did, and GitHub signed it.
32
-
33
- That is what this repository's history proves, and it is all it proves. It does **not**
34
- prove that a squash merge escapes an *enforced* signature rule.
35
-
36
- ## Squash does not bypass an enforced signature rule
37
-
38
- The landing commit being GitHub-signed does not exempt the pull request from the check:
39
- a ruleset that requires signatures inspects the head-branch commits too. GitHub's ruleset
40
- reference, ["Require signed commits"](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets#require-signed-commits)
41
- (quoted verbatim, checked 2026-10-27):
42
-
43
- > When GitHub evaluates whether a pull request can be merged, it creates a test merge commit
44
- > whose parents are the latest commit on the base branch and the pull request's head commit.
45
- > GitHub checks the commits introduced by this test merge, including commits from the head
46
- > branch. As a result, unsigned commits on the head branch can block a squash merge, even
47
- > though GitHub would sign the final squash commit. This restriction can also apply to the
48
- > author of the pull request.
49
-
50
- and the remedy it documents:
51
-
52
- > To merge a blocked pull request, rewrite and sign the unsigned commits on the head branch,
53
- > or ask someone with permission to bypass the applicable protections to merge the pull
54
- > request.
55
-
56
- So "squash it and let GitHub re-sign" is not a way *around* the check — it is only the reason
57
- landed history reads `valid` when no signature rule is in force. If a signature rule is
58
- enforced, the remedy is a signed commit, not a different merge method.
59
-
60
- ## What the ruleset API shows — and what it cannot
61
-
62
- No `required_signatures` rule is visible to the tokens available here, at any level.
63
- Read-only probes:
64
-
65
- ```
66
- $ gh api repos/jaybeeuu/agent-cortex/rules/branches/main --jq '[.[].type]'
67
- ["deletion","non_fast_forward","required_linear_history",
68
- "required_status_checks","pull_request"]
69
- ```
70
-
71
- Every effective rule on `main` comes from `ruleset_id 22101709` with
72
- `ruleset_source_type: Repository`. That is evidence rather than silence, because the endpoint
73
- is not repository-scoped by construction: it is documented to return rules "regardless of the
74
- level at which they are configured (e.g. repository or organization)", and its own response
75
- schema includes a `ruleset_source_type: "Organization"` example ([REST reference, "Get rules for a branch"](https://docs.github.com/en/rest/repos/rules#get-rules-for-a-branch), checked
76
- 2026-10-27). There is no `required_signatures` rule in it, and its `pull_request` parameters
77
- allow `["merge","squash","rebase"]`. The other read paths agree:
78
-
79
- ```
80
- $ gh api repos/jaybeeuu/agent-cortex/branches/main/protection
81
- {"message":"Branch not protected", ... "status":"404"}
82
-
83
- $ gh api orgs/jaybeeuu/rulesets
84
- {"message":"Not Found", ... "status":"404"}
85
- ```
86
-
87
- Two explanations remain. The branch-rule read above weighs heavily against the first, without
88
- formally eliminating it:
89
-
90
- 1. **An organization-level ruleset enforces signatures.** This is the weaker of the two now:
91
- the applied-rule read covers every level and shows no organization-sourced rule, so this
92
- survives only on an undocumented possibility that the endpoint filters by caller
93
- visibility. Org ruleset *definitions* do separately require organization administration
94
- read, which the current token does not hold (scopes: `gist, read:org, repo, workflow`), so
95
- a `404` on `orgs/jaybeeuu/rulesets` is inconclusive — it may mean "none exist" or "you may
96
- not see them". Note that the ruleset's `bypass_actors` is empty and
97
- `current_user_can_bypass` is `"never"`, so repository admin does **not** bypass it.
98
- 2. **The UI message was stale** — shown while a signature rule was active, before ruleset
99
- `22101709` was last updated (2026-09-13).
100
-
101
- Closing this out needs a merge attempt (a mutation) or org-admin access: see *The enforcing
102
- rule: still open (AC1)* and the human follow-ups below.
103
-
104
- One adjacent rule is worth knowing, though it cannot fire here. Ruleset `22101709` sets
105
- `require_extra_approval_for_unattributed_changes: true`, which adds one approval when a pull
106
- request is an unattributed Copilot pull request — but GitHub documents that the setting "has
107
- no effect if the ruleset requires zero approvals" ([available rules for rulesets](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets#additional-approval-for-unattributed-copilot-pull-requests),
108
- checked 2026-10-27), and this ruleset sets `required_approving_review_count: 0`. A blocked
109
- merge box here is the missing `statusCheckRollup` on a Version Packages PR or a missing
110
- code-owner review, not this setting.
111
-
112
- ## Policy: land bot-authored PRs by squash merge
113
-
114
- Adopted: **Option A — no signing key in CI.** So long as no signature rule is enforced, no
115
- unsigned commit is required to land a release: the merge produces a commit GitHub signs, so
116
- the only requirement is the merge method.
117
-
118
- Squash-merge Version Packages PRs (`gh pr merge <n> --squash`). GitHub rewrites the bot's
119
- unsigned branch commit into a single commit that it signs as committer, which is exactly
120
- what `dd347471b1` demonstrates. Squash is the only path that lands a GitHub-signed commit:
121
- `allow_merge_commit` is `false` in the repository merge settings, so a true merge commit is
122
- impossible, and `required_linear_history` on `main` means a pull request "must use a squash
123
- merge or a rebase merge". The ruleset's `allowed_merge_methods`
124
- (`["merge","squash","rebase"]`) leaves both open — its `merge` entry is already dead because
125
- the repository disables merge commits. Of those two, only squash produces a commit GitHub
126
- creates and signs: rebase-and-merge is documented to add the head-branch commits "without
127
- commit signature verification", because the commit it creates is modified and GitHub "can't
128
- therefore sign it as a generic system user" ([about merge methods](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/about-merge-methods-on-github),
129
- checked 2026-10-27). For a `github-actions[bot]` head commit that means an unsigned commit on
130
- `main`, so rebase is not an acceptable path here even though the settings permit it.
131
-
132
- Note the limit of this remedy: squash re-signs the landing commit, it does not bypass an
133
- enforced signature rule (see above). It works here because no such rule is currently
134
- enforced against this repository.
135
-
136
- Consequence: the release automation stays fully automated and no signing key enters CI —
137
- provided no signature rule is enforced. See the contingency below.
138
-
139
- ### Contingency: the enforcing rule turns out to be real at organization level
140
-
141
- The policy above holds only while a squash merge is permitted. If the merge probe or an org
142
- admin confirms an organization-level `required_signatures` rule, Option A's premise fails:
143
- GitHub would then refuse the squash merge as well, because it validates the pull request's
144
- head commits through the test merge. In that case:
145
-
146
- 1. Do not keep re-attempting the squash merge, and do not treat a bypass as the workaround —
147
- a bypass is a human permission decision, not a release path.
148
- 2. The release path must produce signed commits, which means Option B (import a key into the
149
- release job) or having a key-holding actor sign the release commit. That change must land
150
- with the access audit and rotation procedure Option B requires.
151
- 3. Until then, releasing is a human step performed with bypass permission, recorded as a
152
- HITL note on the bead.
153
-
154
- The applied-rule read returns no organization-sourced rule, but org ruleset definitions stay
155
- unreadable from a repository-scoped token, so re-check the read before assuming the absence
156
- persists.
157
-
158
- ### Option B, rejected as the default
159
-
160
- Importing a GPG key into the release job (`GPG_PRIVATE_KEY` + `GPG_PASSPHRASE` secrets and
161
- a `git commit --amend -S` step) would make the *branch* commit signed too. It is rejected as
162
- the default because, while no signature rule is enforced, it buys nothing the squash merge
163
- does not already give — the branch commit is discarded on merge — while placing a
164
- long-lived private key in repository secrets. That trade-off inverts if a signature rule is
165
- confirmed enforced: Option B then becomes necessary (see the contingency above). Either way,
166
- if it is revisited the same change must carry an access audit (who and what can read the
167
- secret) and a rotation procedure (key expiry, re-issue, revocation). Neither exists today,
168
- and adding the key without them is not acceptable.
169
-
170
- ## When the signature check fires
171
-
172
- | Situation | Remedy |
173
- |---|---|
174
- | Bot-authored PR blocked on signatures, rule **confirmed** enforced | A squash merge will not help — GitHub checks head-branch commits through its test merge. Rewrite the branch so its commits are signed (`git rebase --exec 'git commit --amend -S --no-edit'` or an amend plus force-push), then merge; otherwise a person with bypass permission merges it. |
175
- | Bot-authored PR blocked, `rules/branches/main` lists no `required_signatures` rule | The block is most likely not signatures. Read the merge box first: missing required status checks (an empty `statusCheckRollup` on a Version Packages PR is the common case) or a missing code-owner review fully explain `mergeStateStatus=BLOCKED`. |
176
- | An agent commit is reported unsigned | Check `git config --get commit.gpgsign` and `gpg --list-secret-keys`; re-sign with `git commit --amend -S --no-edit` and force-push the branch. |
177
- | The block persists with no visible cause | Read `gh api repos/<owner>/<repo>/rules/branches/<branch>`. That endpoint covers every level, so no `required_signatures` entry means no active signature rule applies as far as this read can see — if the block still looks like signatures, have an org admin confirm the org rulesets rather than guessing. |
178
-
179
- ## The enforcing rule: still open (AC1)
180
-
181
- The parent bead's first acceptance criterion — "Enforcing rule identified, or the UI message
182
- shown to be stale — with the merge API's error text quoted either way" — is **open**. No
183
- merge API error text exists yet, because obtaining it requires a merge attempt, which is a
184
- mutation and therefore a human step. Read-only evidence narrows the question sharply but
185
- does not close it:
186
-
187
- 1. **No repository-level signature rule was blocking on 2026-10-13.** PR #161's head
188
- `fe7ef84` is `verification.verified=false reason=unsigned`, and the PR was squash-merged
189
- at `2026-10-13T21:46:06Z` — after ruleset `22101709`'s last update
190
- (`2026-09-13T21:11:23.985+01:00`, i.e. `2026-09-13T20:11:23Z`). An unsigned head landed
191
- after the ruleset's last edit, so neither that ruleset nor anything older in it enforced
192
- signatures then.
193
- 2. **PR #168's current block needs no signature rule to explain it.**
194
- `gh pr view 168 --json state,mergeable,mergeStateStatus,statusCheckRollup,reviews` returns
195
- `state=OPEN`, `mergeable=MERGEABLE`, `mergeStateStatus=BLOCKED`,
196
- `statusCheckRollup=[]`, `reviews=[]`. All five required checks (`Test`, `Lint`,
197
- `Claude plugin materialiser check`, `Changeset check`, `Setup`) are unreported, and
198
- `require_code_owner_review` is on with no reviews. `required_status_checks` plus the
199
- missing code-owner review fully account for `BLOCKED`.
200
- 3. **The applied-rule read comes back clean, including at organization level.**
201
- `rules/branches/{branch}` is documented to return every active rule "regardless of the
202
- level at which they are configured (e.g. repository or organization)", so it is the read
203
- that *would* surface an organization-level rule. The live read returns five rules, all
204
- `ruleset_source_type: Repository` from `ruleset_id 22101709`, and none of them is
205
- `required_signatures`. On the documented contract that is positive evidence that no
206
- organization-level signature rule is applied to `main` today, not an unreadable gap. The
207
- honest residual is narrower: whether this endpoint filters by caller visibility is
208
- undocumented, and org ruleset *definitions* stay unreadable with the current token —
209
- `gh api orgs/jaybeeuu/rulesets` returns `{"message":"Not Found", ... "status":"404"}` and
210
- `gh api orgs/jaybeeuu` adds `gh: This API operation needs the "admin:org" scope`. So "no
211
- org rule is applied" is read; "no org ruleset exists" is not.
212
-
213
- Status: **open, pending a human merge probe or org-admin inspection** (see below). The read
214
- above narrows the question but cannot close AC1, which turns on the merge API's own error
215
- text; the merge probe supplies that.
216
-
217
- ## Human-only follow-ups
218
-
219
- These need repository or organization settings and cannot be done by an agent:
220
-
221
- - **Merge probe — closes AC1.** Run `gh pr merge 168 --squash` (or
222
- `PUT /repos/jaybeeuu/agent-cortex/pulls/168/merge`) and record the verbatim error text
223
- here. A signature error confirms an invisible rule and triggers the contingency above; a
224
- status-check error confirms the message was stale and closes the criterion as
225
- "UI message stale".
226
- - **Inspect org rulesets.** Open `https://github.com/organizations/jaybeeuu/settings/rules`
227
- and confirm whether a ruleset targets `jaybeeuu/agent-cortex` with "Require signed
228
- commits". Record the answer here.
229
- - **Confirm the merge method.** If squash-merge is the documented path, consider removing
230
- `rebase` from `allowed_merge_methods` so a rebase merge cannot add an unsigned bot
231
- commit to `main`.
@@ -1,75 +0,0 @@
1
- # Idea: Auto-Model Selection Plugin
2
-
3
- ## Status
4
- Backlog idea (not implementation-ready) — **direction: evaluate and adopt existing package**
5
-
6
- ## Why it might be useful
7
- PI has no intelligent model selection. Users must manually choose models, which means they either over-provision (expensive models for simple tasks) or under-provision (weak models for complex work). Rate limits hit without warning, forcing manual model switching mid-session. An auto-selection plugin would optimize cost/performance by matching model capability to task complexity, and provide seamless fallbacks when rate limits are hit.
8
-
9
- ## How we might do it
10
- **Evaluate and adopt an existing PI extension** rather than building from scratch. The ecosystem already has well-maintained packages that cover task-based routing and rate-limit fallbacks. The goal is to:
11
-
12
- 1. **Evaluate the top candidates** (see "Packages to evaluate" below)
13
- 2. **Pick the best fit** for agent-cortex's workflow (beads, pipeline stages, HITL/AFK classification)
14
- 3. **Install and configure** it, possibly with light customisation if needed
15
- 4. **Document** the chosen package and configuration in agent-cortex docs
16
-
17
- ## Packages to evaluate (in priority order)
18
- **Top candidates — cover both task-based routing AND fallbacks:**
19
- 1. **`@kylebrodeur/pi-model-router`** — per-turn routing to high/medium/low tiers based on task intent, context size, budget, with automatic fallback chains and rate-limit recovery. Well-documented fork of yeliu84's original.
20
- 2. **`pi-auto-router`** — multi-provider routing with same-request failover, budget-aware policies, and quota-aware fallback.
21
- 3. **`pi-tiered-router`** — routes different *phases* (planner/validator/executor/tool-parser) to different models. Quality-first, not cost-saving.
22
-
23
- **Fallback-only (simpler, if routing is overkill):**
24
- - **`pi-auto-models`** — Claude→Codex quota switching with 429/529 recovery
25
- - **`pi-provider-fallback`** — cross-provider fallback chain with TUI config
26
-
27
- **Evaluation criteria:**
28
- - Does it integrate cleanly with PI's existing provider/model system?
29
- - Does it respect user's explicit model choice, or override it?
30
- - How does it handle context window mismatches on fallback?
31
- - Is it configurable per-project?
32
- - Does it have fallback chains or just single fallback?
33
- - Rate-limit detection and retry logic
34
- - Documentation quality and maintenance status
35
-
36
- ## When to think about it
37
- - After current feature stabilisation (refactor-to-template epic, npm publishing, system prompt improvements)
38
- - Not blocked, but benefits from stable extension infrastructure
39
-
40
- ## Priority
41
- Medium / backlog — valuable for cost optimisation and reliability, but not urgent. Current manual model selection works, just isn't optimal.
42
-
43
- ## Open questions
44
- - How to classify task complexity? Heuristics (file count, prompt length, keywords)? Or let user tag tasks?
45
- - What defines a "model class"? Cost tier, context window size, reasoning capability, speed?
46
- - Should the plugin override the user's explicit model choice, or only activate when no model is selected?
47
- - How to handle context window mismatches when falling back (e.g., 200k → 128k)?
48
- - Should this be configurable per-project (different policies for different repos)?
49
-
50
- ## Existing packages in the ecosystem
51
- Several published packages already address parts of this problem:
52
-
53
- ### Fallback / rate-limit recovery
54
- - **`pi-provider-fallback`** — cross-provider fallback with interactive TUI config
55
- - **`pi-auto-models`** — primary/fallback switching on quota (Claude→Codex default), 429/529 recovery
56
-
57
- ### Task-based / tier routing
58
- - **`pi-model-router`** (yeliu84, forked by @kdejaeger and @kylebrodeur) — per-turn routing to high/medium/low tiers based on task intent, context size, budget, with automatic fallbacks
59
- - **`pi-model-auto`** — routes by Low/Medium/High/Ultra capability modes per turn
60
- - **`pi-tiered-router`** — routes different phases (planner/validator/executor/tool-parser) to different models
61
-
62
- ### Full auto-router with failover
63
- - **`pi-auto-router`** — multi-provider routing with same-request failover, budget-aware policies
64
- - **`@ifi/pi-extension-adaptive-routing`** — adaptive routing with local telemetry persistence
65
-
66
- ### Model selection (manual)
67
- - **`pi-model-switch`** — direct model switching tool
68
- - **`pi-model-select`** — `/select-model` with favourites and fuzzy search
69
-
70
- ## Notes
71
- - **The ecosystem is active** — this space is already well-served. Before building, evaluate whether an existing package (especially `pi-model-router` or `pi-auto-router`) already meets the need.
72
- - **Gap analysis needed**: compare existing packages against the original requirements (task-based class selection + rate-limit fallbacks) to see if anything is genuinely missing.
73
- - **Partial solutions exist in PI core**: OpenRouter's routing config supports fallbacks and provider ordering, but only within OpenRouter. Cross-provider fallback requires an extension.
74
- - **Implementation approach** (if building): likely a PI extension that registers a "smart-router" provider, which internally delegates to real providers based on task classification and availability.
75
- - **Research done**: reviewed PI docs on providers, models, and extensions. Searched npm and pi.dev for existing packages.