@jaybeeuu/agent-cortex 1.37.1 → 1.38.1

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 (92) hide show
  1. package/.agents/skills/style-versioning/SKILL.md +9 -8
  2. package/.github/workflows/ci.yml +190 -8
  3. package/AGENTS.md +25 -6
  4. package/CHANGELOG.md +42 -0
  5. package/README.md +132 -33
  6. package/agents/README.md +47 -13
  7. package/agents/plan/agent.md +51 -0
  8. package/agents/plan/claude/frontmatter.json +6 -0
  9. package/agents/plan/copilot/frontmatter.json +6 -0
  10. package/agents/plan/pi/frontmatter.json +6 -0
  11. package/agents/plan.agent.md +3 -0
  12. package/agents/ralph/agent.md +262 -0
  13. package/agents/ralph/claude/frontmatter.json +6 -0
  14. package/agents/ralph/claude/polling.md +31 -0
  15. package/agents/ralph/copilot/frontmatter.json +6 -0
  16. package/agents/ralph/copilot/polling.md +62 -0
  17. package/agents/ralph/pi/frontmatter.json +6 -0
  18. package/agents/ralph/pi/polling.md +74 -0
  19. package/agents/ralph-plan/agent.md +114 -0
  20. package/agents/ralph-plan/claude/frontmatter.json +6 -0
  21. package/agents/ralph-plan/copilot/frontmatter.json +6 -0
  22. package/agents/ralph-plan/pi/frontmatter.json +6 -0
  23. package/agents/ralph-plan.agent.md +5 -2
  24. package/agents/ralph.agent.md +83 -57
  25. package/agents/strategy/agent.md +104 -0
  26. package/agents/strategy/claude/frontmatter.json +6 -0
  27. package/agents/strategy/copilot/frontmatter.json +6 -0
  28. package/agents/strategy/pi/frontmatter.json +6 -0
  29. package/agents/strategy.agent.md +3 -0
  30. package/bin/agent-cortex.mjs +68 -1
  31. package/bin/installers/claude.mjs +262 -0
  32. package/bin/installers/copilot.mjs +129 -0
  33. package/bin/installers/pi.mjs +197 -0
  34. package/claude/.claude-plugin/plugin.json +1 -1
  35. package/claude/agents/plan.md +3 -1
  36. package/claude/agents/ralph-plan.md +5 -3
  37. package/claude/agents/strategy.md +3 -1
  38. package/claude/hooks/scripts/notify.mjs +54 -0
  39. package/claude/hooks.json +15 -0
  40. package/docs/claude-hooks.md +115 -0
  41. package/docs/ideas/auto-model-selection.md +75 -0
  42. package/docs/ideas/improve-pi-system-prompt.md +34 -0
  43. package/docs/ideas/model-selector.md +40 -0
  44. package/docs/ideas/pi-task-memory.md +34 -0
  45. package/docs/ideas/qa-extension.md +43 -0
  46. package/docs/ideas/unified-ci-pipeline.md +28 -0
  47. package/docs/skills/skill-anatomy.md +9 -0
  48. package/extensions/agent-modes/README.md +54 -0
  49. package/extensions/agent-modes/discover.test.ts +241 -0
  50. package/extensions/agent-modes/discover.ts +458 -0
  51. package/extensions/agent-modes/index.ts +13 -224
  52. package/extensions/agent-modes/node_modules/.bin/pi +21 -0
  53. package/extensions/agent-modes/node_modules/.bin/tsc +21 -0
  54. package/extensions/agent-modes/node_modules/.bin/tsserver +21 -0
  55. package/extensions/agent-modes/node_modules/.bin/tsx +21 -0
  56. package/extensions/agent-modes/package.json +20 -0
  57. package/extensions/agent-modes/tsconfig.json +12 -0
  58. package/extensions/subagent/README.md +19 -0
  59. package/extensions/subagent/index.ts +131 -45
  60. package/extensions/subagent/node_modules/.bin/pi +21 -0
  61. package/extensions/subagent/node_modules/.bin/pi-ai +21 -0
  62. package/extensions/subagent/node_modules/.bin/tsc +21 -0
  63. package/extensions/subagent/node_modules/.bin/tsserver +21 -0
  64. package/extensions/subagent/node_modules/.bin/tsx +21 -0
  65. package/extensions/subagent/package.json +23 -0
  66. package/extensions/subagent/tsconfig.json +12 -0
  67. package/extensions/subagent/wait.test.ts +202 -0
  68. package/extensions/subagent/wait.ts +118 -0
  69. package/hooks/claude/hooks.json +38 -0
  70. package/hooks/claude/scripts/notify.mjs +54 -0
  71. package/lib/cli.mjs +62 -3
  72. package/package.json +6 -4
  73. package/plugin.json +1 -1
  74. package/scripts/build-copilot-agents.mjs +30 -0
  75. package/scripts/lib/compose-agent.mjs +241 -0
  76. package/skills/engineering/design-an-interface/SKILL.md +1 -1
  77. package/skills/engineering/improve-codebase-architecture/SKILL.md +1 -1
  78. package/skills/workflow/ralph/REFERENCE.md +2 -2
  79. package/skills/workflow/ralph/SKILL.md +6 -6
  80. package/skills/workflow/run-pipeline-stage/scripts/generate-progress.ts +4 -2
  81. package/skills/workflow/using-agent-skills/SKILL.md +122 -0
  82. package/test/cli.test.mjs +115 -2
  83. package/test/copilot-installer.test.mjs +298 -0
  84. package/test/installer.test.mjs +179 -0
  85. package/test/notify-hook.test.mjs +63 -0
  86. package/test/pi-installer.test.mjs +371 -0
  87. package/token-map.README.md +128 -0
  88. package/token-map.json +106 -0
  89. package/.github/workflows/ci.test.ts +0 -217
  90. package/.github/workflows/release.yml +0 -58
  91. package/scripts/build-claude-agents.mjs +0 -179
  92. package/scripts/publish-release.sh +0 -32
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jaybeeuu/agent-cortex",
3
- "version": "1.37.1",
3
+ "version": "1.38.1",
4
4
  "description": "Personal PI package with custom agents, skills, and extensions",
