@jaybeeuu/agent-cortex 1.42.0 → 2.0.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 (83) hide show
  1. package/.agents/skills/style-versioning/SKILL.md +78 -8
  2. package/.github/workflows/ci.yml +51 -38
  3. package/AGENTS.md +32 -17
  4. package/CHANGELOG.md +182 -0
  5. package/README.md +167 -126
  6. package/agents/README.md +26 -27
  7. package/agents/ralph/agent.md +7 -10
  8. package/agents/ralph/claude/polling.md +1 -1
  9. package/bin/agent-cortex.mjs +46 -44
  10. package/bin/installers/claude.mjs +2 -2
  11. package/bin/installers/pi.mjs +885 -237
  12. package/docs/claude-hooks.md +5 -4
  13. package/docs/commit-signing.md +231 -0
  14. package/docs/ideas/enable-signed-commit-enforcement-changesets-bot-commits-must-be-signed.md +10 -1
  15. package/docs/ideas/extension-manifests.md +5 -0
  16. package/docs/research/disable-model-invocation.md +82 -0
  17. package/docs/research/skill-design-research.md +2 -2
  18. package/docs/skills/skill-anatomy.md +5 -2
  19. package/docs/technical-direction/harness-config.md +30 -14
  20. package/docs/technical-direction/migration-execution-labels.md +17 -9
  21. package/docs/user-preferences.md +2 -2
  22. package/extensions/agent-modes/README.md +3 -3
  23. package/extensions/agent-modes/discover.test.ts +19 -0
  24. package/extensions/agent-modes/discover.ts +31 -9
  25. package/extensions/session-start/README.md +38 -0
  26. package/extensions/session-start/index.test.ts +122 -0
  27. package/extensions/session-start/index.ts +27 -0
  28. package/extensions/session-start/package.json +19 -0
  29. package/extensions/session-start/tsconfig.json +12 -0
  30. package/extensions/skill-stats/pnpm-lock.yaml +329 -0
  31. package/extensions/subagent/README.md +3 -3
  32. package/extensions/subagent/agents.test.ts +176 -0
  33. package/extensions/subagent/agents.ts +101 -11
  34. package/extensions/subagent/index.ts +2 -1
  35. package/extensions/subagent/package.json +1 -1
  36. package/lib/cli.mjs +40 -16
  37. package/package.json +8 -9
  38. package/pi/settings.json +1 -7
  39. package/pnpm-workspace.yaml +6 -0
  40. package/scripts/check-changeset.mjs +42 -0
  41. package/scripts/lib/compose-agent.mjs +10 -10
  42. package/scripts/lib/release-gates.mjs +61 -0
  43. package/scripts/lib/verify-worker-tree.mjs +107 -0
  44. package/scripts/resolve-publish-command.mjs +17 -0
  45. package/skills/planning/create-task/scripts/pnpm-lock.yaml +342 -0
  46. package/skills/productivity/validate-agent-dir/scripts/pnpm-lock.yaml +329 -0
  47. package/skills/workflow/git-workflow/SKILL.md +35 -1
  48. package/skills/workflow/ralph/REFERENCE.md +20 -4
  49. package/skills/workflow/ralph/SKILL.md +9 -6
  50. package/skills/workflow/run-pipeline-stage/SKILL.md +11 -4
  51. package/skills/workflow/run-pipeline-stage/playbooks/code.md +2 -0
  52. package/skills/workflow/run-pipeline-stage/playbooks/document.md +3 -0
  53. package/skills/workflow/run-pipeline-stage/playbooks/fix.md +2 -0
  54. package/skills/workflow/run-pipeline-stage/prompts/stage-runner.md +11 -0
  55. package/skills/workflow/run-pipeline-stage/scripts/pnpm-lock.yaml +342 -0
  56. package/test/cli.test.mjs +37 -39
  57. package/test/helpers/fake-pi.mjs +132 -0
  58. package/test/pi-installer.test.mjs +345 -286
  59. package/test/pi-register.test.mjs +342 -0
  60. package/test/pi-sweep.test.mjs +619 -0
  61. package/test/release-gates.test.mjs +190 -0
  62. package/test/verify-worker-tree.test.mjs +120 -0
  63. package/token-map.README.md +16 -18
  64. package/token-map.json +29 -33
  65. package/agents/plan/copilot/frontmatter.json +0 -6
  66. package/agents/plan.agent.md +0 -59
  67. package/agents/ralph/copilot/frontmatter.json +0 -6
  68. package/agents/ralph/copilot/polling.md +0 -62
  69. package/agents/ralph-plan/copilot/frontmatter.json +0 -6
  70. package/agents/ralph-plan.agent.md +0 -126
  71. package/agents/ralph.agent.md +0 -331
  72. package/agents/strategy/copilot/frontmatter.json +0 -6
  73. package/agents/strategy.agent.md +0 -112
  74. package/bin/installers/copilot.mjs +0 -124
  75. package/extensions/session-start.ts +0 -44
  76. package/hooks.json +0 -10
  77. package/lib/pi-packages.mjs +0 -169
  78. package/plugin.json +0 -35
  79. package/scripts/build-copilot-agents.mjs +0 -30
  80. package/scripts/install-instructions.sh +0 -82
  81. package/scripts/sync-plugin-version.sh +0 -17
  82. package/test/copilot-installer.test.mjs +0 -308
  83. package/test/pi-packages.test.mjs +0 -295
