@jaybeeuu/agent-cortex 1.43.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.
- package/.agents/skills/style-versioning/SKILL.md +5 -6
- package/.github/workflows/ci.yml +4 -11
- package/AGENTS.md +10 -16
- package/CHANGELOG.md +16 -0
- package/README.md +44 -55
- package/agents/README.md +9 -23
- package/agents/ralph/agent.md +7 -10
- package/agents/ralph/claude/polling.md +1 -1
- package/bin/agent-cortex.mjs +0 -16
- package/bin/installers/claude.mjs +2 -2
- package/docs/research/disable-model-invocation.md +5 -26
- package/docs/skills/skill-anatomy.md +2 -3
- package/docs/technical-direction/harness-config.md +6 -14
- package/docs/user-preferences.md +2 -2
- package/extensions/agent-modes/README.md +3 -3
- package/extensions/agent-modes/discover.ts +6 -6
- package/extensions/subagent/README.md +2 -2
- package/extensions/subagent/agents.ts +1 -2
- package/lib/cli.mjs +5 -7
- package/package.json +3 -5
- package/scripts/lib/compose-agent.mjs +10 -10
- package/skills/workflow/ralph/REFERENCE.md +3 -3
- package/skills/workflow/ralph/SKILL.md +5 -5
- package/test/cli.test.mjs +11 -10
- package/token-map.README.md +9 -12
- package/token-map.json +26 -31
- package/agents/plan/copilot/frontmatter.json +0 -6
- package/agents/plan.agent.md +0 -59
- package/agents/ralph/copilot/frontmatter.json +0 -6
- package/agents/ralph/copilot/polling.md +0 -62
- package/agents/ralph-plan/copilot/frontmatter.json +0 -6
- package/agents/ralph-plan.agent.md +0 -126
- package/agents/ralph.agent.md +0 -331
- package/agents/strategy/copilot/frontmatter.json +0 -6
- package/agents/strategy.agent.md +0 -112
- package/bin/installers/copilot.mjs +0 -124
- package/hooks.json +0 -10
- package/plugin.json +0 -35
- package/scripts/build-copilot-agents.mjs +0 -30
- package/scripts/install-instructions.sh +0 -82
- package/scripts/sync-plugin-version.sh +0 -17
- package/test/copilot-installer.test.mjs +0 -308
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
Decision record for the frontmatter field this repo uses to keep rare or destructive
|
|
4
4
|
skills out of automatic model routing (bead `agnt-ctx-yf24`).
|
|
5
5
|
|
|
6
|
-
**Verdict:** rely on it for pi and Claude Code.
|
|
7
|
-
"invoke-only" — there it means "unreachable through the model-facing skill tool".
|
|
6
|
+
**Verdict:** rely on it for pi and Claude Code.
|
|
8
7
|
|
|
9
8
|
## What the field does
|
|
10
9
|
|
|
@@ -19,11 +18,10 @@ previously implied.
|
|
|
19
18
|
| --- | --- | --- | --- |
|
|
20
19
|
| pi 1.4.0 | Yes — byte-identical copy | Yes — hidden from the prompt, `/skill:name` still works | `bin/installers/pi.mjs:182-204`, `scripts/lib/compose-agent.mjs:69-95`; `dist/core/skills.js:262` (parse) and `:279` (filter); `docs/skills.md:53` |
|
|
21
20
|
| Claude Code 2.1.294 | Yes — byte-identical copy | Yes — Claude cannot invoke it, `/skill-name` still works | `bin/installers/claude.mjs:160-201`, same token helper; [Claude Code skills docs](https://code.claude.com/docs/en/skills) ("Control who invokes a skill") |
|
|
22
|
-
| Copilot CLI (1.0.55 locally, 1.0.80/1.0.83 upstream) | N/A — no copy; `plugin.json` `"skills": "skills/"` serves the repo tree in place | Auto-invocation suppressed, but explicit model invocation fails; `/skill-name` works | `plugin.json:12`; [github/copilot-cli#4438](https://github.com/github/copilot-cli/issues/4438) (open, retested 1.0.83) |
|
|
23
21
|
|
|
24
22
|
Both materialisers copy `SKILL.md` as text and rewrite only `{{TOOL:...}}` /
|
|
25
23
|
`{{PATH:...}}` tokens, so frontmatter keys they do not know pass through untouched —
|
|
26
|
-
nothing re-serialises YAML. Verified by installing
|
|
24
|
+
nothing re-serialises YAML. Verified by installing both harnesses into
|
|
27
25
|
`/var/tmp/dmi-check` and diffing `skills/productivity/teach/SKILL.md` (the repo's
|
|
28
26
|
only current user of the field): both copies are byte-identical to the source.
|
|
29
27
|
`claude plugin validate /var/tmp/dmi-check/claude/skills` passes, i.e. Claude Code's
|
|
@@ -58,46 +56,27 @@ Two Claude-specific caveats:
|
|
|
58
56
|
frontmatter field itself still applies there — only that settings-based alternative
|
|
59
57
|
is unavailable.
|
|
60
58
|
|
|
61
|
-
**Copilot CLI.** The field is not in GitHub's skill documentation, which lists only
|
|
62
|
-
`name`, `description`, `license`, and `allowed-tools`. In practice the CLI filters
|
|
63
|
-
flagged skills out of the `skill()` tool's resolution list, so the model cannot call
|
|
64
|
-
them even when the user names one: `Skill not found`. Only the interactive
|
|
65
|
-
`/skill-name` slash command reaches a flagged skill, and `-p` mode has no slash path.
|
|
66
|
-
Upstream issue #4438 is open.
|
|
67
|
-
|
|
68
|
-
Local probing was not possible: the installed CLI is 1.0.55 (no `copilot skill`
|
|
69
|
-
subcommand), and prompt runs are refused by this machine's org policy. The upstream
|
|
70
|
-
report is the evidence for Copilot, tested on 1.0.80 and 1.0.83 — newer than 1.0.55,
|
|
71
|
-
so this may differ locally, in either direction.
|
|
72
|
-
|
|
73
59
|
## Options for "explicit invocation only", evaluated
|
|
74
60
|
|
|
75
61
|
| Option | Portable? | Enforced? | Verdict |
|
|
76
62
|
| --- | --- | --- | --- |
|
|
77
|
-
| `disable-model-invocation: true` | pi + Claude Code yes
|
|
63
|
+
| `disable-model-invocation: true` | pi + Claude Code yes | Yes | **Recommended** where suppressing auto-routing is the point and the explicit path is a human typing `/name` |
|
|
78
64
|
| Naming convention (e.g. `manual-*`) | Yes | No — no harness reads names | Rejected: a human signal we already get from the body |
|
|
79
|
-
| `metadata:` block | Yes (spec-legal) | No — pi and Claude read top-level keys only
|
|
65
|
+
| `metadata:` block | Yes (spec-legal) | No — pi and Claude read top-level keys only | Rejected: documentation that looks like enforcement |
|
|
80
66
|
| Keep such skills out of `skills/` | Yes | Yes, by not shipping the skill | Rejected: gives up the per-harness install entirely |
|
|
81
67
|
|
|
82
68
|
## Recommendation
|
|
83
69
|
|
|
84
70
|
Use the field when the danger is fuzzy automatic matching and the intended explicit
|
|
85
71
|
path is a human typing `/skill-name`: that is the case for a migration skill whose
|
|
86
|
-
`--apply` renames labels workspace-wide.
|
|
87
|
-
also blocks model-mediated invocation, including `-p` runs — if a workflow needs
|
|
88
|
-
non-interactive access to such a skill, do not set the field and instead disable the
|
|
89
|
-
skill in that user's Copilot config (`copilot skill disable <name>`, or the `/skills`
|
|
90
|
-
toggle), which is harness-native and per-user.
|
|
72
|
+
`--apply` renames labels workspace-wide.
|
|
91
73
|
|
|
92
74
|
## Reproducing
|
|
93
75
|
|
|
94
76
|
```sh
|
|
95
77
|
node bin/agent-cortex.mjs install claude --output /var/tmp/dmi-check/claude
|
|
96
78
|
node bin/agent-cortex.mjs install pi --output /var/tmp/dmi-check/pi
|
|
97
|
-
node bin/agent-cortex.mjs install copilot --output /var/tmp/dmi-check/copilot
|
|
98
79
|
diff skills/productivity/teach/SKILL.md /var/tmp/dmi-check/claude/skills/teach/SKILL.md
|
|
99
80
|
diff skills/productivity/teach/SKILL.md /var/tmp/dmi-check/pi/skills/productivity/teach/SKILL.md
|
|
100
81
|
claude plugin validate /var/tmp/dmi-check/claude/skills
|
|
101
82
|
```
|
|
102
|
-
|
|
103
|
-
The Copilot run writes only composed agent files — there is no skill copy to inspect.
|
|
@@ -14,8 +14,7 @@ Optional fields:
|
|
|
14
14
|
- `disable-model-invocation`: hides the skill from automatic model routing; explicit
|
|
15
15
|
`/skill-name` invocation still works. Set it when the danger is a fuzzy description
|
|
16
16
|
match, e.g. a skill whose steps are destructive. Preserved and honoured by pi and
|
|
17
|
-
Claude Code
|
|
18
|
-
through its model-facing tool. See `docs/research/disable-model-invocation.md`.
|
|
17
|
+
Claude Code. See `docs/research/disable-model-invocation.md`.
|
|
19
18
|
|
|
20
19
|
## Description format rules
|
|
21
20
|
|
|
@@ -35,7 +34,7 @@ Optional fields:
|
|
|
35
34
|
|
|
36
35
|
## Tool references
|
|
37
36
|
|
|
38
|
-
Reference agent tools by `{{TOOL:name}}` token (canonical
|
|
37
|
+
Reference agent tools by `{{TOOL:name}}` token (canonical authoring name), never a
|
|
39
38
|
hardcoded harness-specific name such as `bash`, `task`, or `read_agent` — installers
|
|
40
39
|
substitute the per-harness name from `token-map.json` at install time. Add any new tool
|
|
41
40
|
to the map's `tools` section in the same change; unknown tokens are hard errors. See
|
|
@@ -20,13 +20,14 @@ below no longer hold:
|
|
|
20
20
|
that both load.
|
|
21
21
|
|
|
22
22
|
`pi.packages` and `lib/pi-packages.mjs` are deleted, so the bespoke-pi-mechanism problem this
|
|
23
|
-
memo was written to settle is closed. The Claude
|
|
23
|
+
memo was written to settle is closed. The Claude analysis stands; Copilot CLI is no longer a
|
|
24
|
+
deploy target (`agnt-ctx-2rl`).
|
|
24
25
|
|
|
25
26
|
## Problem and target outcome
|
|
26
27
|
|
|
27
|
-
- **What we are solving.** agent-cortex ships agents and skills to
|
|
28
|
-
Code
|
|
29
|
-
|
|
28
|
+
- **What we are solving.** agent-cortex ships agents and skills to two harnesses (pi, Claude
|
|
29
|
+
Code) and needs a declared, reproducible set of *third-party* extensions those agents depend
|
|
30
|
+
on (pi packages / Claude plugins). Two bespoke mechanisms currently exist and
|
|
30
31
|
disagree: `main` declares packages in `package.json` → `pi.packages` and provisions them from
|
|
31
32
|
`lib/pi-packages.mjs`; the unmerged pi-harness epic (`agnt-ctx-dfq3`) declares them in
|
|
32
33
|
`pi.extensions.json` / `claude.extensions.json` and provisions them via `agent-cortex ext
|
|
@@ -51,9 +52,6 @@ memo was written to settle is closed. The Claude and Copilot analysis stands.
|
|
|
51
52
|
- **Claude is idiomatic two ways.** Machine state is `~/.claude/settings.json` → `enabledPlugins`
|
|
52
53
|
+ `extraKnownMarketplaces`. A plugin declares other plugins in `.claude-plugin/plugin.json` →
|
|
53
54
|
`dependencies`, which Claude Code resolves and auto-installs.
|
|
54
|
-
- **Copilot has no dependency mechanism.** `copilot plugin install/list/uninstall` exists, but its
|
|
55
|
-
state is auto-managed `~/.copilot/config.json` (not committable) and `plugin.json` declares no
|
|
56
|
-
dependencies.
|
|
57
55
|
- **The epic already built two-thirds of the target.** Unmerged commit `afab2c6` (F3) materialises
|
|
58
56
|
`pi/settings.json` + `pi/keybindings.json` from committed templates with merge-keep-personal and
|
|
59
57
|
the CLI owning `packages`; `1ff212d` (F4) makes bundled pi extensions load via package
|
|
@@ -86,7 +84,7 @@ memo was written to settle is closed. The Claude and Copilot analysis stands.
|
|
|
86
84
|
--json` are the exact machine-state comparison; drift self-heals on install.
|
|
87
85
|
- **Cons.** pi bundling shifts update cadence to agent-cortex releases and grows the tarball;
|
|
88
86
|
Claude cross-marketplace deps need an allowlist; the committed template also carries personal
|
|
89
|
-
settings
|
|
87
|
+
settings.
|
|
90
88
|
- **Risks.** Loading TS extensions from bundled `node_modules/`; maintaining the Claude
|
|
91
89
|
cross-marketplace allowlist.
|
|
92
90
|
|
|
@@ -128,8 +126,6 @@ the epic, and delete `pi.packages` + `lib/pi-packages.mjs` from `main`.
|
|
|
128
126
|
- **Committed personal settings.** `pi/settings.json` already carries models/theme; the template
|
|
129
127
|
model makes the repo own the whole pi settings surface. Accepted; F3's merge preserves personal
|
|
130
128
|
keys and only `packages` is CLI-owned.
|
|
131
|
-
- **Copilot gets no mechanism.** Documented exception — the README says `copilot plugin install`.
|
|
132
|
-
Accepted because Copilot has no dependency field and no committable config.
|
|
133
129
|
- **No dedicated diff command.** A read-only `status` is deferred until drift is shown to hurt.
|
|
134
130
|
|
|
135
131
|
## Validation plan
|
|
@@ -160,8 +156,6 @@ pi extension loads from `node_modules/` and an optional one is materialised from
|
|
|
160
156
|
speculative and should be dropped rather than maintained.
|
|
161
157
|
- Bundling `pi-web-access`'s native-ish dependency tree (unpdf, linkedom) proves brittle or
|
|
162
158
|
unacceptable on a fresh machine.
|
|
163
|
-
- Copilot gains a committable config or a plugin dependency field — revisit the documented
|
|
164
|
-
exception.
|
|
165
159
|
- Drift between the committed template and the machine becomes a recurring annoyance — add the
|
|
166
160
|
deferred read-only `status`.
|
|
167
161
|
|
|
@@ -175,8 +169,6 @@ pi extension loads from `node_modules/` and an optional one is materialised from
|
|
|
175
169
|
(auto-install, cross-marketplace allowlist, tag naming).
|
|
176
170
|
- Claude Code, *Settings* — https://code.claude.com/docs/en/settings (`enabledPlugins`,
|
|
177
171
|
`extraKnownMarketplaces`).
|
|
178
|
-
- GitHub Copilot CLI, *Plugin reference* — https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-plugin-reference
|
|
179
|
-
and *Configuration directory* — https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-config-dir-reference
|
|
180
172
|
- Code evidence (as of 2026-09 — `pi.packages` and `lib/pi-packages.mjs` were removed in
|
|
181
173
|
`agnt-ctx-7kru.1`, see Status): `package.json` (`pi.packages`), `lib/pi-packages.mjs` (main's
|
|
182
174
|
provisioner);
|
package/docs/user-preferences.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# User Preferences
|
|
2
2
|
|
|
3
3
|
This file records personal development preferences for the author (**jaybeeuu**).
|
|
4
|
-
Both
|
|
5
|
-
|
|
4
|
+
Both pi and Claude Code agents should read this file for user-level context when
|
|
5
|
+
making tooling and workflow decisions.
|
|
6
6
|
|
|
7
7
|
## Package manager
|
|
8
8
|
|
|
@@ -39,9 +39,9 @@ contract:
|
|
|
39
39
|
from the tool set with a warning.
|
|
40
40
|
|
|
41
41
|
Flat `agents/*.agent.md` files are parsed as a fallback when an agent has no
|
|
42
|
-
composable directory —
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
composable directory — a staged pi package carries flat renders, and a hand-written
|
|
43
|
+
agent may be a single flat file. A composable directory always wins over its flat
|
|
44
|
+
counterpart for the same agent id.
|
|
45
45
|
|
|
46
46
|
## Development
|
|
47
47
|
|
|
@@ -18,9 +18,9 @@ import type { ThemeColor } from "@earendil-works/pi-coding-agent";
|
|
|
18
18
|
* and symlinked installs).
|
|
19
19
|
*
|
|
20
20
|
* Flat `agents/*.agent.md` files are parsed as a fallback for agents that have
|
|
21
|
-
* no composable directory (
|
|
22
|
-
*
|
|
23
|
-
* counterpart.
|
|
21
|
+
* no composable directory (a staged pi package ships flat renders, and a
|
|
22
|
+
* hand-written agent may be a single flat file). A composable directory always
|
|
23
|
+
* wins over its flat counterpart.
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
26
|
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
@@ -40,7 +40,7 @@ export interface AgentDef {
|
|
|
40
40
|
prompt: string;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
export type HarnessId = "
|
|
43
|
+
export type HarnessId = "claude" | "pi";
|
|
44
44
|
|
|
45
45
|
export interface PathSpec {
|
|
46
46
|
base: string;
|
|
@@ -431,8 +431,8 @@ function readFlatAgent(filePath: string, tokenMap: TokenMap | null): AgentDef |
|
|
|
431
431
|
* Discover agents from the agents directory.
|
|
432
432
|
*
|
|
433
433
|
* Composable directories (`<name>/agent.md` + `<name>/pi/frontmatter.json`) are
|
|
434
|
-
* the primary source. Flat `*.agent.md` files (
|
|
435
|
-
* read only when no composable directory exists for that agent id. When
|
|
434
|
+
* the primary source. Flat `*.agent.md` files (a staged package's renders, or a
|
|
435
|
+
* hand-written agent) are read only when no composable directory exists for that agent id. When
|
|
436
436
|
* `tokenMap` is omitted, token-map.json is loaded from the package root;
|
|
437
437
|
* missing/unreadable maps fall back to the built-in copilot→pi translation.
|
|
438
438
|
*/
|
|
@@ -111,8 +111,8 @@ fire-and-forget orchestration:
|
|
|
111
111
|
- **`read_agent`** — fallback: read one specific agent's output once you know it has
|
|
112
112
|
finished (or query its `STILL RUNNING` state directly).
|
|
113
113
|
|
|
114
|
-
These mirror
|
|
115
|
-
blocking wait that
|
|
114
|
+
These mirror the `task`/`read_agent` model the skills are authored against;
|
|
115
|
+
`wait_for_agents` adds the blocking wait that a `read_agent` poll loop does manually. Abort (Ctrl+C) propagates: a
|
|
116
116
|
pending `wait_for_agents` returns immediately with whatever is known so far.
|
|
117
117
|
|
|
118
118
|
## Output Display
|
|
@@ -155,8 +155,7 @@ function isRenderedAgentsTree(agentsDir: string): boolean {
|
|
|
155
155
|
* renders the flat pi agents into `<package>/agents`.
|
|
156
156
|
*
|
|
157
157
|
* A source checkout contributes nothing: its `agents/` tree is the composable
|
|
158
|
-
* source
|
|
159
|
-
* renders for other harnesses — Copilot's, whose tool names pi does not have.
|
|
158
|
+
* source, composed at runtime by the agent-modes extension.
|
|
160
159
|
*/
|
|
161
160
|
export function resolveUserAgentDirs(packageRoot: string = PACKAGE_ROOT): string[] {
|
|
162
161
|
const dirs: string[] = [];
|
package/lib/cli.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const SUPPORTED_HARNESSES = ["
|
|
1
|
+
const SUPPORTED_HARNESSES = ["claude", "pi"];
|
|
2
2
|
|
|
3
3
|
// Options accepted by `install <harness>`. `--output`/`--dry-run` are shared by
|
|
4
4
|
// the claude and pi installers; `--plugin-root` is pi-specific. Unknown or
|
|
@@ -87,11 +87,6 @@ Commands:
|
|
|
87
87
|
registration cannot run (missing CLI,
|
|
88
88
|
pre-v2 build); default warns and prints
|
|
89
89
|
the manual registration commands
|
|
90
|
-
Options (copilot):
|
|
91
|
-
--output <dir> Write the flat *.agent.md files to <dir>
|
|
92
|
-
(default: <package root>/agents — the dir
|
|
93
|
-
plugin.json "agents" scans)
|
|
94
|
-
--dry-run Print what would be generated without writing
|
|
95
90
|
Options (pi):
|
|
96
91
|
(no --output) Materialise the pi package into
|
|
97
92
|
~/.agent-cortex/pi: package.json,
|
|
@@ -135,7 +130,10 @@ Commands:
|
|
|
135
130
|
|
|
136
131
|
export function validateHarness(harness) {
|
|
137
132
|
if (harness === null) {
|
|
138
|
-
return {
|
|
133
|
+
return {
|
|
134
|
+
ok: false,
|
|
135
|
+
error: `Missing harness argument. Supported harnesses: ${SUPPORTED_HARNESSES.join(", ")}`,
|
|
136
|
+
};
|
|
139
137
|
}
|
|
140
138
|
if (!SUPPORTED_HARNESSES.includes(harness)) {
|
|
141
139
|
return { ok: false, error: `Unknown harness "${harness}". Supported harnesses: ${SUPPORTED_HARNESSES.join(", ")}` };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jaybeeuu/agent-cortex",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Personal PI package with custom agents, skills, and extensions",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package"
|
|
@@ -39,12 +39,10 @@
|
|
|
39
39
|
"check:sync": "node scripts/check-no-sync.mjs",
|
|
40
40
|
"test": "node --test test/*.test.mjs && pnpm -r test",
|
|
41
41
|
"typecheck": "pnpm -r typecheck",
|
|
42
|
-
"build:copilot": "node scripts/build-copilot-agents.mjs",
|
|
43
42
|
"changeset": "changeset",
|
|
44
|
-
"version-packages": "changeset version
|
|
43
|
+
"version-packages": "changeset version",
|
|
45
44
|
"publish-package": "TARBALL=$(pnpm pack | tail -n 1) && npm publish \"$TARBALL\" --provenance --access public",
|
|
46
45
|
"publish-noop": "echo 'No publish: the merged PR carries the no-publish label.'",
|
|
47
|
-
"release": "changeset publish"
|
|
48
|
-
"postinstall": "bash scripts/install-instructions.sh"
|
|
46
|
+
"release": "changeset publish"
|
|
49
47
|
}
|
|
50
48
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Shared composer: reads a composable agent directory (agents/<name>/) and emits
|
|
2
|
-
// the harness-specific agent content defined by agents/README.md. The
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
2
|
+
// the harness-specific agent content defined by agents/README.md. The Claude and pi
|
|
3
|
+
// install-time generators (bin/installers/claude.mjs, bin/installers/pi.mjs) compose
|
|
4
|
+
// from here, so the composable dirs are the single source of truth and the generated
|
|
5
|
+
// files stay in lockstep.
|
|
6
6
|
//
|
|
7
7
|
// Composition per the agents/README.md contract:
|
|
8
8
|
// 1. {{SECTION:name}} is replaced with <dir>/<harness>/<name>.md content.
|
|
@@ -15,15 +15,15 @@
|
|
|
15
15
|
// silently dropped section.
|
|
16
16
|
//
|
|
17
17
|
// Options (the pi installer passes `dropNullTools`, `pluginRoot` and
|
|
18
|
-
// `resolveRelativePaths`; the
|
|
18
|
+
// `resolveRelativePaths`; the claude installer uses the strict defaults):
|
|
19
19
|
// dropNullTools replace null-mapped tool tokens with an empty string and
|
|
20
20
|
// warn instead of throwing (pi's prose rule per the
|
|
21
21
|
// token-map contract)
|
|
22
22
|
// pluginRoot override the plugin_root used for resolved paths
|
|
23
23
|
// (installers compute it from the actual install layout)
|
|
24
24
|
// resolveRelativePaths non-keyed {{PATH:...}} args resolve to pluginRoot/arg
|
|
25
|
-
// instead of staying verbatim (install time;
|
|
26
|
-
//
|
|
25
|
+
// instead of staying verbatim (install time; without it
|
|
26
|
+
// they stay bare for runtime resolution)
|
|
27
27
|
// warn callback for drop/omit warnings (default: no-op; the
|
|
28
28
|
// pi installer collects them into its result)
|
|
29
29
|
//
|
|
@@ -61,7 +61,7 @@ function noop() {}
|
|
|
61
61
|
* the harness's section files before calling this.
|
|
62
62
|
*
|
|
63
63
|
* @param {string} content Source text containing {{TOOL:...}}/{{PATH:...}} tokens
|
|
64
|
-
* @param {string} harness Harness id: "
|
|
64
|
+
* @param {string} harness Harness id: "claude" | "pi"
|
|
65
65
|
* @param {object} tokenMap Parsed token-map.json (from loadTokenMap)
|
|
66
66
|
* @param {object} options { dropNullTools, pluginRoot, resolveRelativePaths, warn, context }
|
|
67
67
|
* @returns {string}
|
|
@@ -99,7 +99,7 @@ export function substituteTokens(content, harness, tokenMap, options = {}) {
|
|
|
99
99
|
*
|
|
100
100
|
* @param {string} root Package root (contains agents/ and token-map.json)
|
|
101
101
|
* @param {string} name Agent directory name (e.g. "ralph", "plan")
|
|
102
|
-
* @param {string} harness Harness id: "
|
|
102
|
+
* @param {string} harness Harness id: "claude" | "pi"
|
|
103
103
|
* @returns {{ name: string, description: string, tools: string[], model?: string, argumentHint?: string, body: string }}
|
|
104
104
|
*/
|
|
105
105
|
export async function composeAgent(root, name, harness, options = {}) {
|
|
@@ -218,7 +218,7 @@ function resolvePath(arg, harness, tokenMap, opts = {}) {
|
|
|
218
218
|
*
|
|
219
219
|
* @param {string[]} tools Canonical tool names from a harness frontmatter.json
|
|
220
220
|
* @param {object} tokenMap Parsed token-map.json (from loadTokenMap)
|
|
221
|
-
* @param {string} harness Harness id: "
|
|
221
|
+
* @param {string} harness Harness id: "claude" | "pi"
|
|
222
222
|
* @param {object} options { warn }
|
|
223
223
|
* @returns {string[]}
|
|
224
224
|
*/
|
|
@@ -116,7 +116,7 @@ When a verify or review stage fails:
|
|
|
116
116
|
|
|
117
117
|
## Log Polling
|
|
118
118
|
|
|
119
|
-
Run whenever
|
|
119
|
+
Run whenever completion handling is triggered (an agent completion):
|
|
120
120
|
|
|
121
121
|
1. **Query in-flight beads**: `bd list --status=in_progress --type=chore`. Extract each bead's ID and title.
|
|
122
122
|
2. For each in-flight bead, read new lines from its **parent's** log file — logs are keyed by **parent** bead ID, so all stages of a feature share one file. Track the next unread line number per parent in memory, starting at 1:
|
|
@@ -167,7 +167,7 @@ Proceed here when no chore beads are in-flight, no `stage:*` chore beads are rea
|
|
|
167
167
|
|
|
168
168
|
When you've completed the above, prompt me to continue.
|
|
169
169
|
```
|
|
170
|
-
6. **Stop completely.** Do not
|
|
170
|
+
6. **Stop completely.** Do not continue the event loop. Wait for the user to re-prompt before doing any further work.
|
|
171
171
|
|
|
172
172
|
---
|
|
173
173
|
|
|
@@ -209,7 +209,7 @@ When `bd list --status=in_progress --type=chore` returns no results AND `bd read
|
|
|
209
209
|
| File | Purpose |
|
|
210
210
|
|------|---------|
|
|
211
211
|
| `.agent-cortex/ralph/progress.md` | Human-readable snapshot. Regenerate: `workspace="/abs/path"; pnpm --prefix skills/workflow/run-pipeline-stage/scripts exec tsx generate-progress.ts --workspace "$workspace" > "$workspace/.agent-cortex/ralph/progress.md"`. `workspace` must be an **absolute** path — never `.` or `$(pwd)`. **Never hand-edit.** |
|
|
212
|
-
| `.agent-cortex/ralph/state.json` | Runtime bookkeeping only: the
|
|
212
|
+
| `.agent-cortex/ralph/state.json` | Runtime bookkeeping only: the in-flight agent-ID→bead mapping. Shape: `{ "inflight": [ { "choreId": "...", "parentId": "...", "title": "...", "agentId": "...", "logLine": 1 } ] }`. Initialise at startup with `{ "inflight": [] }`. Update after every dispatch and every agent completion. **Never hand-edit.** |
|
|
213
213
|
| `.agent-cortex/ralph/ralph-*.log` | Per-parent log files written by subagents — every stage chore of a feature appends to `.agent-cortex/ralph/ralph-<parent-id>.log` (e.g. `ralph-abc-123.log`). |
|
|
214
214
|
|
|
215
215
|
All task state is derived from beads; `state.json` holds only runtime bookkeeping:
|
|
@@ -7,7 +7,7 @@ description: "Run all pending beads end-to-end with up to 5 concurrent pipeline-
|
|
|
7
7
|
|
|
8
8
|
Ralph is a parallel orchestration loop. It advances AFK task beads through pipeline-stage chores (`code` → `verify` → `review` → `document`), dispatching each stage as a background subagent in the feature's worktree, then opens review-gated feature and epic PRs and pauses for human merges. Ralph never writes code itself — it dispatches, tracks, and reports.
|
|
9
9
|
|
|
10
|
-
State model: task state lives in beads (ready/in_progress via `bd`); the only local file is `.agent-cortex/ralph/state.json`, holding the
|
|
10
|
+
State model: task state lives in beads (ready/in_progress via `bd`); the only local file is `.agent-cortex/ralph/state.json`, holding the agent-ID→bead mapping. Pipeline configuration comes from `skills/planning/create-task/pipeline.json`, and stage execution belongs to the `run-pipeline-stage` skill.
|
|
11
11
|
|
|
12
12
|
## When to use
|
|
13
13
|
|
|
@@ -28,14 +28,14 @@ State model: task state lives in beads (ready/in_progress via `bd`); the only lo
|
|
|
28
28
|
1. Run `bd prime` and hold the output verbatim in memory.
|
|
29
29
|
2. Ensure `.agent-cortex/` and `.agent-cortex/worktrees/` are in the project's `.gitignore` (append any that are missing).
|
|
30
30
|
3. Create the workspace: `mkdir -p .agent-cortex/ralph`.
|
|
31
|
-
4. Initialize state: write `.agent-cortex/ralph/state.json` with `{ "
|
|
31
|
+
4. Initialize state: write `.agent-cortex/ralph/state.json` with `{ "inflight": [] }`.
|
|
32
32
|
5. Read `skills/planning/create-task/pipeline.json` and hold it in memory — you need its `maxFixRounds` for the fix loop.
|
|
33
33
|
6. Run `bd ready` and classify each available bead:
|
|
34
34
|
- **Chore with a `stage:*` label**: pipeline stage bead — eligible for dispatch.
|
|
35
35
|
- **Task or other type without an `implementation-type:*` label**: unexpected here — classification happens at planning time via `create-task`. Do not invoke `classify-bead`; treat as needs-refinement and note it for the shutdown summary.
|
|
36
36
|
- **Task labelled `implementation-type:hitl`**: skip — record the ID for the Pending Human Action summary at shutdown.
|
|
37
37
|
7. For each ready chore bead (up to 5), dispatch it from its parent's feature worktree (see _Dispatching a chore bead_ in REFERENCE.md — create branches/worktrees first).
|
|
38
|
-
8. Hand over to your harness's completion-detection mechanism:
|
|
38
|
+
8. Hand over to your harness's completion-detection mechanism: PI keeps a {{TOOL:wait_for_agents}} call outstanding over every in-flight agent ID. If no chore was dispatched and HITL gate beads are pending (`bd list -l lifecycle:feature-pr -l implementation-type:hitl` or `bd list -l awaiting-epic-pr-merge`), go straight to HITL Pause (REFERENCE.md).
|
|
39
39
|
9. Regenerate `.agent-cortex/ralph/progress.md`:
|
|
40
40
|
```bash
|
|
41
41
|
# workspace must be the absolute path you cd'd into — never . or $(pwd)
|
|
@@ -45,7 +45,7 @@ State model: task state lives in beads (ready/in_progress via `bd`); the only lo
|
|
|
45
45
|
|
|
46
46
|
### 2. Event loop
|
|
47
47
|
|
|
48
|
-
On each completion notification (background agent finished
|
|
48
|
+
On each completion notification (a background agent finished):
|
|
49
49
|
|
|
50
50
|
1. Poll that parent's log for new lines — `tail -n +<nextLine> .agent-cortex/ralph/ralph-<parent-id>.log` (logs are keyed by parent bead ID, so every stage of a feature shares one file) — and post only new key events (stage transitions, test/lint results), never empty updates.
|
|
51
51
|
2. Read the completed agent's output with {{TOOL:read_agent}} and parse its `---REPORT---` block for `BEAD_ID`, `STAGE_COMPLETED`, and the outcome.
|
|
@@ -97,7 +97,7 @@ On each completion notification (background agent finished, or the poll timer fi
|
|
|
97
97
|
|
|
98
98
|
## Philosophy / rationale
|
|
99
99
|
|
|
100
|
-
- Orchestration state derives from beads so a crash loses nothing but an in-memory ID mapping: `state.json` holds only the
|
|
100
|
+
- Orchestration state derives from beads so a crash loses nothing but an in-memory ID mapping: `state.json` holds only the agent-ID→bead mapping, never task state.
|
|
101
101
|
- Classification happens up-front at planning time (`create-task`), so the loop can trust `bd ready` instead of re-interpreting each bead's intent.
|
|
102
102
|
- Human review gates are non-negotiable because agent-authored changes still need a person to merge them.
|
|
103
103
|
|
package/test/cli.test.mjs
CHANGED
|
@@ -54,11 +54,6 @@ describe("parseArgs", () => {
|
|
|
54
54
|
assert.deepStrictEqual(result, { command: "help" });
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
-
it("returns { command: 'install', harness: 'copilot' } for install copilot", async () => {
|
|
58
|
-
const result = parseArgs(["install", "copilot"]);
|
|
59
|
-
assert.deepStrictEqual(result, { command: "install", harness: "copilot" });
|
|
60
|
-
});
|
|
61
|
-
|
|
62
57
|
it("returns { command: 'install', harness: 'claude' } for install claude", async () => {
|
|
63
58
|
const result = parseArgs(["install", "claude"]);
|
|
64
59
|
assert.deepStrictEqual(result, { command: "install", harness: "claude" });
|
|
@@ -169,11 +164,17 @@ describe("buildHelpText", () => {
|
|
|
169
164
|
|
|
170
165
|
describe("validateHarness", () => {
|
|
171
166
|
it("returns ok for supported harnesses", async () => {
|
|
172
|
-
for (const h of ["
|
|
167
|
+
for (const h of ["claude", "pi"]) {
|
|
173
168
|
assert.deepStrictEqual(validateHarness(h), { ok: true });
|
|
174
169
|
}
|
|
175
170
|
});
|
|
176
171
|
|
|
172
|
+
it("returns error for copilot, which is no longer a deploy target", async () => {
|
|
173
|
+
const result = validateHarness("copilot");
|
|
174
|
+
assert.equal(result.ok, false);
|
|
175
|
+
assert.ok(result.error.includes("Unknown harness"));
|
|
176
|
+
});
|
|
177
|
+
|
|
177
178
|
it("returns error when harness is null", async () => {
|
|
178
179
|
const result = validateHarness(null);
|
|
179
180
|
assert.equal(result.ok, false);
|
|
@@ -207,10 +208,10 @@ describe("CLI integration", () => {
|
|
|
207
208
|
assert.ok(stdout.includes("Usage:"));
|
|
208
209
|
});
|
|
209
210
|
|
|
210
|
-
it("exits
|
|
211
|
-
const { exitCode,
|
|
212
|
-
assert.equal(exitCode,
|
|
213
|
-
assert.ok(
|
|
211
|
+
it("exits 1 for install copilot, which is no longer a deploy target", async () => {
|
|
212
|
+
const { exitCode, stderr } = await runCli(["install", "copilot"]);
|
|
213
|
+
assert.equal(exitCode, 1);
|
|
214
|
+
assert.ok(stderr.includes("Unknown harness"));
|
|
214
215
|
});
|
|
215
216
|
|
|
216
217
|
it("exits 0 for install claude (into a temp output dir)", async () => {
|
package/token-map.README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# token-map.json — multi-harness token substitution
|
|
2
2
|
|
|
3
3
|
`token-map.json` is the central, single-source mapping of **tool names**, **paths**, and
|
|
4
|
-
**agent naming conventions** across the
|
|
4
|
+
**agent naming conventions** across the two harnesses this repo ships to. It is the
|
|
5
5
|
foundation for the install-time generation system: each harness installer (`agent-cortex
|
|
6
6
|
install <harness>`) reads the map and substitutes `{{TOOL:...}}` / `{{PATH:...}}` tokens in
|
|
7
7
|
the files it generates.
|
|
@@ -14,7 +14,6 @@ decisions behind the map.
|
|
|
14
14
|
|
|
15
15
|
| id | Platform | Agent format | Plugin root |
|
|
16
16
|
|---|---|---|---|
|
|
17
|
-
| `copilot` | GitHub Copilot CLI | `agents/<name>/` composable dirs → generated `agents/*.agent.md` | `~/.copilot/installed-plugins/_direct/agent-cortex` |
|
|
18
17
|
| `pi` | pi coding agent | `agents/<name>/` composable dirs (composed at runtime by agent-modes, or rendered install-time by `agent-cortex install pi`) | `~/.agent-cortex/pi` |
|
|
19
18
|
| `claude` | Claude Code | `~/.agent-cortex/claude/agents/*.md` (materialised home install) | `${CLAUDE_PLUGIN_ROOT}` (env var) |
|
|
20
19
|
|
|
@@ -44,9 +43,9 @@ rather than inventing a dotted form:
|
|
|
44
43
|
### 2. What is mapped
|
|
45
44
|
|
|
46
45
|
- **`tools`** — the twelve canonical tool names as authored in `agents/<name>/agent.md`
|
|
47
|
-
(
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
(the canonical authoring names). Each row gives the equivalent tool name per harness.
|
|
47
|
+
The claude column is consumed by `bin/installers/claude.mjs` (the install-time
|
|
48
|
+
generator — PR #91, #92); the pi column is grounded
|
|
50
49
|
in pi's documented built-in tool surface (`read`, `bash`, `edit`, `write`, `grep`, `find`,
|
|
51
50
|
`ls`) plus `ask_questions` — added by the pi-questions package (mapped from
|
|
52
51
|
`ask_user`) — and `task` / `read_agent` / `wait_for_agents` subagent tools, the last three
|
|
@@ -101,7 +100,7 @@ so the warn-and-omit path applies only to future null entries. See
|
|
|
101
100
|
|
|
102
101
|
The full contract is embedded in `token-map.json` under `contract`. In summary, installers:
|
|
103
102
|
|
|
104
|
-
1. Bind a harness id (`
|
|
103
|
+
1. Bind a harness id (`claude` | `pi`).
|
|
105
104
|
2. Substitute in order: `SECTION` (left for the composer), then `TOOL`, then `PATH`.
|
|
106
105
|
3. For `TOOL`: look up the canonical key, replace with the harness name; null → drop/omit;
|
|
107
106
|
unknown → throw.
|
|
@@ -111,7 +110,7 @@ The full contract is embedded in `token-map.json` under `contract`. In summary,
|
|
|
111
110
|
|
|
112
111
|
## Authoring guidance
|
|
113
112
|
|
|
114
|
-
- Write tokens with the **canonical
|
|
113
|
+
- Write tokens with the **canonical authoring names**: `Use {{TOOL:task}} to spawn
|
|
115
114
|
subagents`, `Read {{PATH:skills/workflow/plan/SKILL.md}}`.
|
|
116
115
|
- Never embed a harness-specific name in the canonical sources (`agents/<name>/agent.md`,
|
|
117
116
|
`skills/**/SKILL.md`) — that defeats the map. The materialised Claude plugin
|
|
@@ -125,11 +124,9 @@ The full contract is embedded in `token-map.json` under `contract`. In summary,
|
|
|
125
124
|
|
|
126
125
|
- `agents/README.md` — composable agent directory format (ADR #63), defines the token
|
|
127
126
|
grammar the map implements.
|
|
128
|
-
- `scripts/
|
|
129
|
-
|
|
130
|
-
`
|
|
131
|
-
files; `bin/installers/copilot.mjs` is the shared generator both `pnpm build:copilot`
|
|
132
|
-
and `agent-cortex install copilot` run.
|
|
127
|
+
- `scripts/lib/compose-agent.mjs` — the shared token composer: resolves `{{TOOL:...}}` /
|
|
128
|
+
`{{PATH:...}}` against the map and `{{SECTION:...}}` from the per-harness section files
|
|
129
|
+
for `bin/installers/claude.mjs` and `bin/installers/pi.mjs`.
|
|
133
130
|
- `bin/installers/claude.mjs` — the single Claude generator: plain
|
|
134
131
|
`agent-cortex install claude` materialises the plugin into `~/.agent-cortex/claude`
|
|
135
132
|
with token-substituted skills, merges the committed `claude/settings.json` into
|