@jaybeeuu/agent-cortex 2.1.0 → 2.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/CHANGELOG.md +411 -0
- package/README.md +33 -13
- package/agents/README.md +22 -10
- package/agents/plan/agent.md +2 -2
- package/agents/ralph/agent.md +126 -88
- package/agents/ralph/claude/frontmatter.json +3 -3
- package/agents/ralph/claude/wake.md +46 -0
- package/agents/ralph/pi/{polling.md → wake.md} +35 -20
- package/agents/ralph-plan/agent.md +23 -11
- package/bin/agent-cortex.mjs +66 -4
- package/bin/installers/claude.mjs +182 -68
- package/bin/installers/pi.mjs +200 -24
- package/extensions/agent-guardrails/README.md +1 -1
- package/extensions/agent-guardrails/guardrails.ts +1 -1
- package/extensions/agent-guardrails/index.ts +1 -1
- package/extensions/agent-modes/discover.test.ts +2 -2
- package/extensions/output-style/README.md +1 -1
- package/extensions/output-style/index.ts +2 -2
- package/extensions/output-style/output-style.ts +2 -2
- package/hooks/claude/scripts/notify.mjs +8 -1
- package/lib/cli.mjs +91 -2
- package/package.json +27 -3
- package/scripts/check-changeset.mjs +4 -0
- package/scripts/check-no-sync.mjs +5 -1
- package/scripts/lib/compose-agent.mjs +69 -9
- package/scripts/lib/fs.mjs +10 -2
- package/scripts/lib/migrate.mjs +736 -0
- package/scripts/lib/release-gates.mjs +21 -1
- package/scripts/lib/skill-frontmatter.mjs +23 -6
- package/scripts/lib/skill-links.mjs +52 -0
- package/scripts/lib/verify-worker-tree.mjs +25 -0
- package/scripts/resolve-publish-command.mjs +4 -0
- package/skills/engineering/design-an-interface/SKILL.md +3 -3
- package/skills/engineering/grill-with-docs/SKILL.md +3 -5
- package/skills/engineering/improve-codebase-architecture/SKILL.md +5 -4
- package/skills/engineering/tdd/SKILL.md +5 -7
- package/skills/engineering/technical-direction/SKILL.md +5 -5
- package/skills/planning/classify-bead/REFERENCE.md +3 -3
- package/skills/planning/classify-bead/SKILL.md +14 -9
- package/skills/planning/classify-bead/scripts/classify-bead.mjs +5 -4
- package/skills/planning/create-task/REFERENCE.md +52 -3
- package/skills/planning/create-task/SKILL.md +70 -26
- package/skills/planning/create-task/scripts/{create-chores.ts → create-chores.mjs} +48 -23
- package/skills/planning/flesh-out-idea/REFERENCE.md +116 -0
- package/skills/planning/flesh-out-idea/SKILL.md +146 -0
- package/skills/planning/prd-to-tasks/REFERENCE.md +54 -5
- package/skills/planning/prd-to-tasks/SKILL.md +22 -16
- package/skills/planning/record-idea/FORMAT.md +66 -17
- package/skills/planning/record-idea/SKILL.md +48 -24
- package/skills/planning/request-refactor-plan/SKILL.md +4 -4
- package/skills/planning/spec-to-tickets/SKILL.md +5 -5
- package/skills/planning/write-a-prd/SKILL.md +8 -9
- package/skills/planning/write-a-ticket/SKILL.md +4 -6
- package/skills/productivity/bd-tool/SKILL.md +15 -10
- package/skills/productivity/grill-me/SKILL.md +5 -0
- package/skills/productivity/init-beads/SKILL.md +3 -3
- package/skills/productivity/migration/REFERENCE.md +227 -0
- package/skills/productivity/migration/SKILL.md +188 -0
- package/skills/productivity/validate-agent-dir/scripts/{validate-agent-dir.ts → validate-agent-dir.mjs} +49 -28
- package/skills/productivity/write-a-skill/SKILL.md +5 -5
- package/skills/review/maintain-agent-docs/SKILL.md +5 -7
- package/skills/review/refactor-skill/SKILL.md +4 -3
- package/skills/review/review-security/SKILL.md +3 -5
- package/skills/style/style-code/SKILL.md +5 -10
- package/skills/style/style-comms/SKILL.md +5 -7
- package/skills/style/style-documentation/SKILL.md +5 -6
- package/skills/style/style-tests/SKILL.md +5 -7
- package/skills/workflow/git-workflow/SKILL.md +52 -26
- package/skills/workflow/hitl-collab/SKILL.md +4 -6
- package/skills/workflow/plan/SKILL.md +41 -30
- package/skills/workflow/ralph/REFERENCE.md +182 -51
- package/skills/workflow/ralph/SKILL.md +89 -50
- package/skills/workflow/run-pipeline-stage/SKILL.md +72 -71
- package/skills/workflow/run-pipeline-stage/playbooks/code.md +11 -0
- package/skills/workflow/run-pipeline-stage/playbooks/document.md +12 -0
- package/skills/workflow/run-pipeline-stage/playbooks/fix.md +12 -0
- package/skills/workflow/run-pipeline-stage/playbooks/review.md +11 -0
- package/skills/workflow/run-pipeline-stage/playbooks/verify.md +13 -0
- package/skills/workflow/run-pipeline-stage/prompts/stage-runner.md +73 -1
- package/token-map.README.md +9 -4
- package/token-map.json +13 -6
- package/.agents/skills/style-versioning/SKILL.md +0 -172
- package/.changeset/README.md +0 -8
- package/.changeset/config.json +0 -11
- package/.github/workflows/ci.yml +0 -302
- package/.junie/guidelines.md +0 -87
- package/.junie/mcp/mcp.json +0 -10
- package/AGENTS.md +0 -153
- package/agents/ralph/claude/polling.md +0 -31
- package/agents-native/ralph.md +0 -203
- package/docs/claude-hooks.md +0 -144
- package/docs/commit-signing.md +0 -231
- package/docs/ideas/auto-model-selection.md +0 -75
- package/docs/ideas/ban-content-assertion-tests.md +0 -75
- package/docs/ideas/bead-progress-notes-for-session-resumption.md +0 -75
- package/docs/ideas/classify-beads-via-deterministic-script-with-agent-fallback.md +0 -70
- package/docs/ideas/ctx-alias-version-and-update-commands.md +0 -65
- package/docs/ideas/ctx-feedback-command-for-capturing-ideas-from-any-machine.md +0 -67
- package/docs/ideas/dedicated-review-tests-skill.md +0 -71
- package/docs/ideas/deployment-beads-for-post-merge-pipelines.md +0 -36
- package/docs/ideas/design-and-delivery-as-separate-bead-trees/design-and-delivery-as-separate-bead-trees.md +0 -99
- package/docs/ideas/enable-signed-commit-enforcement-changesets-bot-commits-must-be-signed.md +0 -42
- package/docs/ideas/extension-manifests.md +0 -121
- package/docs/ideas/improve-pi-system-prompt.md +0 -43
- package/docs/ideas/map-every-cortex-tool-to-a-real-pi-equivalent.md +0 -95
- package/docs/ideas/model-selector.md +0 -40
- package/docs/ideas/pi-task-memory.md +0 -34
- package/docs/ideas/qa-extension.md +0 -43
- package/docs/ideas/record-idea-implementation-questions.md +0 -68
- package/docs/ideas/record-ideas-as-beads.md +0 -115
- package/docs/ideas/self-flushing-session.md +0 -72
- package/docs/ideas/state-in-beads-not-md.md +0 -69
- package/docs/ideas/subagent-visibility.md +0 -72
- package/docs/ideas/task-session-context.local.md +0 -95
- package/docs/ideas/task-session-context.md +0 -89
- package/docs/ideas/test-data-creation-helpers.md +0 -92
- package/docs/ideas/test-planning-stage-bead-in-feature-planning.md +0 -68
- package/docs/ideas/unified-ci-pipeline.md +0 -28
- package/docs/ideas/unify-the-ticket-and-task-decomposition-workflows.md +0 -71
- package/docs/ideas/worktree-housekeeping-for-closed-beads.md +0 -39
- package/docs/inspirations.md +0 -33
- package/docs/research/disable-model-invocation.md +0 -82
- package/docs/research/gas-city-research.md +0 -256
- package/docs/research/skill-design-research.md +0 -286
- package/docs/research/skill-improvements-analysis.md +0 -117
- package/docs/research/skill-patterns-research.md +0 -24
- package/docs/skills/skill-anatomy.md +0 -200
- package/docs/technical-direction/harness-config.md +0 -177
- package/docs/technical-direction/migration-execution-labels.md +0 -177
- package/docs/user-preferences.md +0 -17
- package/extensions/agent-guardrails/tsconfig.json +0 -12
- package/extensions/agent-modes/tsconfig.json +0 -12
- package/extensions/output-style/tsconfig.json +0 -12
- package/extensions/session-start/tsconfig.json +0 -12
- package/extensions/skill-stats/pnpm-lock.yaml +0 -329
- package/extensions/skill-stats/tsconfig.json +0 -12
- package/extensions/subagent/agents/planner.md +0 -37
- package/extensions/subagent/agents/reviewer.md +0 -35
- package/extensions/subagent/agents/scout.md +0 -50
- package/extensions/subagent/agents/worker.md +0 -24
- package/extensions/subagent/prompts/implement-and-review.md +0 -10
- package/extensions/subagent/prompts/implement.md +0 -10
- package/extensions/subagent/prompts/scout-and-plan.md +0 -9
- package/extensions/subagent/tsconfig.json +0 -12
- package/pi/keybindings.json +0 -3
- package/pi/settings.json +0 -34
- package/pnpm-workspace.yaml +0 -14
- package/skills/planning/create-task/scripts/package.json +0 -14
- package/skills/planning/create-task/scripts/pnpm-lock.yaml +0 -342
- package/skills/planning/create-task/scripts/tsconfig.json +0 -12
- package/skills/planning/record-idea/scripts/new-idea.sh +0 -89
- package/skills/productivity/validate-agent-dir/scripts/package.json +0 -15
- package/skills/productivity/validate-agent-dir/scripts/pnpm-lock.yaml +0 -329
- package/skills/productivity/validate-agent-dir/scripts/pnpm-workspace.yaml +0 -2
- package/skills/productivity/validate-agent-dir/scripts/tsconfig.json +0 -19
- package/skills/productivity/validate-agent-dir/scripts/validate-agent-dir.test.ts +0 -317
- package/skills/workflow/run-pipeline-stage/REFERENCE.md +0 -22
- package/skills/workflow/run-pipeline-stage/scripts/generate-progress.test.ts +0 -682
- package/skills/workflow/run-pipeline-stage/scripts/generate-progress.ts +0 -588
- package/skills/workflow/run-pipeline-stage/scripts/package.json +0 -15
- package/skills/workflow/run-pipeline-stage/scripts/pnpm-lock.yaml +0 -342
- package/skills/workflow/run-pipeline-stage/scripts/pnpm-workspace.yaml +0 -2
- package/skills/workflow/run-pipeline-stage/scripts/tsconfig.json +0 -12
- package/test/classify-bead.test.mjs +0 -277
- package/test/claude-installer.test.mjs +0 -308
- package/test/cli.test.mjs +0 -314
- package/test/create-chores.test.mjs +0 -85
- package/test/fake-bd.test.mjs +0 -72
- package/test/fs.test.mjs +0 -76
- package/test/helpers/fake-bd.mjs +0 -87
- package/test/helpers/fake-claude.mjs +0 -152
- package/test/helpers/fake-pi.mjs +0 -132
- package/test/installer.test.mjs +0 -806
- package/test/notify-hook.test.mjs +0 -63
- package/test/pending-gates.test.mjs +0 -147
- package/test/pi-installer.test.mjs +0 -785
- package/test/pi-register.test.mjs +0 -342
- package/test/pi-sweep.test.mjs +0 -619
- package/test/release-gates.test.mjs +0 -190
- package/test/skill-frontmatter.test.mjs +0 -137
- package/test/verify-worker-tree.test.mjs +0 -120
package/agents-native/ralph.md
DELETED
|
@@ -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.)
|
package/docs/claude-hooks.md
DELETED
|
@@ -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.
|
package/docs/commit-signing.md
DELETED
|
@@ -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.
|