@@ -54,17 +54,35 @@ Fix status bead showing wrong priority after update
54
54
 
55
55
  ### Rules
56
56
 
57
+ - **Every PR adds a changeset.** CI fails otherwise. The only opt-out is the
58
+ `no-publish` label (see below).
57
59
  - The frontmatter package name must match exactly: `"@jaybeeuu/agent-cortex"`
58
60
  - The description should be one or two sentences, user-facing (it goes into CHANGELOG.md)
59
61
  - One changeset per PR. If a PR has multiple unrelated changes, use multiple changeset files.
60
62
  - The filename doesn't matter to changesets — only the frontmatter and description do.
61
63
 
64
+ ## The PR gate
65
+
66
+ `changeset-check` runs on every pull request and fails it unless the PR adds a
67
+ `.changeset/*.md` file. **Publishing is the default; `no-publish` is the only
68
+ opt-out** — skipping a release is an explicit, reviewable decision, never an accident.
69
+
70
+ | Exemption | Applies to |
71
+ |---|---|
72
+ | `changeset-release/*` head branch, or actor `github-actions[bot]` | the changesets bot's Version Packages PR — it consumes changesets and adds none of its own |
73
+ | `no-publish` label | a PR that genuinely ships nothing |
74
+
75
+ The `no-publish` label must exist in the repository's label settings — a one-off
76
+ human step (`gh label create no-publish`), not something a PR can ship. If the gate
77
+ fails and the PR really ships nothing, ask for the label; do not manufacture a
78
+ changeset to make it green.
79
+
62
80
  ## After merge to main
63
81
 
64
82
  The `release` job in `.github/workflows/ci.yml` handles everything automatically:
65
83
 
66
84
  1. **Detects new changesets** on main
67
- 2. **Creates a "Version Packages" PR** — the `version` step runs `pnpm version-packages`, which bumps `package.json`, syncs `plugin.json` (via `scripts/sync-plugin-version.sh`), updates `CHANGELOG.md`, and regenerates the committed Copilot output (`pnpm build:copilot`; the Claude plugin is materialised at install time with the package version, so it has no committed output to regenerate) so the drift gates never fail on a version bump
85
+ 2. **Creates a "Version Packages" PR** — the `version` step runs `pnpm version-packages` (`changeset version`), which bumps `package.json` and rewrites `CHANGELOG.md`. That is the whole release surface: every plugin this package ships is materialised at install time with the package version, so there is no generated output to regenerate and no drift gates to satisfy on a version bump
68
86
  3. **When "Version Packages" is merged**:
69
87
  - Creates a git tag
70
88
  - Publishes to npm — `pnpm publish-package` packs with `pnpm pack` and publishes with `npm publish --provenance --access public`. Authenticates via npm Trusted Publishing (OIDC): the release job's `id-token` permission lets npm exchange a GitHub OIDC token for a short-lived npm token at publish time, so no `NPM_TOKEN` secret or `.npmrc` auth config is required — only the one-time npm-side Trusted Publishing setup on npmjs.com (package → Access → Trusted Publishing → GitHub repo `jaybeeuu/agent-cortex` + workflow `.github/workflows/ci.yml`)
@@ -72,25 +90,77 @@ The `release` job in `.github/workflows/ci.yml` handles everything automatically
72
90
 
73
91
  `changesets/action` execs the `version`/`publish` inputs without a shell, so each
74
92
  must be a single unquoted command token — keep release logic in pnpm scripts
75
- (`version-packages`, `publish-package`), never inline shell strings.
93
+ (`version-packages`, `publish-package`, `publish-noop`), never inline shell strings.
94
+
95
+ ### Approve CI on the Version Packages PR
96
+
97
+ The version PR arrives `BLOCKED` with an empty check list, and nothing is broken:
98
+ `changesets/action` pushes that branch with `GITHUB_TOKEN`, so GitHub parks the CI
99
+ run the push creates behind **“Approve workflows to run”** (`action_required`, zero
100
+ jobs). A parked run reports no checks, so the five required contexts are
101
+ unsatisfiable until someone approves it. Approve it from the PR's merge box, or:
102
+
103
+ ```bash
104
+ run=$(gh run list --branch changeset-release/main --limit 20 \
105
+ --json databaseId,conclusion --jq 'map(select(.conclusion=="action_required"))[0].databaseId')
106
+ gh api -X POST "repos/{owner}/{repo}/actions/runs/$run/approve"
107
+ ```
108
+
109
+ An approval is per head commit. Every merge to `main` force-updates the version
110
+ branch and starts a fresh parked run, so approve immediately before merging the
111
+ version PR — not once per release. Do not reach for a PAT or GitHub App token to
112
+ skip this: one click is cheaper than a long-lived credential in repository
113
+ secrets, and the `GITHUB_TOKEN` the job already holds cannot approve its own run.
114
+
115
+ Which of the two publish scripts runs is decided per push, not hard-coded: labels are
116
+ invisible on a push event, so the job resolves the PR merged for the pushed commit via
117
+ the GitHub API and reads its labels — `publish-noop` when the PR carried `no-publish`,
118
+ `publish-package` otherwise. That needs no new secret or scope; the job already holds
119
+ `GITHUB_TOKEN` and `pull-requests: write`. A direct push with no merged PR resolves to
120
+ no labels and so publishes, which keeps a genuine publish of an already-published
121
+ version failing loudly — there is deliberately no idempotency guard.
122
+
123
+ ### Merge method and commit signatures
124
+
125
+ Land a Version Packages PR with `gh pr merge <n> --squash`. Agent and human commits here are
126
+ GPG-signed by the environment and verify as `valid`; the `github-actions[bot]` commit is
127
+ `unsigned` because `GITHUB_TOKEN` cannot sign. The commit that lands is signed by GitHub,
128
+ which is why `main`'s history reads `valid`: PR #161's unsigned head `fe7ef84` landed as
129
+ `dd347471b1` with `committer=GitHub`, `verified=true`.
130
+
131
+ Squash re-signs the landing commit; it does not escape an enforced signature rule. GitHub
132
+ evaluates a pull request by creating a test merge commit and checking the commits it
133
+ introduces — head-branch commits included — so an enforced `required_signatures` rule blocks
134
+ a squash merge too, and the remedy is then a signed commit on the branch, not another merge
135
+ method. `allow_merge_commit` is off and `required_linear_history` is on, so a merge commit is
136
+ not an option — squash or rebase only, and only squash lands a commit GitHub signs.
137
+
138
+ See `docs/commit-signing.md` for the evidence, the ruleset reads that show only
139
+ repository-level rules applying to `main` (a read that covers organization rules too), and the
140
+ human-only follow-ups, including the merge probe that closes AC1.
76
141
 