5
5
  "keywords": [
6
6
  "pi-package"
@@ -29,11 +29,13 @@
29
29
  "scripts": {
30
30
  "build": "echo 'Build complete — no compilation needed for PI package'",
31
31
  "lint": "pnpm typecheck",
32
- "test": "pnpm -r test",
32
+ "test": "node --test test/*.test.mjs && pnpm -r test",
33
33
  "typecheck": "pnpm -r typecheck",
34
- "build:claude": "node scripts/build-claude-agents.mjs",
34
+ "build:claude": "node bin/agent-cortex.mjs install claude",
35
+ "build:copilot": "node scripts/build-copilot-agents.mjs",
35
36
  "changeset": "changeset",
36
- "version-packages": "changeset version && bash scripts/sync-plugin-version.sh",
37
+ "version-packages": "changeset version && bash scripts/sync-plugin-version.sh && pnpm build:claude && pnpm build:copilot",
38
+ "publish-package": "TARBALL=$(pnpm pack | tail -n 1) && npm publish \"$TARBALL\" --provenance --access public",
37
39
  "release": "changeset publish",
38
40
  "postinstall": "bash scripts/install-instructions.sh"
39
41
  }
package/plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "agent-cortex",
3
3
  "description": "Personal Copilot CLI plugin with custom agents and skills",
4
- "version": "1.37.1",
4
+ "version": "1.38.1",
5
5
  "author": {
6
6
  "name": "jaybeeuu"
7
7
  },
@@ -0,0 +1,30 @@
1
+ // Regenerates the committed Copilot CLI flat agent files (agents/*.agent.md)
2
+ // from the canonical composable agent sources (agents/<name>/).
3
+ //
4
+ // This script is a thin wrapper over the shared install-time generator
5
+ // (bin/installers/copilot.mjs) — `agent-cortex install copilot` runs exactly the
6
+ // same code path, so install-time and build-time output can never diverge. CI
7
+ // runs this and checks `git diff --exit-code -- 'agents/*.agent.md'` to
8
+ // guarantee the committed flat files are never stale: a fresh clone (or a
9
+ // direct path plugin install) ships the Copilot plugin read-ready.
10
+ //
11
+ // agents/<name>.agent.md composed from agents/<name>/agent.md +
12
+ // agents/<name>/copilot/frontmatter.json +
13
+ // agents/<name>/copilot/<section>.md ({{SECTION:...}}),
14
+ // with {{TOOL:...}}/{{PATH:...}} substituted against
15
+ // the copilot column of token-map.json.
16
+ //
17
+ // The flat files live in the same agents/ directory the Copilot plugin scans
18
+ // (plugin.json "agents": "agents/"), next to the composable dirs they come
19
+ // from — the generator only writes *.agent.md files and never deletes.
20
+ //
21
+ // Run: pnpm build:copilot (node scripts/build-copilot-agents.mjs)
22
+ // Zero dependencies so it runs on the CI Node (20) and local Node alike.
23
+
24
+ import { join, dirname } from "node:path";
25
+ import { fileURLToPath } from "node:url";
26
+ import { installCopilot } from "../bin/installers/copilot.mjs";
27
+
28
+ const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..");
29
+
30
+ installCopilot({ root: ROOT, output: join(ROOT, "agents") });
@@ -0,0 +1,241 @@
1
+ // Shared composer: reads a composable agent directory (agents/<name>/) and emits
2
+ // the harness-specific agent content defined by agents/README.md. The Copilot
3
+ // generator (scripts/build-copilot-agents.mjs) and the Claude install-time generator
4
+ // (bin/installers/claude.mjs) compose from here, so the composable dirs are
5
+ // the single source of truth and the flat/generated files stay in lockstep.
6
+ //
7
+ // Composition per the agents/README.md contract:
8
+ // 1. {{SECTION:name}} is replaced with <dir>/<harness>/<name>.md content.
9
+ // 2. {{TOOL:key}} is replaced with the harness column of token-map.json.
10
+ // 3. {{PATH:arg}} with a named key resolves through token-map.json's paths
11
+ // table; anything else is a relative path and stays verbatim.
12
+ // Substitution order is SECTION → TOOL → PATH (matches extensions/agent-modes).
13
+ // Missing sections, unknown tool keys, or schema-invalid frontmatter are hard
14
+ // errors: a committed generated file must never ship a literal token or a
15
+ // silently dropped section.
16
+ //
17
+ // Options (the pi installer passes `dropNullTools`, `pluginRoot` and
18
+ // `resolveRelativePaths`; the copilot generator and claude installer use the strict defaults):
19
+ // dropNullTools replace null-mapped tool tokens with an empty string and
20
+ // warn instead of throwing (pi's prose rule per the
21
+ // token-map contract)
22
+ // pluginRoot override the plugin_root used for resolved paths
23
+ // (installers compute it from the actual install layout)
24
+ // resolveRelativePaths non-keyed {{PATH:...}} args resolve to pluginRoot/arg
25
+ // instead of staying verbatim (install time; the build
26
+ // scripts leave them bare for Copilot CLI resolution)
27
+ // warn callback for drop/omit warnings (default: no-op; the
28
+ // pi installer collects them into its result)
29
+ //
30
+ // Zero dependencies so it runs on the CI Node (20) and local Node alike.
31
+
32
+ import { readFileSync, existsSync } from "node:fs";
33
+ import { join } from "node:path";
34
+
35
+ // ─── Token substitution ──────────────────────────────────────────────────────
36
+
37
+ const TOOL_RE = /\{\{TOOL:([^}]+)\}\}/g;
38
+ const PATH_RE = /\{\{PATH:([^}]+)\}\}/g;
39
+
40
+ function noop() {}
41
+
42
+ /**
43
+ * Substitute {{TOOL:...}} and {{PATH:...}} tokens in arbitrary content (agent
44
+ * bodies, skill files) against one harness column of token-map.json.
45
+ *
46
+ * - TOOL: unknown key → throw (the map must stay complete); null mapping → drop
47
+ * with a warning when `dropNullTools`, otherwise throw.
48
+ * - PATH: named key → resolve through the paths table (plugin_root overridable);
49
+ * non-keyed → join(pluginRoot, arg) when `resolveRelativePaths`, else verbatim.
50
+ * - SECTION tokens are *not* handled here — the agent composer resolves them from
51
+ * the harness's section files before calling this.
52
+ *
53
+ * @param {string} content Source text containing {{TOOL:...}}/{{PATH:...}} tokens
54
+ * @param {string} harness Harness id: "copilot" | "claude" | "pi"
55
+ * @param {object} tokenMap Parsed token-map.json (from loadTokenMap)
56
+ * @param {object} options { dropNullTools, pluginRoot, resolveRelativePaths, warn, context }
57
+ * @returns {string}
58
+ */
59
+ export function substituteTokens(content, harness, tokenMap, options = {}) {
60
+ const { dropNullTools = false, pluginRoot, resolveRelativePaths = false, warn = noop, context = "" } = options;
61
+ const ctx = context ? `${context}: ` : "";
62
+
63
+ // 2. {{TOOL:key}} → token-map.json tools.<key>.<harness>
64
+ content = content.replace(TOOL_RE, (_token, key) => {
65
+ const entry = tokenMap.tools[key];
66
+ if (!entry) throw new Error(`${ctx}unknown tool token {{TOOL:${key}}} — extend token-map.json`);
67
+ const mapped = entry[harness];
68
+ if (mapped == null) {
69
+ if (dropNullTools) {
70
+ warn(`tool token {{TOOL:${key}}} has no ${harness} mapping — dropped`);
71
+ return "";
72
+ }
73
+ throw new Error(`${ctx}tool token {{TOOL:${key}}} has no ${harness} mapping (null) — drop the token in agent.md first`);
74
+ }
75
+ return mapped;
76
+ });
77
+
78
+ // 3. {{PATH:arg}} → named keys via token-map.json paths; relative paths verbatim
79
+ // (or resolved against pluginRoot when the installer option is set)
80
+ content = content.replace(PATH_RE, (_token, arg) =>
81
+ resolvePath(arg, harness, tokenMap, { pluginRoot, resolveRelativePaths }),
82
+ );
83
+
84
+ return content;
85
+ }
86
+
87
+ /**
88
+ * Compose the harness-specific agent content from a composable agent directory.
89
+ *
90
+ * @param {string} root Package root (contains agents/ and token-map.json)
91
+ * @param {string} name Agent directory name (e.g. "ralph", "plan")
92
+ * @param {string} harness Harness id: "copilot" | "claude" | "pi"
93
+ * @returns {{ name: string, description: string, tools: string[], model?: string, argumentHint?: string, body: string }}
94
+ */
95
+ export function composeAgent(root, name, harness, options = {}) {
96
+ const { dropNullTools = false, pluginRoot, resolveRelativePaths = false, warn = noop } = options;
97
+ const agentDir = join(root, "agents", name);
98
+ const frontmatter = parseFrontmatter(join(agentDir, harness, "frontmatter.json"), name, harness);
99
+ const tokenMap = loadTokenMap(root);
100
+
101
+ let body = readFileSync(join(agentDir, "agent.md"), "utf-8");
102
+
103
+ // 1. {{SECTION:name}} → <harness>/<name>.md (may itself contain TOOL/PATH tokens)
104
+ body = body.replace(/\{\{SECTION:([^}]+)\}\}/g, (_token, section) => {
105
+ const sectionPath = join(agentDir, harness, `${section}.md`);
106
+ if (!existsSync(sectionPath)) {
107
+ throw new Error(`agent "${name}": missing section "${section}" for harness "${harness}" (${sectionPath})`);
108
+ }
109
+ return readFileSync(sectionPath, "utf-8").trim();
110
+ });
111
+
112
+ // 2. + 3. TOOL/PATH substitution (contextualised for error messages)
113
+ body = substituteTokens(body, harness, tokenMap, {
114
+ dropNullTools,
115
+ pluginRoot,
116
+ resolveRelativePaths,
117
+ warn,
118
+ context: `agent "${name}"`,
119
+ });
120
+
121
+ return { ...frontmatter, body: body.trim() };
122
+ }
123
+
124
+ // ─── Frontmatter ─────────────────────────────────────────────────────────────
125
+
126
+ const REQUIRED_FIELDS = ["name", "description", "tools"];
127
+ const KNOWN_OPTIONAL_FIELDS = ["model", "argumentHint"];
128
+
129
+ /** Parse and schema-check a harness frontmatter.json (strict, per agents/README.md). */
130
+ function parseFrontmatter(path, name, harness) {
131
+ const raw = readFileSync(path, "utf-8");
132
+ let fm;
133
+ try {
134
+ fm = JSON.parse(raw);
135
+ } catch (err) {
136
+ throw new Error(`agent "${name}": invalid JSON in ${path}: ${err.message}`);
137
+ }
138
+ if (typeof fm !== "object" || fm === null) {
139
+ throw new Error(`agent "${name}": ${path} must be a JSON object`);
140
+ }
141
+ for (const field of REQUIRED_FIELDS) {
142
+ if (!(field in fm)) throw new Error(`agent "${name}": ${path} missing required field "${field}" (harness ${harness})`);
143
+ }
144
+ if (typeof fm.name !== "string" || fm.name.trim() === "") throw new Error(`agent "${name}": ${path} name must be a non-empty string`);
145
+ if (typeof fm.description !== "string" || fm.description.trim() === "") throw new Error(`agent "${name}": ${path} description must be a non-empty string`);
146
+ if (!Array.isArray(fm.tools) || fm.tools.length === 0 || !fm.tools.every((t) => typeof t === "string")) {
147
+ throw new Error(`agent "${name}": ${path} tools must be a non-empty array of strings`);
148
+ }
149
+ for (const key of Object.keys(fm)) {
150
+ if (![...REQUIRED_FIELDS, ...KNOWN_OPTIONAL_FIELDS].includes(key)) {
151
+ throw new Error(`agent "${name}": ${path} unknown field "${key}" — strict schema per agents/README.md`);
152
+ }
153
+ }
154
+ return {
155
+ name: fm.name,
156
+ description: fm.description,
157
+ tools: fm.tools,
158
+ ...(typeof fm.model === "string" ? { model: fm.model } : {}),
159
+ ...(typeof fm.argumentHint === "string" ? { argumentHint: fm.argumentHint } : {}),
160
+ };
161
+ }
162
+
163
+ // ─── Path resolution ─────────────────────────────────────────────────────────
164
+
165
+ /**
166
+ * Resolve a {{PATH:...}} argument for a harness's generated output.
167
+ * Named keys resolve through token-map.json's paths table (recursively for
168
+ * {base, relative} specs); non-keyed args are relative paths, kept verbatim —
169
+ * the installer beads own precise runtime path resolution (see token-map.README.md).
170
+ * With the installer options (`pluginRoot`, `resolveRelativePaths`) the
171
+ * plugin_root base and bare relative paths resolve against the actual install
172
+ * layout instead.
173
+ */
174
+ function resolvePath(arg, harness, tokenMap, opts = {}) {
175
+ const entry = tokenMap.paths?.[arg];
176
+ if (!entry) {
177
+ if (opts.resolveRelativePaths && opts.pluginRoot) return join(opts.pluginRoot, arg);
178
+ return arg;
179
+ }
180
+
181
+ const spec = entry[harness];
182
+ if (typeof spec === "string") {
183
+ if (arg === "plugin_root" && opts.pluginRoot) return opts.pluginRoot;
184
+ return spec;
185
+ }
186
+ if (spec && typeof spec === "object" && typeof spec.base === "string" && typeof spec.relative === "string") {
187
+ return join(resolvePath(spec.base, harness, tokenMap, opts), spec.relative);
188
+ }
189
+ throw new Error(`unresolvable {{PATH:${arg}}} for harness "${harness}" — extend token-map.json`);
190
+ }
191
+
192
+ /**
193
+ * Translate a frontmatter tool list into one harness's tool names.
194
+ *
195
+ * Canonical keys resolve through token-map.json's tools table; a null mapping
196
+ * means the harness has no equivalent and the entry is omitted (the contract's
197
+ * tool-list rule); a name that is not a canonical key passes through untouched
198
+ * (it may be a native tool, e.g. pi's fetch_content). Mirrors the runtime
199
+ * translation in extensions/agent-modes/discover.ts.
200
+ *
201
+ * @param {string[]} tools Canonical tool names from a harness frontmatter.json
202
+ * @param {object} tokenMap Parsed token-map.json (from loadTokenMap)
203
+ * @param {string} harness Harness id: "copilot" | "claude" | "pi"
204
+ * @param {object} options { warn }
205
+ * @returns {string[]}
206
+ */
207
+ export function translateToolList(tools, tokenMap, harness, { warn = noop } = {}) {
208
+ const out = [];
209
+ for (const tool of tools) {
210
+ const mapping = tokenMap.tools[tool];
211
+ if (mapping === undefined) {
212
+ out.push(tool);
213
+ continue;
214
+ }
215
+ const mapped = mapping[harness];
216
+ if (mapped == null) {
217
+ warn(`tool "${tool}" has no ${harness} mapping — omitted from the tool list`);
218
+ continue;
219
+ }
220
+ out.push(mapped);
221
+ }
222
+ return out;
223
+ }
224
+
225
+ // ─── Token map ───────────────────────────────────────────────────────────────
226
+
227
+ /** Load token-map.json from the package root; missing/incomplete maps hard-fail. */
228
+ export function loadTokenMap(root) {
229
+ const path = join(root, "token-map.json");
230
+ let raw;
231
+ try {
232
+ raw = readFileSync(path, "utf-8");
233
+ } catch {
234
+ throw new Error(`missing ${path} — the composer requires token-map.json`);
235
+ }
236
+ const parsed = JSON.parse(raw);
237
+ if (!parsed.tools || !parsed.paths) {
238
+ throw new Error(`${path}: expected "tools" and "paths" tables`);
239
+ }
240
+ return parsed;
241
+ }
@@ -23,7 +23,7 @@ Ask: "What does this module need to do? Who will use it?"
23
23
 
