@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
@@ -1,124 +0,0 @@
1
- // Install-time generator for the Copilot CLI flat agent files (agents/*.agent.md).
2
- // This is the single code path for producing those files from the canonical
3
- // composable sources — both entry points below call installCopilot(), so
4
- // install-time and build-time output can never diverge:
5
- //
6
- // - bin/agent-cortex.mjs `agent-cortex install copilot` (install-time;
7
- // `--output <dir>` overrides the target,
8
- // `--dry-run` plans without writing)
9
- // - scripts/build-copilot-agents.mjs `pnpm build:copilot` (dev/CI: regenerates
10
- // the committed agents/*.agent.md files in place)
11
- //
12
- // Output lands in <root>/agents/ (the default `output`) because that is the
13
- // directory the Copilot plugin actually loads: plugin.json declares
14
- // "agents": "agents/", which scans for *.agent.md files. The generated flat
15
- // files therefore share the agents/ directory with the canonical composable
16
- // dirs they are composed from (agents/<name>/) — only flat *.agent.md files are
17
- // written, nothing is deleted, so a generated file can never clobber a
18
- // composable source. `--output` exists for the same preview/test contract as the
19
- // claude and pi installers: point it at a scratch dir and inspect the output.
20
- //
21
- // agents/<name>.agent.md composed from agents/<name>/agent.md +
22
- // agents/<name>/copilot/frontmatter.json +
23
- // agents/<name>/copilot/<section>.md ({{SECTION:...}}),
24
- // with {{TOOL:...}}/{{PATH:...}} substituted against
25
- // the copilot column of token-map.json.
26
- //
27
- // The flat files stay committed and CI drift-checks them (build:copilot +
28
- // git diff --exit-code -- 'agents/*.agent.md'), so a fresh clone (or a direct
29
- // path plugin install) ships the plugin read-ready.
30
- //
31
- // Zero dependencies so it runs on the CI Node and local Node alike.
32
-
33
- import { writeFile, mkdir, readdir } from "node:fs/promises";
34
- import { join, dirname } from "node:path";
35
- import { fileURLToPath } from "node:url";
36
- import { composeAgent } from "../../scripts/lib/compose-agent.mjs";
37
- import { isDirectory, isFile } from "../../scripts/lib/fs.mjs";
38
-
39
- const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
40
- const DEFAULT_ROOT = join(MODULE_DIR, "..", "..");
41
-
42
- function byName(a, b) {
43
- return a.localeCompare(b);
44
- }
45
-
46
- /**
47
- * Serialise the flat-file YAML frontmatter. Field order and names mirror the
48
- * pre-migration flat sources (description, name, tools, argument-hint) so
49
- * Copilot CLI sees the same agent metadata. The GENERATED comment references
50
- * scripts/build-copilot-agents.mjs — the committed entry point — so the
51
- * generated bytes are identical whichever of the two entry points ran.
52
- */
53
- function frontmatterYaml(name, fm) {
54
- const lines = [
55
- "---",
56
- `# GENERATED from agents/${name}/ by scripts/build-copilot-agents.mjs — DO NOT EDIT.`,
57
- `description: ${JSON.stringify(fm.description)}`,
58
- `name: ${JSON.stringify(fm.name)}`,
59
- `tools: [${fm.tools.map((t) => JSON.stringify(t)).join(", ")}]`,
60
- ];
61
- if (fm.argumentHint) lines.push(`argument-hint: ${JSON.stringify(fm.argumentHint)}`);
62
- lines.push("---");
63
- return lines.join("\n");
64
- }
65
-
66
- /** Compose agents from agents/<name>/; every composable dir must ship a copilot harness. */
67
- async function buildAgents(root) {
68
- const files = [];
69
- const entries = (await readdir(join(root, "agents"), { withFileTypes: true })).sort((a, b) =>
70
- byName(a.name, b.name),
71
- );
72
-
73
- for (const entry of entries) {
74
- if (!entry.isDirectory()) continue; // skip generated *.agent.md flat files and README
75
- const dir = join(root, "agents", entry.name);
76
- if (!(await isFile(join(dir, "agent.md")))) continue; // not a composable agent dir
77
- if (!(await isDirectory(join(dir, "copilot"))) || !(await isFile(join(dir, "copilot", "frontmatter.json")))) {
78
- throw new Error(`agent "${entry.name}": composable directory without copilot/frontmatter.json — define the copilot harness or exclude the agent`);
79
- }
80
-
81
- const fm = await composeAgent(root, entry.name, "copilot");
82
- files.push({
83
- name: entry.name,
84
- file: `${entry.name}.agent.md`,
85
- content: `${frontmatterYaml(entry.name, fm)}\n\n${fm.body}\n`,
86
- });
87
- }
88
- return files;
89
- }
90
-
91
- /**
92
- * Generate the Copilot CLI flat agent files.
93
- *
94
- * @param {object} options
95
- * @param {string} [options.root] Package root (contains agents/, token-map.json, …).
96
- * Defaults to the repo containing this module.
97
- * @param {string} [options.output] Directory to write the flat *.agent.md files into
98
- * (default: <root>/agents — the dir plugin.json's
99
- * "agents": "agents/" scans for the plugin).
100
- * @param {boolean} [options.dryRun] Plan and report without writing anything.
101
- * @returns {{ output: string, agents: string[], dryRun: boolean }}
102
- */
103
- export async function installCopilot({ root = DEFAULT_ROOT, output, dryRun = false } = {}) {
104
- const out = output ?? join(root, "agents");
105
- const files = await buildAgents(root);
106
- const summary = {
107
- output: out,
108
- agents: files.map((f) => f.name),
109
- dryRun,
110
- };
111
-
112
- if (dryRun) {
113
- console.log(`DRY-RUN — would generate into ${out}, no files written:`);
114
- console.log(` agents: ${summary.agents.join(", ")}`);
115
- return summary;
116
- }
117
-
118
- await mkdir(out, { recursive: true });
119
- for (const { file, content } of files) {
120
- await writeFile(join(out, file), content);
121
- }
122
- console.log(`Generated ${files.length} Copilot agent file(s): ${summary.agents.join(", ")}`);
123
- return summary;
124
- }
@@ -1,44 +0,0 @@
1
- import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
- import { loadSessionContext } from "./lib/context-loader.js";
3
-
4
- /**
5
- * Session-start extension.
6
- *
7
- * Injects baseline context at the start of every PI session:
8
- * 1. Skill availability hints (so the agent knows they exist)
9
- * 2. Project context files (AGENTS.md, user-preferences.md)
10
- *
11
- * Context files are read dynamically from the project root (cwd).
12
- */
13
- export default function (pi: ExtensionAPI) {
14
- pi.on("before_agent_start", async (_event, ctx) => {
15
- const skillHints = [
16
- "Available skills — invoke when relevant (not pre-loaded to save context):",
17
- "",
18
- "• /skill:using-agent-skills — meta-skill that routes to the right skill",
19
- " and enforces core agent behaviors. Check this first if unsure.",
20
- "",
21
- "• /skill:bd-tool — project context & task tracking with beads.",
22
- " Run `bd ready` to see available work.",
23
- "",
24
- "• /skill:git-workflow — git discipline: feature branches,",
25
- " worktrees for solo AFK work, PR workflow, and when to ask.",
26
- "",
27
- "Read the SKILL.md for full instructions when needed.",
28
- ].join("\n");
29
-
30
- const contextFiles = loadSessionContext(ctx.cwd);
31
-
32
- const content = contextFiles
33
- ? `${skillHints}\n\n---\n\n${contextFiles}`
34
- : skillHints;
35
-
36
- return {
37
- message: {
38
- customType: "session-start",
39
- content,
40
- display: false,
41
- },
42
- };
43
- });
44
- }
package/hooks.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "hooks": {
3
- "sessionStart": [
4
- {
5
- "type": "prompt",
6
- "prompt": "Load AGENTS.md and active beads context before taking action."
7
- }
8
- ]
9
- }
10
- }
@@ -1,169 +0,0 @@
1
- // Pi third-party package provisioning.
2
- //
3
- // agent-cortex's pi harness needs tools that live in third-party pi packages:
4
- // ask_questions comes from pi-questions, fetch_content from pi-web-access (see
5
- // token-map.json notes and docs/ideas/extension-manifests.md). Those packages
6
- // are declared in the package manifest — package.json → pi.packages — and this
7
- // module makes them real: `agent-cortex install pi` reads the declaration and
8
- // installs any package the pi user scope is missing.
9
- //
10
- // Provisioning goes through the pi CLI (`pi install <source>`), which both
11
- // installs the package under ~/.pi/agent/npm and declares it in
12
- // ~/.pi/agent/settings.json — the same store pi loads packages from. It is
13
- // opt-in (installPi option `provisionPackages`) and idempotent: a package that
14
- // is already declared and installed is skipped. A failed install warns and the
15
- // rest continue, so an offline machine never breaks the agent install.
16
-
17
- import { readFile, readdir } from "node:fs/promises";
18
- import { join } from "node:path";
19
- import { spawn } from "node:child_process";
20
-
21
- const DEFAULT_WARN = (msg) => console.warn(`[pi-packages] ${msg}`);
22
-
23
- /**
24
- * Read the pi package sources agent-cortex declares it needs.
25
- *
26
- * @param {string} root Package root containing package.json
27
- * @returns {Promise<string[]>} Declared sources, e.g. ["npm:pi-questions"]
28
- */
29
- export async function loadRequiredPackages(root) {
30
- const manifest = JSON.parse(await readFile(join(root, "package.json"), "utf-8"));
31
- const packages = manifest?.pi?.packages;
32
- return Array.isArray(packages) ? packages.filter((entry) => typeof entry === "string") : [];
33
- }
34
-
35
- /**
36
- * Extract the npm package name from a pi source string.
37
- *
38
- * @param {string} source e.g. "npm:pi-web-access@0.10.7", "npm:@scope/pkg"
39
- * @returns {string | null} The name, or null for sources we cannot inspect locally
40
- */
41
- export function npmSourceName(source) {
42
- if (typeof source !== "string" || !source.startsWith("npm:")) return null;
43
- const spec = source.slice("npm:".length);
44
- const at = spec.lastIndexOf("@");
45
- return at > 0 ? spec.slice(0, at) : spec;
46
- }
47
-
48
- /**
49
- * Decide which required packages still need installing.
50
- *
51
- * A package is satisfied only when it is both declared in settings (so pi loads
52
- * it) and present in the npm store (so it is installed) — otherwise it needs a
53
- * `pi install` to reconcile.
54
- *
55
- * @param {string[]} required
56
- * @param {{ declaredSources: string[], installedNames: string[] }} state
57
- * @returns {string[]} The sources still to install
58
- */
59
- export function planPackageInstalls(required, { declaredSources, installedNames }) {
60
- const declared = new Set(declaredSources.map(npmSourceName).filter(Boolean));
61
- const installed = new Set(installedNames);
62
- return required.filter((source) => {
63
- const name = npmSourceName(source);
64
- return name === null || !declared.has(name) || !installed.has(name);
65
- });
66
- }
67
-
68
- /**
69
- * Install every required package the pi user scope is missing.
70
- *
71
- * @param {object} options
72
- * @param {string[]} options.required Declared pi sources (see loadRequiredPackages)
73
- * @param {string} options.piRoot Pi user scope dir (default ~/.pi/agent)
74
- * @param {boolean} [options.dryRun] Report the plan without installing
75
- * @param {(source: string) => Promise<{ok: boolean, error: string | null}>} [options.runInstall]
76
- * @param {(msg: string) => void} [options.warn]
77
- * @returns {Promise<{planned: string[], installed: string[], failed: {source: string, error: string}[]}>}
78
- */
79
- export async function provisionPiPackages({
80
- required,
81
- piRoot,
82
- dryRun = false,
83
- runInstall = runPiInstall,
84
- warn = DEFAULT_WARN,
85
- }) {
86
- const declaredSources = await readDeclaredSources(join(piRoot, "settings.json"));
87
- const installedNames = await readInstalledNames(join(piRoot, "npm", "node_modules"));
88
- const planned = planPackageInstalls(required, { declaredSources, installedNames });
89
-
90
- if (dryRun) return { planned, installed: [], failed: [] };
91
-
92
- const installed = [];
93
- const failed = [];
94
- for (const source of planned) {
95
- const result = await runInstall(source);
96
- if (result.ok) {
97
- installed.push(source);
98
- } else {
99
- failed.push({ source, error: result.error });
100
- warn(`could not install pi package ${source}: ${result.error}`);
101
- }
102
- }
103
- return { planned, installed, failed };
104
- }
105
-
106
- /** Install one pi package source through the pi CLI. */
107
- export function runPiInstall(source) {
108
- return new Promise((resolve) => {
109
- const child = spawn("pi", ["install", source], { stdio: ["ignore", "pipe", "pipe"] });
110
- let stderr = "";
111
- child.stdout.resume(); // drain; only failures are interesting
112
- child.stderr.on("data", (chunk) => {
113
- stderr += chunk;
114
- });
115
- child.on("error", (err) => {
116
- resolve({
117
- ok: false,
118
- error: err.code === "ENOENT" ? "pi CLI not found on PATH" : err.message,
119
- });
120
- });
121
- child.on("close", (code) => {
122
- resolve({
123
- ok: code === 0,
124
- error: code === 0 ? null : stderr.trim() || `pi install exited with code ${code}`,
125
- });
126
- });
127
- });
128
- }
129
-
130
- // ─── Pi user-scope inspection ────────────────────────────────────────────────
131
-
132
- /** Read the package sources declared in a pi settings.json (missing or unreadable → none). */
133
- async function readDeclaredSources(settingsPath) {
134
- let settings;
135
- try {
136
- settings = JSON.parse(await readFile(settingsPath, "utf-8"));
137
- } catch {
138
- // Nothing declared yet, or a file pi itself owns and repairs. Provisioning is
139
- // a non-essential step — it must never fail the agent install.
140
- return [];
141
- }
142
- const packages = Array.isArray(settings?.packages) ? settings.packages : [];
143
- return packages
144
- .map((entry) => (typeof entry === "string" ? entry : entry?.source))
145
- .filter((source) => typeof source === "string");
146
- }
147
-
148
- /** List installed package names in the pi npm store (missing dir → none). */
149
- async function readInstalledNames(nodeModulesDir) {
150
- let entries;
151
- try {
152
- entries = await readdir(nodeModulesDir, { withFileTypes: true });
153
- } catch (err) {
154
- if (err.code === "ENOENT") return [];
155
- throw err;
156
- }
157
- const names = [];
158
- for (const entry of entries) {
159
- if (!entry.isDirectory()) continue;
160
- if (!entry.name.startsWith("@")) {
161
- names.push(entry.name);
162
- continue;
163
- }
164
- for (const scoped of await readdir(join(nodeModulesDir, entry.name), { withFileTypes: true })) {
165
- if (scoped.isDirectory()) names.push(`${entry.name}/${scoped.name}`);
166
- }
167
- }
168
- return names;
169
- }
package/plugin.json DELETED
@@ -1,35 +0,0 @@
1
- {
2
- "name": "agent-cortex",
3
- "description": "Personal Copilot CLI plugin with custom agents and skills",
4
- "version": "1.42.0",
5
- "author": {
6
- "name": "jaybeeuu"
7
- },
8
- "license": "MIT",
9
- "repository": "https://github.com/jaybeeuu/agent-cortex",
10
- "bin": "bin/agent-cortex.mjs",
11
- "agents": "agents/",
12
- "skills": "skills/",
13
- "mcpServers": {
14
- "context7": {
15
- "type": "stdio",
16
- "command": "npx",
17
- "args": [
18
- "-y",
19
- "@upstash/context7-mcp@latest"
20
- ]
21
- },
22
- "github": {
23
- "type": "stdio",
24
- "command": "pnpm",
25
- "args": [
26
- "dlx",
27
- "@modelcontextprotocol/server-github"
28
- ],
29
- "tools": [
30
- "*"
31
- ]
32
- }
33
- },
34
- "hooks": "hooks.json"
35
- }
@@ -1,30 +0,0 @@
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
- await installCopilot({ root: ROOT, output: join(ROOT, "agents") });
@@ -1,82 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Installs ~/.copilot/copilot-instructions.md with proactive skill directives.
3
- # Run after cloning this plugin: pnpm install (or bash scripts/install-instructions.sh)
4
- # Safe to re-run — replaces the agent-cortex section only.
5
-
6
- set -euo pipefail
7
-
8
- INSTRUCTIONS_FILE="$HOME/.copilot/copilot-instructions.md"
9
- MARKER_START="<!-- agent-cortex:start -->"
10
- MARKER_END="<!-- agent-cortex:end -->"
11
-
12
- BLOCK="$MARKER_START
13
- <!-- This block is managed by agent-cortex. Manual edits inside will be overwritten. -->
14
-
15
- ## Proactive skill use (agent-cortex plugin)
16
-
17
- You have a set of custom skills available. Apply them automatically whenever they are relevant — the user should not have to invoke them by name.
18
-
19
- ### Code & tests
20
-
21
- - Apply **style-code** whenever writing, editing, or reviewing code. It defines naming, module boundaries, and architectural conventions.
22
- - Apply **style-tests** whenever writing, editing, or reviewing tests. It defines assertion strategy, mock discipline, and what to test.
23
- - Apply **style-comms** whenever writing external-facing communication: tickets, RFCs, PRDs, proposals, or reports.
24
- - Apply **style-documentation** whenever deciding what to document or reviewing existing docs.
25
- - Use **tdd** (red-green-refactor loop) whenever building a new feature or fixing a bug where correctness matters.
26
- - Run **review-security** before committing any changes that touch secrets, auth, or credentials.
27
-
28
- ### Planning & design
29
-
30
- - Use **write-a-prd** when the user wants to plan a new feature or product requirement.
31
- - Use **prd-to-tasks** after a PRD is approved to break it into phased epics and task beads.
32
- - Use **create-task** when creating a new trackable task bead.
33
- - Use **record-idea** when the user shares an early-stage idea that is not yet ready to implement.
34
- - Use **request-refactor-plan** when the user wants to plan a refactor with safe incremental commits.
35
- - Use **write-a-ticket** when writing a ticket for an external issue tracker (e.g. Jira).
36
- - Use **design-an-interface** when the user wants to explore multiple API or module designs.
37
- - Use **technical-direction** when evaluating architecture or technology choices with tradeoff analysis.
38
- - Use **grill-me** or **grill-with-docs** when the user wants to stress-test a plan or design.
39
- - Use **improve-codebase-architecture** when the user wants to find architectural improvement opportunities.
40
-
41
- ### Task execution
42
-
43
- - Use **bd-tool** whenever the user mentions beads, bd, tasks, or asks what work is available.
44
- - Use **ralph** to run all pending beads end-to-end with review gates.
45
- - Use **run-pipeline-stage** to work through individual pipeline stages inline.
46
- - Use **hitl-collab** when a task requires human review, manual steps, or a PR handoff.
47
- - Use **classify-bead** when a bead is missing its implementation-type label.
48
-
49
- ### Repo & plugin maintenance
50
-
51
- - Use **maintain-agent-docs** when reviewing or updating AGENTS.md or agent-consumed docs.
52
- - Use **refactor-skill** when restructuring or reviewing an existing skill.
53
- - Use **write-a-skill** when creating a new skill.
54
- - Use **init-beads** when setting up the bd task-tracker in a new project.
55
-
56
- $MARKER_END"
57
-
58
- mkdir -p "$(dirname "$INSTRUCTIONS_FILE")"
59
-
60
- if [ ! -f "$INSTRUCTIONS_FILE" ]; then
61
- printf '%s\n' "$BLOCK" > "$INSTRUCTIONS_FILE"
62
- echo "✓ Created $INSTRUCTIONS_FILE"
63
- elif grep -qF "$MARKER_START" "$INSTRUCTIONS_FILE"; then
64
- # Write replacement block to a temp file so awk can read it with getline
65
- BLOCK_FILE=$(mktemp)
66
- printf '%s\n' "$BLOCK" > "$BLOCK_FILE"
67
- awk -v start="$MARKER_START" -v end="$MARKER_END" -v blockfile="$BLOCK_FILE" '
68
- $0 == start {
69
- while ((getline line < blockfile) > 0) print line
70
- close(blockfile)
71
- skip=1; next
72
- }
73
- $0 == end { skip=0; next }
74
- !skip { print }
75
- ' "$INSTRUCTIONS_FILE" > "${INSTRUCTIONS_FILE}.tmp"
76
- mv "${INSTRUCTIONS_FILE}.tmp" "$INSTRUCTIONS_FILE"
77
- rm -f "$BLOCK_FILE"
78
- echo "✓ Updated agent-cortex section in $INSTRUCTIONS_FILE"
79
- else
80
- printf '\n%s\n' "$BLOCK" >> "$INSTRUCTIONS_FILE"
81
- echo "✓ Appended agent-cortex section to $INSTRUCTIONS_FILE"
82
- fi
@@ -1,17 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Sync plugin.json version with package.json
3
- # Called by changesets after versioning to keep them in lockstep
4
-
5
- set -euo pipefail
6
-
7
- VERSION=$(node -p "require('./package.json').version")
8
-
9
- # Update plugin.json version field
10
- node -e "
11
- const fs = require('fs');
12
- const plugin = JSON.parse(fs.readFileSync('plugin.json', 'utf8'));
13
- plugin.version = '$VERSION';
14
- fs.writeFileSync('plugin.json', JSON.stringify(plugin, null, 2) + '\n');
15
- "
16
-
17
- echo "✓ Synced plugin.json to version $VERSION"