77
142
  ### Version lockstep
78
143
 
79
- All version numbers stay in lockstep automatically:
144
+ Two files carry the version, in lockstep automatically:
80
145
 
81
146
  1. `package.json` → bumped by changesets
82
- 2. `plugin.json` → synced by `scripts/sync-plugin-version.sh`
83
- 3. `CHANGELOG.md` → generated by changesets
147
+ 2. `CHANGELOG.md` → generated by changesets
84
148
 
85
149
  **Never bump versions manually.** Always create a changeset file.
86
150
 
87
151
  ## Common mistakes
88
152
 
89
153
  - **Running `pnpm changeset`**: Interactive, wastes tokens. Write the file directly.
90
- - **Bumping versions manually**: Don't touch `"version"` in `package.json` or `plugin.json`. Create a changeset.
91
- - **Skipping the changeset**: A PR without a changeset won't trigger a release. The changesets bot will remind you.
154
+ - **Bumping versions manually**: Don't touch `"version"` in `package.json`. Create a changeset.
155
+ - **Omitting the changeset**: CI fails the PR. Publishing is the default; the only
156
+ opt-out is the `no-publish` label, which must already exist in the repo's settings.
92
157
  - **Wrong bump type**: `patch` for fixes, `minor` for additions, `major` for breakage. When in doubt, ask the user.
93
158
  - **Wrong package name in frontmatter**: Must be `"@jaybeeuu/agent-cortex"` exactly.
159
+ - **Merging a Version Packages PR with anything but squash**: the bot's commit is unsigned,
160
+ and squash is the path this repo has landed on (a rebase merge adds the head-branch commit
161
+ without signature verification).
162
+ Squash does not, however, bypass an enforced signature rule — if one is confirmed, the
163
+ branch needs a signed commit. See `docs/commit-signing.md`.
94
164
 
95
165
  ## What changed from the old workflow
96
166
 
@@ -99,4 +169,4 @@ All version numbers stay in lockstep automatically:
99
169
  | Agent bumps versions locally | Agent writes a changeset file |
100
170
  | Manual GitHub release creation | Automated by the `release` job in `ci.yml` |
101
171
  | `publish.yml` triggered by release | `ci.yml` release job on push to main |
102
- | Version sync was manual | `sync-plugin-version.sh` runs automatically |
172
+ | Version files synced by hand | changesets bumps `package.json` + `CHANGELOG.md` |
@@ -5,6 +5,12 @@ on:
5
5
  branches:
6
6
  - main
7
7
  pull_request:
8
+ # The default types (opened/synchronize/reopened) would make the documented
9
+ # `no-publish` opt-out unreachable: labelling a PR after the check failed
10
+ # would never re-trigger it, and a manual re-run replays the original event
11
+ # payload. Label events keep the gate honest in both directions — adding the
12
+ # label turns it green, removing it turns it red again.
13
+ types: [opened, synchronize, reopened, labeled, unlabeled]
8
14
 
9
15
  jobs:
10
16
  setup:
@@ -42,6 +48,12 @@ jobs:
42
48
 
43
49
  changeset-check:
44
50
  name: Changeset check
51
+ # The gate is a pure, idempotent recomputation of the diff plus PR metadata,
52
+ # so every pull_request event must run it. Do NOT narrow this to the
53
+ # labels that can change the verdict: GitHub reports a skipped job as a
54
+ # success (docs.github.com - about-status-checks), so skipping on unrelated
55
+ # label churn would silently turn a failing gate green and let a
56
+ # changeset-less PR merge.
45
57
  if: github.event_name == 'pull_request'
46
58
  runs-on: ubuntu-latest
47
59
  steps:
@@ -49,35 +61,25 @@ jobs:
49
61
  uses: actions/checkout@v4
50
62
  with:
51
63
  fetch-depth: 0