24
24
  ### 2. Generate Designs (Parallel Sub-Agents)
25
25
 
26
- Spawn 3+ sub-agents simultaneously using Task tool. Each must produce a **radically different** approach.
26
+ Spawn 3+ sub-agents simultaneously using {{TOOL:task}}. Each must produce a **radically different** approach.
27
27
 
28
28
  ```
29
29
  Prompt template for each sub-agent:
@@ -13,7 +13,7 @@ A **deep module** (John Ousterhout, "A Philosophy of Software Design") has a sma
13
13
 
14
14
  ### 1. Explore the codebase
15
15
 
16
- Explore the codebase using your available tools (bash, rg, view, glob, find). Navigate organically and note where you experience friction:
16
+ Explore the codebase using your available tools ({{TOOL:bash}}, {{TOOL:rg}}, {{TOOL:view}}, {{TOOL:glob}}). Navigate organically and note where you experience friction:
17
17
 
18
18
  - Where does understanding one concept require bouncing between many small files?
19
19
  - Where are modules so shallow that the interface is nearly as complex as the implementation?
@@ -10,7 +10,7 @@ Detailed procedures for the fleet orchestration workflow. See [SKILL.md](./SKILL
10
10
  2. **Read its `stage:*` label** from `bd show <id>`.
11
11
  3. **Load the universal stage runner prompt** from `skills/workflow/run-pipeline-stage/prompts/stage-runner.md`.
12
12
  4. **Read the parent task context**: follow the `parent-child` dependency to the parent task bead, run `bd show <parent-id>` to get the full task description.
13
- 5. **Ensure branch + worktree exist for this parent task** (see _Feature branches and worktrees_ below), then note the worktree path — you'll pass it as `cwd` to `task`.
13
+ 5. **Ensure branch + worktree exist for this parent task** (see _Feature branches and worktrees_ below), then note the worktree path — you'll pass it as `cwd` to {{TOOL:task}}.
14
14
  6. **Fill in the prompt** — replace placeholders with:
15
15
  - Stage from bead label (`stage:<stage>`) for `<stage>`
16
16
  - `bd prime` output (held in memory from initialization)
@@ -18,7 +18,7 @@ Detailed procedures for the fleet orchestration workflow. See [SKILL.md](./SKILL
18
18
  - For `fix` stage: `FILES_CHANGED` from the preceding stage's report (the required changes come from the fix bead's own description — read via `bd show <fix-id>`)
19
19
  - For `verify`, `review`, `document` stages: `SUMMARY` and `FILES_CHANGED` from the preceding stage's report
20
20
  - Bead ID and log file path (`.agent-cortex/ralph/ralph-<bead-id>.log`)
21
- 7. **Call the `task` tool** with the filled prompt as `prompt` and the worktree path as `cwd`. Store the returned agentId — you need it for step 8 and for log polling.
21
+ 7. **Call the {{TOOL:task}} tool** with the filled prompt as `prompt` and the worktree path as `cwd`. Store the returned agentId — you need it for step 8 and for log polling.
22
22
  8. **Map** the agent ID to the bead ID in memory for lookup on completion.
23
23
 
24
24
  ---
@@ -35,7 +35,7 @@ Run once at startup:
35
35
  - **Task or other type without an `implementation-type:*` label**: unexpected here — classification is a planning-stage concern already applied by `create-task`. Do not invoke `classify-bead`; treat as needs-refinement and note for the shutdown summary.
36
36
  - **Task labelled `implementation-type:hitl`**: skip — record the bead ID for the **Pending Human Action** summary at shutdown.
37
37
  7. For each ready chore bead (up to 5), **dispatch** it (see _Dispatching a chore bead_ in REFERENCE.md). Chores for a parent bead must run from that parent's worktree.
38
- 8. **If** any chore beads were dispatched in step 7, start the **poll timer**: run `sleep 120` as a background bash process and hold its shellId in memory. **Otherwise**, if HITL gate beads are pending (check `bd list -l lifecycle:feature-pr -l implementation-type:hitl` and `bd list -l awaiting-epic-pr-merge`), proceed to **HITL Pause** (see REFERENCE.md) immediately.
38
+ 8. **If** any chore beads were dispatched in step 7, start the **poll timer** (Copilot only): run `sleep 120` as a background bash process and hold its shellId in memory. PI has no timer — keep a `wait_for_agents` call outstanding over every in-flight agent ID instead (see the Event Loop note). **Otherwise**, if HITL gate beads are pending (check `bd list -l lifecycle:feature-pr -l implementation-type:hitl` and `bd list -l awaiting-epic-pr-merge`), proceed to **HITL Pause** (see REFERENCE.md) immediately.
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)
@@ -47,7 +47,7 @@ Run once at startup:
47
47
 
48
48
  ## Event Loop
49
49
 
50
- After initialization, wait for background agents or the poll timer to complete. On each completion notification:
50
+ After initialization, wait for background agents or the poll timer to complete. Completion detection is harness-specific: the `sleep 120` poll timer described below is the **Copilot** mechanism. **PI** replaces it with the blocking `wait_for_agents` tool — it returns as soon as any in-flight agent finishes, so each return plays the role of a poll-timer tick with its completed-agent result attached; there is no timer to start or kill on PI. On each completion notification:
51
51
 
52
52
  ### Poll timer completed
53
53
 
@@ -59,7 +59,7 @@ After initialization, wait for background agents or the poll timer to complete.
59
59
  ### Background agent completed
60
60
 
61
61
  1. **Poll that bead's log** to flush any final lines.
62
- 2. **Read** the completed agent's full output with `read_agent`.
62
+ 2. **Read** the completed agent's full output with {{TOOL:read_agent}} (on PI the completed result arrives in the `wait_for_agents` response; read_agent remains a fallback for a specific result).
63
63
  3. **Identify the bead**: parse the `---REPORT---` block for `BEAD_ID` and `STAGE_COMPLETED`.
64
64
  4. **Close** the chore bead: `bd close <bead-id>`.
65
65
  5. **Handle stage outcome**:
@@ -90,10 +90,10 @@ After initialization, wait for background agents or the poll timer to complete.
90
90
  - **Always** run in **foreground** (interactive) mode. If you find yourself executing as a background task, immediately surface a warning to the user and ask them to re-run you in foreground mode.
91
91
  - **Never** write, edit, or create source code or documentation yourself.
92
92
  - **Never** edit bead task files directly — only use `bd` commands.
93
- - **ALWAYS call the `task` tool to spawn subagents** — never use bash, never run stages inline, never use any other tool. This is your only spawning mechanism.
93
+ - **ALWAYS call the {{TOOL:task}} tool to spawn subagents** — never use {{TOOL:bash}}, never run stages inline, never use any other tool. This is your only spawning mechanism.
94
94
  - **Always** derive orchestration state from beads — do not maintain a separate state file.
95
- - **Always** include the full `bd prime` output verbatim in every `task` tool prompt.
96
- - **Always** keep the poll timer running — restart it immediately after it fires — **unless** the HITL pause condition is met (no chores in-flight, no `stage:*` chores ready, HITL gate beads pending), in which case proceed to **HITL Pause** (see REFERENCE.md) and stop instead.
95
+ - **Always** include the full `bd prime` output verbatim in every {{TOOL:task}} tool prompt.
96
+ - **Always** keep the poll timer running (Copilot) — restart it immediately after it fires — **unless** the HITL pause condition is met (no chores in-flight, no `stage:*` chores ready, HITL gate beads pending), in which case proceed to **HITL Pause** (see REFERENCE.md) and stop instead. On PI there is no timer to keep alive — always keep one `wait_for_agents` call outstanding while agents are in-flight.
97
97
  - **Never** post empty poll updates to chat — only surface new log content.
98
98
  - **Max 5** tasks in-flight at once.
99
99
  - **Max fix rounds** per task as defined by `maxFixRounds` in `skills/planning/create-task/pipeline.json`.
@@ -50,8 +50,10 @@ const STATUS_CHAR_MAP: Record<string, BeadStatus> = {
50
50
  export function parseListLine(
51
51
  line: string,
52
52
  ): { id: string; status: BeadStatus; title: string } | null {
53
- // Format: {STATUS_CHAR} {ID} ● P{N} {TITLE}
54
- const match = line.trim().match(/^([○◐●✓❄])\s+(\S+)\s+●\s+P\d+\s+(.+)$/);
53
+ // Formats accepted:
54
+ // {STATUS_CHAR} {ID} P{N} {TITLE} — current bd list output
55
+ // {STATUS_CHAR} {ID} ● P{N} {TITLE} — older bd (● before P{N} is optional)
56
+ const match = line.trim().match(/^([○◐●✓❄])\s+(\S+)\s+(?:●\s+)?P\d+\s+(.+)$/);
55
57
  if (!match) return null;
56
58
  const [, statusChar, id, title] = match;
57
59
  const status = STATUS_CHAR_MAP[statusChar];
@@ -0,0 +1,122 @@
1
+ ---
2
+ name: using-agent-skills
3
+ description: Routes incoming work to the right skill and enforces core agent behaviors. Use when starting a session, deciding which skill applies, or when you need to check "which skill should I use?".
4
+ ---
5
+
6
+ # Using Agent Skills
7
+
8
+ ## When to use
9
+
10
+ - Starting a new session and need to orient on available workflows.
11
+ - A task arrives and you need to decide which skill applies.
12
+ - The user asks "which skill should I use for this?"
13
+ - You want to verify that core operating behaviors are being followed.
14
+
15
+ ## Workflow
16
+
17
+ When a task arrives, identify the development phase and apply the corresponding skill:
18
+
19
+ ```
20
+ Task arrives
21
+ │
22
+ ├── Don't know what to build yet? ──────→ grill-me
23
+ ├── Have a rough idea? ─────────────────→ record-idea
24
+ ├── New feature / PRD needed? ──────────→ write-a-prd
25
+ ├── PRD approved, need tasks? ──────────→ prd-to-tasks
26
+ ├── Need a single task tracked? ────────→ create-task
27
+ ├── Need to plan a feature end-to-end? ─→ plan
28
+ ├── Running beads / task execution? ────→ ralph
29
+ │ └── Single stage? ─────────────────→ run-pipeline-stage
30
+ ├── Implementing code? ────────────────→ tdd
31
+ │ ├── Designing an interface? ───────→ design-an-interface
32
+ │ └── Need style conventions? ───────→ style-code
33
+ ├── Reviewing code? ───────────────────→ style-code
34
+ │ ├── Security concerns? ────────────→ review-security
35
+ │ └── Reviewing tests? ──────────────→ style-tests
36
+ ├── Writing tests? ────────────────────→ style-tests
37
+ ├── Writing docs? ─────────────────────→ style-documentation
38
+ ├── Writing external comms? ───────────→ style-comms
39
+ ├── Stress-testing a plan? ────────────→ grill-with-docs
40
+ ├── Planning a refactor? ──────────────→ request-refactor-plan
41
+ ├── Evaluating architecture? ──────────→ technical-direction
42
+ ├── Finding refactor opportunities? ───→ improve-codebase-architecture
43
+ ├── Need task tracking? ───────────────→ bd-tool
44
+ ├── Need human review / HITL? ─────────→ hitl-collab
45
+ ├── Need a handoff doc? ───────────────→ handoff
46
+ ├── Writing a ticket for Jira? ────────→ write-a-ticket
47
+ ├── Creating a new skill? ─────────────→ write-a-skill
48
+ ├── Refactoring a skill? ──────────────→ refactor-skill
49
+ ├── Updating agent docs? ──────────────→ maintain-agent-docs
50
+ └── Setting up beads in a new project? → init-beads
51
+ ```
52
+
53
+ ## Core Operating Behaviors
54
+
55
+ These behaviors apply at all times, across all skills. They are non-negotiable.
56
+
57
+ ### 1. Surface Assumptions
58
+
59
+ Before implementing anything non-trivial, explicitly state your assumptions. Don't silently fill in ambiguous requirements — surface uncertainty early, it's cheaper than rework.
60
+
61
+ ### 2. Manage Confusion Actively
62
+
63
+ When you encounter inconsistencies, conflicting requirements, or unclear specifications: **STOP**. Name the specific confusion, present the tradeoff or ask the clarifying question, and wait for resolution before continuing.
64
+
65
+ ### 3. Push Back When Warranted
66
+
67
+ You are not a yes-machine. When an approach has clear problems, point out the issue directly, explain the concrete downside, propose an alternative, and accept the human's decision if they override with full information.
68
+
69
+ ### 4. Enforce Simplicity
70
+
71
+ Your natural tendency is to overcomplicate. Before finishing any implementation, ask: Can this be done in fewer lines? Are these abstractions earning their complexity? Prefer the boring, obvious solution.
72
+
73
+ ### 5. Maintain Scope Discipline
74
+
75
+ Touch only what you're asked to touch. Do not clean up orthogonal code, refactor adjacent systems, or add features not in the spec. Surgical precision, not unsolicited renovation.
76
+
77
+ ### 6. Verify, Don't Assume
78
+
79
+ A task is not complete until verification passes. "Seems right" is never sufficient — there must be evidence: passing tests, build output, or runtime data.
80
+
81
+ ### 7. Flag Persistent Failures
82
+
83
+ When a tool or command fails repeatedly, stop and flag it to the user for investigation. Don't paper over failures with workarounds — workarounds waste tokens and hide real problems. Describe what failed, how many times, and any obvious patterns. Let the user decide whether to investigate in a dedicated session. Inefficiencies and failures should be squashed, not hidden.
84
+
85
+ ### 8. Stay On Target
86
+
87
+ Stick to the task at hand. If you discover work that's outside the current scope — a tangential bug, an adjacent improvement, a missing doc — flag it to the user but don't pursue it. If the side quest blocks or slows your progress, stop and report it. Otherwise, note it and get back on track. Scope creep mid-task burns tokens and dilutes focus.
88
+
89
+ ## Lifecycle Sequence
90
+
91
+ For a complete feature, the typical skill sequence is:
92
+
93
+ 1. `grill-me` → Extract what the user actually wants
94
+ 2. `record-idea` → Refine vague ideas
95
+ 3. `write-a-prd` → Define what we're building
96
+ 4. `prd-to-tasks` → Break into verifiable chunks
97
+ 5. `plan` → Orchestrate the full flow end-to-end
98
+ 6. `ralph` → Execute all pending beads
99
+ 7. `tdd` → Prove each slice works
100
+ 8. `style-code` → Review before merge
101
+ 9. `review-security` → Check for secrets
102
+ 10. `git-workflow` → Clean commit history
103
+
104
+ Not every task needs every skill. A bug fix might only need: `tdd` → `style-code` → `review-security`.
105
+
106
+ ## Red Flags
107
+
108
+ - Starting work without checking which skill applies.
109
+ - Skipping verification because "it looks right."
110
+ - Making wrong assumptions without stating them.
111
+ - Overcomplicating code when a simple solution exists.
112
+ - Modifying code orthogonal to the task scope.
113
+ - Going on side-quests instead of staying on target.
114
+ - Going on side-quests instead of staying on target.
115
+ - Going on side-quests instead of staying on target.
116
+
117
+ ## Verification checklist
118
+
119
+ - [ ] Correct skill identified before starting work.
120
+ - [ ] Core operating behaviors followed throughout.
121
+ - [ ] Verification completed with evidence (tests, build, runtime).
122
+ - [ ] Scope limited to the task at hand.