52
- - name: Check for changeset
64
+
65
+ - name: Setup Node
66
+ uses: actions/setup-node@v6
67
+ with:
68
+ node-version: 24
69
+
70
+ # Publishing is the default: every PR must add a changeset. The only
71
+ # exemptions are the changesets bot's Version Packages PR (it consumes
72
+ # changesets and adds none) and PRs explicitly labelled `no-publish`.
73
+ # Deciding that in code keeps the rule unit-tested; this step only feeds
74
+ # it the diff and the PR metadata.
75
+ - name: Require a changeset unless labelled no-publish
53
76
  env:
54
77
  BASE_REF: ${{ github.event.pull_request.base.ref }}
78
+ PR_HEAD_REF: ${{ github.event.pull_request.head.ref }}
79
+ PR_ACTOR: ${{ github.event.pull_request.user.login }}
80
+ PR_LABELS: ${{ toJSON(github.event.pull_request.labels.*.name) }}
55
81
  run: |
56
- # Paths that require a changeset when modified
57
- VERSIONED_PATHS='extensions/|skills/|agents/|package\.json|plugin\.json'
58
-
59
- changed=$(git diff --name-only "origin/${BASE_REF}...HEAD")
60
- echo "Changed files:"
61
- echo "$changed"
62
-
63
- versioned=$(echo "$changed" | grep -E "$VERSIONED_PATHS" || true)
64
- if [ -z "$versioned" ]; then
65
- echo "No versioned paths changed — skipping changeset check."
66
- exit 0
67
- fi
68
-
69
- changesets=$(echo "$changed" | grep -E '^\.changeset/.*\.md$' | grep -v 'README.md' || true)
70
- if [ -z "$changesets" ]; then
71
- echo ""
72
- echo "::error::This PR modifies versioned paths but does not include a changeset."
73
- echo "Run 'pnpm changeset' to add one. See: style-versioning skill."
74
- echo ""
75
- echo "Versioned paths changed:"
76
- echo "$versioned"
77
- exit 1
78
- fi
79
-
80
- echo "Changeset found: $changesets"
82
+ git diff --name-status "origin/${BASE_REF}...HEAD" | node scripts/check-changeset.mjs
81
83
 
82
84
  lint:
83
85
  name: Lint
@@ -218,11 +220,6 @@ jobs:
218
220
  PLUGIN_VERSION=$(node -p "require('$OUT/.claude-plugin/plugin.json').version")
219
221
  test "$PKG_VERSION" = "$PLUGIN_VERSION"
220
222
 
221
- - name: Check generated Copilot agent files are up to date
222
- run: |
223
- pnpm build:copilot
224
- git diff --exit-code -- 'agents/*.agent.md'
225
-
226
223
  release:
227
224
  name: Release
228
225
  needs: [lint, test, claude-plugin-check]
@@ -263,6 +260,22 @@ jobs:
263
260
  - name: Install dependencies
264
261
  run: pnpm install --frozen-lockfile
265
262
 
263
+ # Labels are invisible on a push event, so resolve the PR merged for this
264
+ # commit through the API and read its labels. No new secret or scope: the
265
+ # job already holds pull-requests: write, gh is preinstalled, and
266
+ # GITHUB_TOKEN is already here. A commit with no merged PR (direct push)
267
+ # resolves to no labels — publish stays the default, so attempting to
268
+ # publish an already-published version still fails loudly.
269
+ - name: Resolve publish command
270
+ id: gate
271
+ env:
272
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
273
+ run: |
274
+ labels=$(gh api "repos/${{ github.repository }}/commits/${{ github.sha }}/pulls" \
275
+ --jq '[.[] | select(.merged_at != null) | .labels[].name]')
276
+ publish=$(node scripts/resolve-publish-command.mjs "$labels")
277
+ echo "publish=${publish}" >> "$GITHUB_OUTPUT"
278
+
266
279
  - name: Create Release Pull Request or Publish
267
280
  id: changesets
268
281
  uses: changesets/action@v1
@@ -270,14 +283,14 @@ jobs:
270
283
  # changesets/action execs these inputs via @actions/exec with NO shell:
271
284
  # the string is split by argStringToArray on whitespace (single quotes
272
285
  # survive literally), so each must be a single unquoted command token
273
- # that runs a pnpm script. version-packages bumps versions, syncs
274
- # plugin.json, THEN regenerates the committed Copilot output
275
- # (build:copilot re-derives agents/*.agent.md; the Claude plugin is
276
- # materialised at install time with the package version, so nothing
277
- # committed needs regenerating) before the action commits, so the
278
- # Version Packages PR always passes the drift gates.
286
+ # that runs a pnpm script. version-packages bumps the package version
287
+ # and rewrites CHANGELOG.md, and nothing else is committed: the Claude
288
+ # plugin is materialised at install time with the package version, so
289
+ # there is no committed output to regenerate.
279
290
  version: pnpm version-packages
280
- publish: pnpm publish-package
291
+ # pnpm publish-package when the merged PR is unlabelled, pnpm
292
+ # publish-noop when it carries `no-publish`.
293
+ publish: ${{ steps.gate.outputs.publish }}
281
294
  commit: "chore: version packages"
282
295
  title: "chore: version packages"
283
296
  env:
package/AGENTS.md CHANGED
@@ -4,20 +4,17 @@ Instructions for agents working on this repository.
4
4
 
5
5
  ## What This Repo Is
6
6
 
7
- A personal Copilot CLI plugin containing custom agents and skills, shipped to Copilot, pi,
8
- and Claude Code, plus PI extensions and Claude hooks for enhancing the coding agent
9
- runtime. Changes here affect the behaviour of every agent, skill, and PI extension
10
- available in the author's coding sessions.
7
+ A personal collection of custom agents and skills, shipped to pi and Claude Code, plus PI
8
+ extensions and Claude hooks for enhancing the coding agent runtime. Changes here affect the
9
+ behaviour of every agent, skill, and PI extension available in the author's coding sessions.
11
10
 
12
11
  ## Structure
13
12
 
14
13
  ```
15
14
  agent-cortex/
16
- ├── package.json # PI package manifest (pi: { extensions, skills, packages })
17
- ├── plugin.json # GitHub Copilot plugin manifest — agents, skills, MCP servers
15
+ ├── package.json # PI package manifest (pi: { extensions, skills }) + pi runtime deps
18
16
  ├── agents/ # Custom agents — canonical composable <name>/ dirs
19
- │ ├── *.agent.md # generated from <name>/ by scripts/build-copilot-agents.mjs
20
- │ ├── ralph/ # composable format — see agents/README.md
17
+ │ ├── ralph/ # composable format (shared agent.md + pi/, claude/) — see agents/README.md
21
18
  │ ├── plan/ # "
22
19
  │ ├── ralph-plan/ # "
23
20
  │ └── strategy/ # "
@@ -38,13 +35,13 @@ agent-cortex/
38
35
  ├── claude-extras/ # Hand-authored Claude plugin extras
39
36
  │ ├── .mcp.json # MCP servers (context7, github) — copied into installs
40
37
  │ └── scripts/ # statusline-command.sh — copied into installs (executable)
41
- └── package.json # PI package manifest (pi: { extensions, skills, packages })
38
+ └── package.json # PI package manifest (pi: { extensions, skills }) + pi runtime deps
42
39
  ```
43
40
 
44
41
  ## Versioning
45
42
 
46
43
  Use `pnpm changeset` for all version bumps. Never edit versions manually.
47
- `package.json`, `plugin.json`, and `CHANGELOG.md` stay in lockstep automatically.
44
+ `package.json` and `CHANGELOG.md` stay in lockstep automatically.
48
45
  See the `style-versioning` skill for the full workflow.
49
46
 
50
47
  ## Changelog
@@ -53,6 +50,11 @@ Generated automatically by changesets. Do not edit `CHANGELOG.md` manually.
53
50
 
54
51
  ## Coding Conventions
55
52
 
53
+ - **Landing method**: pull requests are squash-merged. Merge commits are disabled in the
54
+ repository settings and `main` requires linear history, so a branch's own commit shape never
55
+ reaches `main` — bring a behind branch up to date by merging `main` in rather than rebasing it.
56
+ `docs/commit-signing.md` records why squash is the only landing path that produces a signed
57
+ commit; the rebase-versus-merge reasoning lives in the `git-workflow` skill.
56
58
  - **Never block the main thread**: no `*Sync` functions (`readFileSync`, `spawnSync`, …).
57
59
  Tooling code in `bin/`, `scripts/`, `lib/`, `hooks/`, and `test/` must be async —
58
60
  enforced by `scripts/check-no-sync.mjs` (runs via `pnpm lint`). Skill-owned
@@ -63,6 +65,12 @@ Generated automatically by changesets. Do not edit `CHANGELOG.md` manually.
63
65
 
64
66
  ## Skill Conventions
65
67
 
68
+ - **Skills are portable, not repo documentation.** `skills/` is installed onto arbitrary machines
69
+ (pi, Claude Code), so it describes general practice and the author's portable
70
+ preferences — never how this repository is configured or how to work in it. Facts about this
71
+ checkout (branch bases, merge method, signature rules, required checks, release mechanics) belong
72
+ in `AGENTS.md`, `docs/`, or the tracker. Repo-local `.agents/skills/` follows the same rule: a
73
+ skill is a skill, not a place for this repo's configuration.
66
74
  - `SKILL.md` must include a YAML front-matter block with `name` and `description`.
67
75
  - `description` must be ≤ 1024 characters. First sentence: what it does. Second: "Use when…".
68
76
  - Keep `SKILL.md` near the ~150-line target in `docs/skills/skill-anatomy.md`, overflowing into
@@ -77,13 +85,10 @@ Generated automatically by changesets. Do not edit `CHANGELOG.md` manually.
77
85
  ## Agent Conventions
78
86
 
79
87
  - Agents live in composable `<name>/` directories under `agents/`: a shared `agent.md` body plus
80
- per-harness subdirectories `pi/`, `copilot/`, `claude/` (frontmatter.json and optional section
81
- files) per the spec in `agents/README.md`. `ralph`, `plan`, `ralph-plan`, and `strategy` all use
82
- the composable layout. The flat `agents/*.agent.md` files are **generated output** — composed
83
- from the canonical directories by the shared `bin/installers/copilot.mjs` code path behind both
84
- `agent-cortex install copilot` and `scripts/build-copilot-agents.mjs` (thin wrapper), and
85
- committed for Copilot CLI (plugin.json `agents: "agents/"` scans for `*.agent.md`); never edit
86
- them by hand. The Claude plugin is materialised by the install-time generator
88
+ per-harness subdirectories `pi/` and `claude/` (frontmatter.json and optional section files) per
89
+ the spec in `agents/README.md`. `ralph`, `plan`, `ralph-plan`, and `strategy` all use the
90
+ composable layout, and no flat agent file is committed — each harness renders its own at install
91
+ time. The Claude plugin is materialised by the install-time generator
87
92
  `bin/installers/claude.mjs`: a plain `agent-cortex install claude` copies it into
88
93
  `~/.agent-cortex/claude` (skills copied flat with `{{TOOL:...}}`/`{{PATH:...}}` substituted,
89
94
  never symlinked), writes the marketplace manifest at
@@ -96,6 +101,16 @@ Generated automatically by changesets. Do not edit `CHANGELOG.md` manually.
96
101
  `--output <dir>` is the generate-only form (tests/CI materialiser checks); `ralph`
97
102
  is authored natively in `agents-native/` and copied verbatim; the other agents compose from their
98
103
  `claude/` harness dirs).
104
+ - The pi package is materialised by `bin/installers/pi.mjs`: `agent-cortex install pi` stages a
105
+ self-contained pi package in `~/.agent-cortex/pi` (manifest, flat rendered agents, token-substituted
106
+ skills, a copy of `extensions/`, `token-map.json`, and the bundled `pi.packages` closure under
107
+ `node_modules/`) and registers that directory with pi through the `pi` CLI — pi's own
108
+ `~/.pi/agent/settings.json` is read, never written. `--output <dir>` stages only (no registration,
109
+ no sweep) and `--dry-run` reports the plan. Once registration succeeds, a one-shot migration sweeps
110
+ the copies the pre-staged-model installer rendered into `~/.pi/agent`, attributing them by name from
111
+ the package root and recording completion in `~/.agent-cortex/legacy-sweep.json`; `~/.pi/agent/extensions`
112
+ is never touched. Run it from the main checkout: the staged package is a snapshot of the checkout you
113
+ invoked, so a run from a ralph worktree stages that worktree's content.
99
114
  - Keep orchestration logic in the agent file; extract shared per-task workflow into a skill
100
115
  so it can be reused (e.g. ralph delegates per-task stage execution to `run-pipeline-stage`).
101
116
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,187 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 847ce42: Remove Copilot CLI as a deploy target. `agent-cortex install copilot` is gone (the
8
+ supported harnesses are now `claude` and `pi`), along with the Copilot plugin manifest
9
+ `plugin.json`, the `build:copilot` script and its committed `agents/*.agent.md` output,
10
+ the `agents/*/copilot/` harness dirs, `scripts/sync-plugin-version.sh`, the `postinstall`
11
+ hook and `scripts/install-instructions.sh` that wrote `~/.copilot/copilot-instructions.md`,
12
+ and the Copilot column of `token-map.json`.
13
+
14
+ `version-packages` is now plain `changeset version`: the release surface is
15
+ `package.json` + `CHANGELOG.md`, since every plugin is materialised at install time with
16
+ the package version. Nothing is swept from an existing `~/.copilot` install — remove
17
+ `~/.copilot/installed-plugins/_direct/agent-cortex` by hand.
18
+
19
+ ## 1.43.0
20
+
21
+ ### Minor Changes
22
+
23
+ - b6fe713: `agent-cortex install pi` now sweeps the artifacts the pre-staged-model
24
+ installer rendered into pi's own user directory. Once the staged package at
25
+ `~/.agent-cortex/pi` is registered, those copies are a second source of the same
26
+ agent or skill — the skill-collision diagnostics the staged model exists to
27
+ remove — so the installer removes the ones it can attribute to agent-cortex:
28
+ `agents/<name>.agent.md` and `skills/<group>/<name>` for agents and skills it
29
+ ships or once shipped (`pipeline-worker`, the `migration` skill), plus a
30
+ `.agent-cortex-install.json` path record left in that directory listing those
31
+ copies.
32
+
33
+ The sweep is a one-time migration, not a standing rule: attribution is by name
34
+ from the package root, which cannot tell a rendered copy from a file you wrote
35
+ under the same name, so a finished migration is recorded in
36
+ `~/.agent-cortex/legacy-sweep.json` — keyed by the pi user directory, never
37
+ inside it — and nothing there is removed again. A completed migration leaves
38
+ `~/.pi/agent` with no agent-cortex file in it. Only a migration that removed
39
+ everything it attributed, from directories it could read, is recorded: a copy
40
+ that could not be deleted, or a directory that could not be listed, is warned
41
+ about and retried on the next install, and a record that cannot be written
42
+ warns without failing an install that has already registered. Files whose name this package
43
+ does not ship are left alone, and pi's
44
+ `extensions/` directory is never touched — no installer has ever written there,
45
+ so its contents are yours. pi's own `settings.json` and `keybindings.json` are
46
+ never touched either.
47
+
48
+ The sweep runs only after registration succeeds, follows the settings file the
49
+ installer reads (`~/.pi/agent`), and is skipped entirely by `--dry-run` and
50
+ `--output <dir>`. A pi agent dir relocated with `PI_CODING_AGENT_DIR` keeps its
51
+ copies: the installer does not inspect it.
52
+
53
+ - b6fe713: `agent-cortex install pi` now registers the staged package with pi: after
54
+ staging `~/.agent-cortex/pi` it drives pi's own `pi install` so pi loads the
55
+ agents, skills, and extensions from that directory. Registration is idempotent
56
+ by state — a re-run after `git pull && agent-cortex install pi` changes nothing —
57
+ and a source pointing at a raw agent-cortex checkout is removed first, so exactly
58
+ one agent-cortex source stays configured. A superseded source that `pi remove`
59
+ cannot drop fails the install rather than reporting success — two configured
60
+ sources both load, so leaving both in place is a failed registration, not a
61
+ warning. The installer still writes nothing into `~/.pi/agent`; it only reads
62
+ pi's `settings.json` to decide the plan. A missing `pi` CLI warns and prints the
63
+ exact commands (failing only with `--require-register`), and `--dry-run` prints
64
+ the registration plan without writing or spawning anything. `--output <dir>`
65
+ remains the stage-only form.
66
+ - b6fe713: `agent-cortex install pi` now stages a self-contained pi package at
67
+ `~/.agent-cortex/pi` (manifest, agents, skills, extensions, and the bundled
68
+ pi-questions / pi-web-access trees) instead of writing into pi's own
69
+ `~/.pi/agent` directories. Register the staged package with `pi install
70
+ ~/.agent-cortex/pi`. `--no-provision` is gone — the required packages travel
71
+ inside the staged tree — and the installer no longer materialises pi's
72
+ `settings.json` / `keybindings.json`.
73
+
74
+ The committed `pi/settings.json` template drops its `npm:pi-questions` and
75
+ `npm:pi-web-access@0.10.7` entries for the same reason: once the staged package
76
+ carries those tools, the `packages` array holds only the optional personal
77
+ toolset (`@getpipher/vision`, `@hypabolic/pi-hypa`, `context-mode`), so there is
78
+ one source of truth for `ask_questions` / `fetch_content` instead of two that can
79
+ drift. Its `../../src/agent-cortex` entry goes too, so the staged package is the
80
+ only agent-cortex source pi loads.
81
+
82
+ The `subagent` extension discovers agents from the package it ships inside as
83
+ well as from pi's own user agent dir, so a staged package supplies the agents it
84
+ ships instead of depending on `~/.pi/agent` copies. A source checkout's
85
+ composable `agents/` tree is left to `agent-modes`, which composes it at runtime;
86
+ the flat renders committed there are for other harnesses and are not read as pi
87
+ agents. Frontmatter `tools` written as a YAML sequence is accepted alongside the
88
+ scalar form.
89
+
90
+ ### Patch Changes
91
+
92
+ - e15cf37: Stop documenting a fixed local-bin `bd` path as the authoritative bd binary. The migration technical-direction doc now describes `bd` as resolved from `PATH` with `BD_PATH` as the override, warns against pinning an orphaned binary (schema-version mismatch risk), and its script-package constraint reflects the post-D2 root workspace membership.
93
+ - 937f610: Document the commit-signing expectation behind the "Commits must have verified signatures"
94
+ merge block. Agent commits are GPG-signed by the environment and verify as `valid`; the
95
+ `github-actions[bot]` commit on a Version Packages PR is `unsigned` because `GITHUB_TOKEN`
96
+ cannot sign. The squash merge GitHub performs re-signs the commit that lands, which is why
97
+ `main`'s history reads `valid` — but a squash merge does **not** escape an enforced signature
98
+ rule, since GitHub checks head-branch commits through its test merge, so the remedy in that
99
+ case is a signed commit rather than a different merge method. The new `docs/commit-signing.md`
100
+ records the evidence, the ruleset reads that show no signature rule applied to `main` at
101
+ either repository or organization level (while org ruleset definitions stay unreadable), the
102
+ open acceptance criterion with its human merge probe, and the release policy: land Version
103
+ Packages by squash merge, never put a signing key in CI secrets, with an explicit
104
+ contingency if an organization-level signature rule turns out to be enforced.
105
+ `style-versioning` points at it.
106
+ - 0f9b7f8: Drop the hardcoded skill blurb from the pi `session-start` extension. The blurb advertised three
107
+ skills with `/skill:<name>` syntax that pi cannot resolve, and pi's own system prompt already lists
108
+ every discovered skill with its absolute `SKILL.md` path, so the local copy was incomplete and
109
+ drifted from `skills/` silently — verbatim text an agent reads first each session (and on
110
+ 2026-10-27 misread a missing-extension outage as a missing-skills problem). Session start now
111
+ injects only the project context files (AGENTS.md, `docs/user-preferences.md`). The extension moves
112
+ to `extensions/session-start/` (`index.ts`, `package.json`, `README.md`, `index.test.ts`) per the
113
+ one-directory-per-extension convention; the new test pins the contract: no `/skill:` syntax, no
114
+ hardcoded skill names, context files injected when present, nothing injected when absent.
115
+ - 6be3679: Stop the Release job re-publishing an already-published version. Every PR now
116
+ has to add a changeset unless it is labelled `no-publish` (the changesets bot's
117
+ Version Packages PR is exempt), and the Release job resolves the merged PR's
118
+ labels for the pushed commit before choosing between `publish-package` and the
119
+ new `publish-noop` script. `README.md` and the `style-versioning` skill document
120
+ the gate, including the out-of-band requirement that the `no-publish` label exists
121
+ in the repository's label settings before the opt-out can work.
122
+ - f86c767: `agent-cortex install pi` no longer registers the git worktree it was invoked from as the pi package source. When the package root is a linked worktree (its `.git` is a file and `git rev-parse --git-common-dir` differs from `--git-dir`), the settings `packages` entry now resolves to the main checkout, with a warning naming the checkout that was registered instead. Previously a run inside `.agent-cortex/worktrees/<id>` left `~/.pi/agent/settings.json` pointing at that gitignored, ephemeral worktree — which dangles as soon as the worktree is removed.
123
+ - 0ad2576: Fix subagents starting with no tools at all. `agent-cortex install pi` rendered
124
+ each generated agent's tool list as one space-separated scalar
125
+ (`tools: "bash read grep find task …"`), but every consumer splits that scalar on
126
+ commas: the subagent extension turned it into `pi --tools "<one bogus name>"`,
127
+ whose allowlist matched no tool, so delegated agents (ralph, pipeline workers)
128
+ ran with only MCP tools and reported the `task` tool — and every other tool — as
129
+ missing. The pi renderer now emits the comma-separated form that
130
+ `parseFrontmatter`, the subagent extension, and `pi --tools` all agree on;
131
+ `parseToolList` in the subagent extension and agent-modes' flat-frontmatter
132
+ parser accept comma- and whitespace-separated lists so a re-render cannot
133
+ silently zero out a tool list again; and a round-trip test asserts a rendered
134
+ agent's tools survive the parse.
135
+ - 65cb7f8: The `git-workflow` skill now says how to bring a behind branch up to date, and
136
+ why the answer is usually "merge the base in" rather than "rebase". `git rebase`
137
+ drops merge commits and the patches they carry, so rebasing a branch that has
138
+ already merged the base silently reverts what that merge resolved — the conflict
139
+ resolutions, and any fix from the base the merge brought in — and the result
140
+ reads like a regression in the branch's own change. `--rebase-merges` keeps the
141
+ structure but re-opens the same conflicts, so it earns its cost only when the
142
+ branch history is the deliverable. Rebasing stays right for a linear branch that
143
+ has not been reviewed yet, and then it needs `--force-with-lease`.
144
+
145
+ The choice follows from the repository's landing method, not from taste: a squash
146
+ merge collapses the branch, so its shape never reaches the base branch, while a
147
+ rebase-and-merge requires linear history and therefore a rebase before the first
148
+ review rather than after a merge. `AGENTS.md` now records this repository's
149
+ answer — squash merge, merge commits disabled, `main` requires linear history —
150
+ because that is a fact about this checkout, not portable practice.
151
+
152
+ - 2ae24da: Document what `disable-model-invocation` actually does and how each harness handles it: preserved and honoured by pi and Claude Code, honoured by Copilot CLI but at the cost of model-mediated invocation. Corrects the front-matter guidance in `docs/skills/skill-anatomy.md`, which described the field as affecting how the body is interpreted.
153
+ - 5da1d45: Make pipeline-stage workers prove they delivered, and stop dispatch from being
154
+ improvised.
155
+
156
+ A stage worker's `---REPORT---` was taken at face value: nothing instructed it to
157
+ commit or push, and nothing checked the worktree afterwards. A worker could
158
+ report `OUTCOME: SUCCESS` and leave its changes uncommitted, and ralph would
159
+ advance the parent and open the feature PR from a branch holding none of the
160
+ work. Six runs needed a human to finish the tree by hand.
161
+
162
+ - The stage contract now requires delivery: the stage-runner prompt and the
163
+ code, fix, and document playbooks commit and push before reporting, and the
164
+ REPORT gained `COMMIT`, `PUSHED`, and `PR` fields.
165
+ - `scripts/lib/verify-worker-tree.mjs` checks the worktree itself — clean tree,
166
+ at least one commit ahead of the recorded base — so ralph gates each stage on
167
+ evidence rather than on the worker's prose.
168
+ - ralph stops and reports a missing subagent tool instead of backgrounding
169
+ `pi -p … &`. That substitution has no completion signal, so a finished worker
170
+ and a killed one look identical — the trap that produced the buffered-log and
171
+ post-exit liveness misreadings.
172
+ - `token-map.json` records that pi's `task`/`read_agent`/`wait_for_agents` come
173
+ from this repo's `extensions/subagent`, not from pi.
174
+
175
+ - 931a20e: Document the one manual step in the release loop: the Version Packages PR arrives
176
+ `BLOCKED` with an empty check list because `changesets/action` pushes that branch
177
+ with `GITHUB_TOKEN`, so GitHub parks the CI run the push creates behind "Approve
178
+ workflows to run" and a parked run reports nothing. Approve it — merge box click,
179
+ or the documented `gh api … /approve` one-liner — and the five required checks
180
+ start. The approval is per head commit, so it is needed again after any further
181
+ merge to `main`, which force-updates the version branch. Adding a PAT or GitHub App
182
+ token would let the bot trigger its own CI, but one click per release is a better
183
+ trade than a long-lived credential in repository secrets.
184
+
3
185
  ## 1.42.0
4
186
 
5
187
  ### Minor Changes