@jaybeeuu/agent-cortex 1.37.1 → 1.39.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 +9 -8
- package/.github/workflows/ci.yml +190 -8
- package/AGENTS.md +27 -6
- package/CHANGELOG.md +72 -0
- package/README.md +156 -39
- package/agents/README.md +49 -13
- package/agents/plan/agent.md +51 -0
- package/agents/plan/claude/frontmatter.json +6 -0
- package/agents/plan/copilot/frontmatter.json +6 -0
- package/agents/plan/pi/frontmatter.json +6 -0
- package/agents/plan.agent.md +3 -0
- package/agents/ralph/agent.md +262 -0
- package/agents/ralph/claude/frontmatter.json +6 -0
- package/agents/ralph/claude/polling.md +31 -0
- package/agents/ralph/copilot/frontmatter.json +6 -0
- package/agents/ralph/copilot/polling.md +62 -0
- package/agents/ralph/pi/frontmatter.json +6 -0
- package/agents/ralph/pi/polling.md +74 -0
- package/agents/ralph-plan/agent.md +114 -0
- package/agents/ralph-plan/claude/frontmatter.json +6 -0
- package/agents/ralph-plan/copilot/frontmatter.json +6 -0
- package/agents/ralph-plan/pi/frontmatter.json +6 -0
- package/agents/ralph-plan.agent.md +6 -3
- package/agents/ralph.agent.md +83 -57
- package/agents/strategy/agent.md +104 -0
- package/agents/strategy/claude/frontmatter.json +6 -0
- package/agents/strategy/copilot/frontmatter.json +6 -0
- package/agents/strategy/pi/frontmatter.json +6 -0
- package/agents/strategy.agent.md +3 -0
- package/bin/agent-cortex.mjs +76 -1
- package/bin/installers/claude.mjs +376 -0
- package/bin/installers/copilot.mjs +129 -0
- package/bin/installers/pi.mjs +197 -0
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/agents/plan.md +3 -1
- package/claude/agents/ralph-plan.md +6 -4
- package/claude/agents/strategy.md +3 -1
- package/claude/hooks/scripts/notify.mjs +54 -0
- package/claude/hooks.json +15 -0
- package/docs/claude-hooks.md +115 -0
- package/docs/ideas/auto-model-selection.md +75 -0
- package/docs/ideas/extension-manifests.md +75 -0
- package/docs/ideas/improve-pi-system-prompt.md +34 -0
- package/docs/ideas/model-selector.md +40 -0
- package/docs/ideas/pi-task-memory.md +34 -0
- package/docs/ideas/qa-extension.md +43 -0
- package/docs/ideas/record-ideas-as-beads.md +115 -0
- package/docs/ideas/subagent-visibility.md +72 -0
- package/docs/ideas/task-session-context.md +89 -0
- package/docs/ideas/unified-ci-pipeline.md +28 -0
- package/docs/research/skill-design-research.md +4 -4
- package/docs/research/skill-improvements-analysis.md +1 -1
- package/docs/skills/skill-anatomy.md +47 -2
- package/docs/technical-direction/migration-execution-labels.md +132 -0
- package/extensions/agent-modes/README.md +54 -0
- package/extensions/agent-modes/discover.test.ts +241 -0
- package/extensions/agent-modes/discover.ts +458 -0
- package/extensions/agent-modes/index.ts +13 -224
- package/extensions/agent-modes/node_modules/.bin/pi +21 -0
- package/extensions/agent-modes/node_modules/.bin/tsc +21 -0
- package/extensions/agent-modes/node_modules/.bin/tsserver +21 -0
- package/extensions/agent-modes/node_modules/.bin/tsx +21 -0
- package/extensions/agent-modes/package.json +20 -0
- package/extensions/agent-modes/tsconfig.json +12 -0
- package/extensions/subagent/README.md +19 -0
- package/extensions/subagent/index.ts +131 -45
- package/extensions/subagent/node_modules/.bin/pi +21 -0
- package/extensions/subagent/node_modules/.bin/pi-ai +21 -0
- package/extensions/subagent/node_modules/.bin/tsc +21 -0
- package/extensions/subagent/node_modules/.bin/tsserver +21 -0
- package/extensions/subagent/node_modules/.bin/tsx +21 -0
- package/extensions/subagent/package.json +23 -0
- package/extensions/subagent/tsconfig.json +12 -0
- package/extensions/subagent/wait.test.ts +202 -0
- package/extensions/subagent/wait.ts +118 -0
- package/hooks/claude/hooks.json +38 -0
- package/hooks/claude/scripts/notify.mjs +54 -0
- package/lib/cli.mjs +68 -3
- package/package.json +6 -4
- package/plugin.json +1 -1
- package/pnpm-workspace.yaml +1 -1
- package/scripts/build-copilot-agents.mjs +30 -0
- package/scripts/lib/compose-agent.mjs +241 -0
- package/skills/engineering/design-an-interface/SKILL.md +78 -58
- package/skills/engineering/grill-with-docs/REFERENCE.md +78 -0
- package/skills/engineering/grill-with-docs/SKILL.md +66 -63
- package/skills/engineering/improve-codebase-architecture/SKILL.md +66 -48
- package/skills/engineering/technical-direction/FORMAT.md +38 -0
- package/skills/engineering/technical-direction/SKILL.md +70 -77
- package/skills/planning/classify-bead/SKILL.md +59 -35
- package/skills/planning/create-task/REFERENCE.md +40 -0
- package/skills/planning/create-task/SKILL.md +70 -66
- package/skills/planning/create-task/scripts/create-chores.ts +6 -1
- package/skills/planning/create-task/scripts/node_modules/.bin/tsc +21 -0
- package/skills/planning/create-task/scripts/node_modules/.bin/tsserver +21 -0
- package/skills/planning/create-task/scripts/node_modules/.bin/tsx +21 -0
- package/skills/planning/prd-to-tasks/REFERENCE.md +66 -0
- package/skills/planning/prd-to-tasks/SKILL.md +86 -170
- package/skills/planning/record-idea/FORMAT.md +44 -0
- package/skills/planning/record-idea/SKILL.md +70 -53
- package/skills/planning/request-refactor-plan/FORMAT.md +45 -0
- package/skills/planning/request-refactor-plan/SKILL.md +57 -46
- package/skills/planning/write-a-prd/FORMAT.md +54 -0
- package/skills/planning/write-a-prd/SKILL.md +49 -48
- package/skills/planning/write-a-ticket/SKILL.md +68 -53
- package/skills/productivity/handoff/SKILL.md +12 -0
- package/skills/productivity/init-beads/SKILL.md +48 -40
- package/skills/productivity/validate-agent-dir/scripts/node_modules/.bin/tsc +21 -0
- package/skills/productivity/validate-agent-dir/scripts/node_modules/.bin/tsserver +21 -0
- package/skills/productivity/validate-agent-dir/scripts/node_modules/.bin/tsx +21 -0
- package/skills/productivity/write-a-skill/SKILL.md +2 -1
- package/skills/review/maintain-agent-docs/SKILL.md +71 -51
- package/skills/workflow/hitl-collab/SKILL.md +86 -17
- package/skills/workflow/ralph/REFERENCE.md +24 -19
- package/skills/workflow/ralph/SKILL.md +88 -74
- package/skills/workflow/run-pipeline-stage/REFERENCE.md +22 -0
- package/skills/workflow/run-pipeline-stage/SKILL.md +91 -93
- package/skills/workflow/run-pipeline-stage/scripts/generate-progress.test.ts +6 -107
- package/skills/workflow/run-pipeline-stage/scripts/generate-progress.ts +4 -2
- package/skills/workflow/run-pipeline-stage/scripts/node_modules/.bin/tsc +21 -0
- package/skills/workflow/run-pipeline-stage/scripts/node_modules/.bin/tsserver +21 -0
- package/skills/workflow/run-pipeline-stage/scripts/node_modules/.bin/tsx +21 -0
- package/skills/workflow/using-agent-skills/SKILL.md +122 -0
- package/test/claude-installer.test.mjs +248 -0
- package/test/cli.test.mjs +115 -2
- package/test/copilot-installer.test.mjs +298 -0
- package/test/installer.test.mjs +179 -0
- package/test/notify-hook.test.mjs +63 -0
- package/test/pi-installer.test.mjs +371 -0
- package/token-map.README.md +130 -0
- package/token-map.json +106 -0
- package/.github/workflows/ci.test.ts +0 -217
- package/.github/workflows/release.yml +0 -58
- package/scripts/build-claude-agents.mjs +0 -179
- package/scripts/publish-release.sh +0 -32
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
// Pi harness installer: agent-cortex install pi
|
|
2
|
+
//
|
|
3
|
+
// Materialises the agent-cortex package into the pi runtime's user scope:
|
|
4
|
+
//
|
|
5
|
+
// <output>/agents/<slug>.agent.md composed agents (default ~/.pi/agent/agents)
|
|
6
|
+
// <output>/skills/<group>/<name>/ token-substituted skill copies (default ~/.pi/agent/skills)
|
|
7
|
+
//
|
|
8
|
+
// Composition per the token-map.json contract:
|
|
9
|
+
// 1. {{SECTION:name}} is resolved from the agent's pi/<name>.md section file
|
|
10
|
+
// (shared composer, scripts/lib/compose-agent.mjs).
|
|
11
|
+
// 2. {{TOOL:key}} is substituted with the pi column; a null mapping drops the
|
|
12
|
+
// token from prose with a warning (pi has no ask_user/skill tool).
|
|
13
|
+
// 3. {{PATH:key}} named keys resolve through the paths table; bare relative
|
|
14
|
+
// paths resolve against the plugin root (default: token-map.json's pi value,
|
|
15
|
+
// overridable with --plugin-root for checkout/symlinked installs).
|
|
16
|
+
// Frontmatter tool lists are translated the same way agent-modes does at runtime:
|
|
17
|
+
// canonical → pi column, null → omitted, unknown (native pi tool) → pass through.
|
|
18
|
+
// Skill markdown files get the same TOOL/PATH substitution so pi never serves
|
|
19
|
+
// literal token syntax; other skill files are copied verbatim.
|
|
20
|
+
//
|
|
21
|
+
// Skills install into ~/.pi/agent/skills (pi's user-global skill dir), which pi
|
|
22
|
+
// loads before package skills, so the substituted copies shadow the raw package
|
|
23
|
+
// skills of the same name (pi dedupes by name, user wins).
|
|
24
|
+
//
|
|
25
|
+
// Zero dependencies so it runs on the CI Node and local Node alike.
|
|
26
|
+
|
|
27
|
+
import { readFileSync, writeFileSync, mkdirSync, copyFileSync, readdirSync, statSync } from "node:fs";
|
|
28
|
+
import { join, dirname } from "node:path";
|
|
29
|
+
import { fileURLToPath } from "node:url";
|
|
30
|
+
import { homedir } from "node:os";
|
|
31
|
+
import { composeAgent, loadTokenMap, substituteTokens, translateToolList } from "../../scripts/lib/compose-agent.mjs";
|
|
32
|
+
|
|
33
|
+
const PI = "pi";
|
|
34
|
+
|
|
35
|
+
// The token-map contract version this installer implements (token-map.json
|
|
36
|
+
// "version" field). A higher map version is rejected: the contract must be
|
|
37
|
+
// extended before this installer can trust it.
|
|
38
|
+
const CONTRACT_VERSION = 1;
|
|
39
|
+
|
|
40
|
+
const REPO_ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
41
|
+
const DEFAULT_OUTPUT = join(homedir(), ".pi", "agent");
|
|
42
|
+
|
|
43
|
+
const DEFAULT_WARN = (msg) => console.warn(`[pi-installer] ${msg}`);
|
|
44
|
+
|
|
45
|
+
function isDirectory(p) {
|
|
46
|
+
try {
|
|
47
|
+
return statSync(p).isDirectory();
|
|
48
|
+
} catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function isFile(p) {
|
|
54
|
+
try {
|
|
55
|
+
return statSync(p).isFile();
|
|
56
|
+
} catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Install the agent-cortex pi harness into the pi runtime.
|
|
63
|
+
*
|
|
64
|
+
* @param {object} options
|
|
65
|
+
* @param {string} [options.root] Package root (defaults to this file's repo)
|
|
66
|
+
* @param {string} [options.output] Pi user-scope dir; agents go to
|
|
67
|
+
* <output>/agents, skills to <output>/skills
|
|
68
|
+
* (default ~/.pi/agent)
|
|
69
|
+
* @param {boolean} [options.dryRun] Compute and report without writing anything
|
|
70
|
+
* @param {string} [options.pluginRoot] Override plugin_root used for {{PATH:...}}
|
|
71
|
+
* resolution (default: token-map pi value)
|
|
72
|
+
* @param {(msg: string) => void} [options.warn] Warning sink, also collected in `warnings`
|
|
73
|
+
* @returns {{ agents: {name:string, filePath:string}[], skills: {skills:number, md:number, files:number, dir:string},
|
|
74
|
+
* warnings: string[], dryRun: boolean, agentsDir: string, skillsDir: string }}
|
|
75
|
+
*/
|
|
76
|
+
export function installPi(options = {}) {
|
|
77
|
+
const root = options.root ?? REPO_ROOT;
|
|
78
|
+
const output = options.output ?? DEFAULT_OUTPUT;
|
|
79
|
+
const dryRun = options.dryRun ?? false;
|
|
80
|
+
const warnings = [];
|
|
81
|
+
const warn = (msg) => {
|
|
82
|
+
warnings.push(msg);
|
|
83
|
+
(options.warn ?? DEFAULT_WARN)(msg);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const tokenMap = loadTokenMap(root);
|
|
87
|
+
if (typeof tokenMap.version === "number" && tokenMap.version > CONTRACT_VERSION) {
|
|
88
|
+
throw new Error(
|
|
89
|
+
`token-map.json version ${tokenMap.version} is newer than the contract version ${CONTRACT_VERSION} this installer implements — upgrade agent-cortex`,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const pluginRoot = options.pluginRoot ?? tokenMap.paths.plugin_root?.[PI];
|
|
94
|
+
const agentsDir = join(output, "agents");
|
|
95
|
+
const skillsDir = join(output, "skills");
|
|
96
|
+
|
|
97
|
+
const agents = installAgents({ root, agentsDir, dryRun, pluginRoot, tokenMap, warn });
|
|
98
|
+
const skills = installSkills({ root, skillsDir, dryRun, pluginRoot, tokenMap, warn });
|
|
99
|
+
|
|
100
|
+
return { agents, skills, warnings, dryRun, agentsDir, skillsDir };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ─── Agents ──────────────────────────────────────────────────────────────────
|
|
104
|
+
|
|
105
|
+
function installAgents({ root, agentsDir, dryRun, pluginRoot, tokenMap, warn }) {
|
|
106
|
+
const written = [];
|
|
107
|
+
const agentsSrc = join(root, "agents");
|
|
108
|
+
for (const entry of readdirSync(agentsSrc, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
109
|
+
if (!entry.isDirectory()) continue; // skip generated *.agent.md flat files
|
|
110
|
+
const dir = join(agentsSrc, entry.name);
|
|
111
|
+
if (!isFile(join(dir, "agent.md"))) continue; // not a composable agent dir
|
|
112
|
+
if (!isDirectory(join(dir, PI)) || !isFile(join(dir, PI, "frontmatter.json"))) {
|
|
113
|
+
throw new Error(`agent "${entry.name}": composable directory without pi/frontmatter.json — define the pi harness or exclude the agent`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const fm = composeAgent(root, entry.name, PI, {
|
|
117
|
+
dropNullTools: true,
|
|
118
|
+
pluginRoot,
|
|
119
|
+
resolveRelativePaths: true,
|
|
120
|
+
warn,
|
|
121
|
+
});
|
|
122
|
+
const tools = translateToolList(fm.tools, tokenMap, PI, { warn });
|
|
123
|
+
const content = renderPiAgent(entry.name, fm, tools);
|
|
124
|
+
const filePath = join(agentsDir, `${entry.name}.agent.md`);
|
|
125
|
+
if (!dryRun) {
|
|
126
|
+
mkdirSync(agentsDir, { recursive: true });
|
|
127
|
+
writeFileSync(filePath, content);
|
|
128
|
+
}
|
|
129
|
+
written.push({ name: entry.name, filePath });
|
|
130
|
+
}
|
|
131
|
+
return written;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function renderPiAgent(name, fm, tools) {
|
|
135
|
+
const lines = [
|
|
136
|
+
"---",
|
|
137
|
+
`# GENERATED from agents/${name}/ by bin/installers/pi.mjs — DO NOT EDIT.`,
|
|
138
|
+
`name: ${JSON.stringify(fm.name)}`,
|
|
139
|
+
`description: ${JSON.stringify(fm.description)}`,
|
|
140
|
+
`tools: ${JSON.stringify(tools.join(" "))}`,
|
|
141
|
+
];
|
|
142
|
+
if (fm.model) lines.push(`model: ${JSON.stringify(fm.model)}`);
|
|
143
|
+
if (fm.argumentHint) lines.push(`argument-hint: ${JSON.stringify(fm.argumentHint)}`);
|
|
144
|
+
lines.push("---");
|
|
145
|
+
return `${lines.join("\n")}\n\n${fm.body}\n`;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ─── Skills ──────────────────────────────────────────────────────────────────
|
|
149
|
+
|
|
150
|
+
function installSkills({ root, skillsDir, dryRun, pluginRoot, tokenMap, warn }) {
|
|
151
|
+
const skillsSrc = join(root, "skills");
|
|
152
|
+
if (!isDirectory(skillsSrc)) return { skills: 0, md: 0, files: 0, dir: skillsDir };
|
|
153
|
+
|
|
154
|
+
const transform = (content) =>
|
|
155
|
+
substituteTokens(content, PI, tokenMap, { dropNullTools: true, pluginRoot, resolveRelativePaths: true, warn });
|
|
156
|
+
|
|
157
|
+
if (!dryRun) mkdirSync(skillsDir, { recursive: true });
|
|
158
|
+
let skills = 0;
|
|
159
|
+
let md = 0;
|
|
160
|
+
let files = 0;
|
|
161
|
+
for (const group of readdirSync(skillsSrc).sort()) {
|
|
162
|
+
const groupDir = join(skillsSrc, group);
|
|
163
|
+
if (!isDirectory(groupDir)) continue;
|
|
164
|
+
for (const name of readdirSync(groupDir).sort()) {
|
|
165
|
+
if (!isFile(join(groupDir, name, "SKILL.md"))) continue;
|
|
166
|
+
skills += 1;
|
|
167
|
+
const stats = copyTree(join(groupDir, name), join(skillsDir, group, name), transform, dryRun);
|
|
168
|
+
md += stats.md;
|
|
169
|
+
files += stats.files;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return { skills, md, files, dir: skillsDir };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** Recursively copy a tree; transform .md file contents, copy everything else verbatim. */
|
|
176
|
+
function copyTree(src, dest, transform, dryRun) {
|
|
177
|
+
let md = 0;
|
|
178
|
+
let files = 0;
|
|
179
|
+
const entries = readdirSync(src, { withFileTypes: true });
|
|
180
|
+
for (const entry of entries) {
|
|
181
|
+
const from = join(src, entry.name);
|
|
182
|
+
const to = join(dest, entry.name);
|
|
183
|
+
if (entry.isDirectory()) {
|
|
184
|
+
const stats = copyTree(from, to, transform, dryRun);
|
|
185
|
+
md += stats.md;
|
|
186
|
+
files += stats.files;
|
|
187
|
+
} else if (entry.isFile()) {
|
|
188
|
+
files += 1;
|
|
189
|
+
if (entry.name.endsWith(".md")) md += 1;
|
|
190
|
+
if (dryRun) continue;
|
|
191
|
+
mkdirSync(dest, { recursive: true });
|
|
192
|
+
if (entry.name.endsWith(".md")) writeFileSync(to, transform(readFileSync(from, "utf-8")));
|
|
193
|
+
else copyFileSync(from, to);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return { md, files };
|
|
197
|
+
}
|
package/claude/agents/plan.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
---
|
|
2
|
-
# GENERATED from agents/plan
|
|
2
|
+
# GENERATED from agents/plan/ by bin/installers/claude.mjs — DO NOT EDIT.
|
|
3
3
|
name: plan
|
|
4
4
|
description: "Guide a feature from first discussion through PRD and task breakdown to classified beads ready for ralph execution. Full end-to-end planning workflow using the plan skill. Use when starting a new feature, scoping work to hand off to ralph, or saying 'plan this'."
|
|
5
5
|
tools: Bash, Read, Edit, Write, Grep, Glob, AskUserQuestion, Task, Skill
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
+
# plan — end-to-end feature planning agent
|
|
9
|
+
|
|
8
10
|
You are a planning agent. Your job is to guide a feature from first discussion through PRD and task breakdown to classified beads ready for ralph execution.
|
|
9
11
|
|
|
10
12
|
You follow the **plan** skill workflow. The skill is defined in `skills/workflow/plan/SKILL.md`. Read it now to load the full instructions.
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
---
|
|
2
|
-
# GENERATED from agents/ralph-plan
|
|
2
|
+
# GENERATED from agents/ralph-plan/ by bin/installers/claude.mjs — DO NOT EDIT.
|
|
3
3
|
name: ralph-plan
|
|
4
4
|
description: "Plans changes by exploring codebases and creating beads to track the work. Use when you want to scope a feature, bug fix, or refactor — the agent reads, reasons, grills the user, writes a high-level plan into the top-level bead, then files child beads ready for ralph."
|
|
5
5
|
tools: Bash, Read, Edit, Write, Grep, Glob, AskUserQuestion
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
+
# ralph-plan — planning agent for ralph
|
|
9
|
+
|
|
8
10
|
You are a planning agent. Your job is to understand a task, explore the codebase, grill the user until the design is clear, write a concise implementation plan, and file beads for ralph to implement. You **must not** modify any source code or tracked documentation — your writes are limited to `.agent-cortex/working-docs/` and bead fields.
|
|
9
11
|
|
|
10
12
|
## Permitted writes
|
|
@@ -32,7 +34,7 @@ Invoke the **beads** skill (set workspace root, run `bd prime`). Hold the output
|
|
|
32
34
|
If the input looks like a PRD (product requirements document), invoke the **prd-to-tasks** skill first — it handles exploration, user quizzing, and creates epics and task beads directly. Then continue from step 7 (Agree with the user).
|
|
33
35
|
|
|
34
36
|
### 2. Understand the request
|
|
35
|
-
If the request is ambiguous or incomplete, use
|
|
37
|
+
If the request is ambiguous or incomplete, use AskUserQuestion to resolve blockers before exploring. One question at a time.
|
|
36
38
|
|
|
37
39
|
If the domain language is unclear or inconsistent, invoke the **grill-with-docs** skill to extract canonical terms. It updates `CONTEXT.md` inline and surfaces ambiguities.
|
|
38
40
|
|
|
@@ -68,7 +70,7 @@ bd dep add <feature-or-task-id> <planning-gate-id> # feature/task depends on p
|
|
|
68
70
|
|
|
69
71
|
Do not close planning gates in bulk. Only close a gate after the user explicitly confirms that exact feature/task is ready to implement; leave all unconfirmed gates open and blocking.
|
|
70
72
|
|
|
71
|
-
|
|
73
|
+
Before handing off, ensure every bead created in this step carries an `implementation-type` label — check `bd label list <id>` yourself. Do not spawn `classify-bead` here: planning gates were tagged inline above and `create-task` classifies its beads internally. Only invoke it for a bead that genuinely lacks both the label and a `## Type` field.
|
|
72
74
|
|
|
73
75
|
Tag every bead created in this step with `workflow:ralph`:
|
|
74
76
|
|
|
@@ -116,4 +118,4 @@ Every explore sub-agent prompt must include:
|
|
|
116
118
|
- Never assume — verify by reading actual code before creating a bead.
|
|
117
119
|
- Never write outside `.agent-cortex/working-docs/` or bead fields.
|
|
118
120
|
- Never make commits, open PRs, or run shell commands that modify the repo.
|
|
119
|
-
- Use
|
|
121
|
+
- Use Bash only for read-only commands (`git log`, `find`, `cat`, etc.).
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
---
|
|
2
|
-
# GENERATED from agents/strategy
|
|
2
|
+
# GENERATED from agents/strategy/ by bin/installers/claude.mjs — DO NOT EDIT.
|
|
3
3
|
name: strategy
|
|
4
4
|
description: "Creates top-level design documents across strategy, PRD, and technical direction so delivery planning starts with clear intent and justified decisions. Use when defining product direction before implementation planning, shaping a feature PRD, or selecting technical direction before ralph-plan."
|
|
5
5
|
tools: Bash, Read, Grep, Glob, AskUserQuestion, WebFetch, Skill, Edit, Write
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
+
# strategy — pre-delivery design agent
|
|
9
|
+
|
|
8
10
|
You are a pre-delivery design agent. Your job is to produce high-quality design artifacts that set up `ralph-plan` for success.
|
|
9
11
|
|
|
10
12
|
## Scope
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Claude Code Notification hook — desktop notification on task completion/error.
|
|
3
|
+
//
|
|
4
|
+
// Reads the Notification hook JSON payload from stdin and prints a
|
|
5
|
+
// `{ "terminalSequence": "..." }` response for Claude Code to emit. Hooks run
|
|
6
|
+
// without a controlling terminal, so OSC sequences must go through Claude Code
|
|
7
|
+
// itself (it handles tmux/screen re-wrapping); writing /dev/tty directly fails.
|
|
8
|
+
//
|
|
9
|
+
// Mapped from the pi `notify` extension (extensions/notify/): pi notifies on
|
|
10
|
+
// agent_end for multi-turn or long tasks. Claude Code's Notification matcher is an
|
|
11
|
+
// exact-string list over `notification_type` values (there are no `success`/
|
|
12
|
+
// `error` types) — hooks.json selects `agent_completed|agent_needs_input|permission_prompt`
|
|
13
|
+
// to mirror "task completed / failed / needs approval". The payload already carries
|
|
14
|
+
// a message + title, so no summarization LLM call is needed here.
|
|
15
|
+
//
|
|
16
|
+
// Zero dependencies; runs on the Node that ships with Claude Code.
|
|
17
|
+
|
|
18
|
+
let raw = "";
|
|
19
|
+
for await (const chunk of process.stdin) {
|
|
20
|
+
raw += chunk;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let payload = {};
|
|
24
|
+
try {
|
|
25
|
+
payload = raw.trim() ? JSON.parse(raw) : {};
|
|
26
|
+
} catch {
|
|
27
|
+
process.exit(0); // never fail a session on an unparsable payload
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const message = typeof payload.message === "string" ? payload.message.trim() : "";
|
|
31
|
+
if (!message) process.exit(0); // nothing worth notifying (e.g. autocompact events)
|
|
32
|
+
|
|
33
|
+
const title =
|
|
34
|
+
typeof payload.title === "string" && payload.title.trim() ? payload.title.trim() : "Claude Code";
|
|
35
|
+
const type = typeof payload.notification_type === "string" ? payload.notification_type : "";
|
|
36
|
+
|
|
37
|
+
process.stdout.write(JSON.stringify({ terminalSequence: pickSequence(title, message, type) }) + "\n");
|
|
38
|
+
|
|
39
|
+
/** Pick an OSC notification escape sequence for the detected terminal. */
|
|
40
|
+
function pickSequence(title, message, type) {
|
|
41
|
+
const body = message.replace(/\u001b/g, "").replace(/\n/g, " ").trim();
|
|
42
|
+
const label = type ? `${type}: ${title}` : title;
|
|
43
|
+
|
|
44
|
+
if (process.env.KITTY_WINDOW_ID) {
|
|
45
|
+
// Kitty: two-part persistent notification (title + body) — same form as the pi notify extension.
|
|
46
|
+
return `\u001b]99;i=1:d=1;${title}\u001b\\\u001b]99;i=1:p=body;${body}\u001b\\`;
|
|
47
|
+
}
|
|
48
|
+
if (process.env.TERM_PROGRAM === "iTerm.app" || process.env.ITERM_SESSION_ID) {
|
|
49
|
+
// iTerm2 / ConEmu / Windows Terminal / WezTerm: OSC 9.
|
|
50
|
+
return `\u001b]9;${label}: ${body}\u0007`;
|
|
51
|
+
}
|
|
52
|
+
// urxvt / Ghostty / Warp, and default fallback: OSC 777.
|
|
53
|
+
return `\u001b]777;notify;${label};${body}\u0007`;
|
|
54
|
+
}
|
package/claude/hooks.json
CHANGED
|
@@ -12,12 +12,27 @@
|
|
|
12
12
|
"type": "command",
|
|
13
13
|
"command": "echo 'Style policy: this project ships style skills — prefer them over ad-hoc choices. Invoke style-code BEFORE writing or editing code (and when refactoring); style-tests BEFORE writing or changing tests; style-documentation BEFORE writing or updating docs; style-comms BEFORE composing commit messages, PR descriptions, tickets, or other written deliverables.'"
|
|
14
14
|
},
|
|
15
|
+
{
|
|
16
|
+
"type": "command",
|
|
17
|
+
"command": "echo 'Skill policy: agent-cortex ships skills — prefer them over ad-hoc choices. using-agent-skills routes work to the right skill (check it first when unsure); bd-tool tracks beads tasks (run bd ready for available work); git-workflow enforces branch and PR discipline. Invoke skills via the Skill tool.'"
|
|
18
|
+
},
|
|
15
19
|
{
|
|
16
20
|
"type": "command",
|
|
17
21
|
"command": "echo 'Be extremely concise. Sacrifice grammar for the sake of concision.'"
|
|
18
22
|
}
|
|
19
23
|
]
|
|
20
24
|
}
|
|
25
|
+
],
|
|
26
|
+
"Notification": [
|
|
27
|
+
{
|
|
28
|
+
"matcher": "agent_completed|agent_needs_input|permission_prompt",
|
|
29
|
+
"hooks": [
|
|
30
|
+
{
|
|
31
|
+
"type": "command",
|
|
32
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/scripts/notify.mjs\""
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
|
21
36
|
]
|
|
22
37
|
}
|
|
23
38
|
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Claude Code hooks — extension port audit
|
|
2
|
+
|
|
3
|
+
The pi extensions in `extensions/` were audited for Claude Code equivalents.
|
|
4
|
+
Implemented ports live in `hooks/claude/hooks.json` (copied verbatim into the
|
|
5
|
+
generated plugin as `claude/hooks.json`); support scripts live in
|
|
6
|
+
`hooks/claude/scripts/` and are bundled into `claude/hooks/scripts/` by
|
|
7
|
+
`bin/installers/claude.mjs` (referenced from hooks.json via `$CLAUDE_PLUGIN_ROOT`).
|
|
8
|
+
|
|
9
|
+
Claude Code's hook model differs from PI's: hooks are shell commands fed a JSON
|
|
10
|
+
payload on stdin, with events like `SessionStart`, `SessionEnd`, `Stop`,
|
|
11
|
+
`SubagentStop`, and `Notification` — there is no `before_agent_start` /
|
|
12
|
+
`agent_end` / `tool_call` extension API, no runtime tool registration, and no
|
|
13
|
+
UI surface. Each decision below is grounded in the Claude Code hooks reference.
|
|
14
|
+
|
|
15
|
+
| pi extension | Claude port | Decision |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| `session-start.ts` | `SessionStart` hook commands | **Port** (extended) |
|
|
18
|
+
| `auto-name.ts` | — | **Reject** — built-in |
|
|
19
|
+
| `notify/` | `Notification` hook + `scripts/notify.mjs` | **Port** |
|
|
20
|
+
| `skill-stats/` | — | **Reject** — no equivalent |
|
|
21
|
+
| `subagent/` | — | **Reject** — native |
|
|
22
|
+
| `agent-modes/` | — | **Reject** — no equivalent |
|
|
23
|
+
|
|
24
|
+
## `session-start.ts` → SessionStart (port)
|
|
25
|
+
|
|
26
|
+
pi injects skill-availability hints + project context files (AGENTS.md,
|
|
27
|
+
`docs/user-preferences.md`) into every session. Claude Code already loads
|
|
28
|
+
`AGENTS.md` natively and the existing SessionStart hook nudge ("Load AGENTS.md
|
|
29
|
+
and active beads context…") plus the style-skill policy (PR #57) cover the
|
|
30
|
+
context side. This bead closes the remaining gap: a skill-policy command listing
|
|
31
|
+
the meta-skills (`using-agent-skills` for routing, `bd-tool` for beads context,
|
|
32
|
+
`git-workflow` for branch/PR discipline). SessionStart command-hook stdout is
|
|
33
|
+
added to Claude's context, so plain `echo` commands are the right shape —
|
|
34
|
+
keep them fast and dependency-free. Skipped from the pi original: the dynamic
|
|
35
|
+
file read of AGENTS.md/user-preferences.md, since Claude Code loads AGENTS.md
|
|
36
|
+
itself and user-preferences.md is a pi-harness document.
|
|
37
|
+
|
|
38
|
+
## `auto-name.ts` → Reject (built-in)
|
|
39
|
+
|
|
40
|
+
pi names sessions via a tiny side-model call on the first prompt. Claude Code
|
|
41
|
+
already auto-generates descriptive session titles (visible in `claude --resume`;
|
|
42
|
+
a background model request in interactive and headless/SDK sessions) and supports
|
|
43
|
+
explicit naming via `--name` / `/rename`. A hook-based title generator would
|
|
44
|
+
duplicate platform behaviour with an extra LLM call — rejected. (SessionStart
|
|
45
|
+
hooks can also set `sessionTitle` in JSON output for the rare case where a
|
|
46
|
+
custom title is genuinely needed.)
|
|
47
|
+
|
|
48
|
+
## `notify/` → Notification hook (port)
|
|
49
|
+
|
|
50
|
+
pi notifies on `agent_end` for multi-turn/long tasks with a desktop notification
|
|
51
|
+
+ bell. Claude Code's native `Notification` event fires at the equivalent
|
|
52
|
+
completion points and already carries `message`, `title`, and `notification_type`
|
|
53
|
+
in the payload — and hooks emit desktop notifications by returning a
|
|
54
|
+
`terminalSequence` JSON field (hooks have no controlling terminal; Claude Code
|
|
55
|
+
emits the sequence itself, including inside tmux/screen).
|
|
56
|
+
|
|
57
|
+
Implemented as a `Notification` hook with matcher
|
|
58
|
+
`agent_completed|agent_needs_input|permission_prompt` invoking `scripts/notify.mjs`,
|
|
59
|
+
which reads the payload from stdin and prints the OSC sequence for the detected
|
|
60
|
+
terminal (Kitty OSC 99, iTerm2/Windows Terminal OSC 9, default urxvt/Ghostty/Warp
|
|
61
|
+
OSC 777 — same detection as the pi `notify` extension). The Notification matcher
|
|
62
|
+
is an **exact-string list** over the `notification_type` field; there are no
|
|
63
|
+
`success`/`error` types (an earlier draft used that matcher, which silently never
|
|
64
|
+
fired). The documented types are `permission_prompt`, `idle_prompt`, `auth_success`,
|
|
65
|
+
`elicitation_dialog`, `elicitation_url_dialog`, `elicitation_complete`,
|
|
66
|
+
`elicitation_response`, `agent_needs_input`, `agent_completed`,
|
|
67
|
+
`quota_auto_resume_fired`, `quota_auto_resume_stale`, `quota_auto_resume_disabled`
|
|
68
|
+
(the `agent_*` types require Claude Code v2.1.198+, the `quota_auto_resume_*`
|
|
69
|
+
types v2.1.234+). The selection maps to pi's "task completed / failed / needs
|
|
70
|
+
approval" semantics: `agent_completed` covers completion and failure ("finishes
|
|
71
|
+
or fails"), `agent_needs_input` covers a background session waiting on input, and
|
|
72
|
+
`permission_prompt` covers an awaited approval. Explicitly excluded as noise:
|
|
73
|
+
`idle_prompt` (fires ~60s after every turn you don't answer within a minute — a
|
|
74
|
+
desktop ping on every pause), `auth_success` and `quota_auto_resume_*` (not task
|
|
75
|
+
events), and `elicitation_*` (dialog trivia). Skipped from the pi original: the LLM
|
|
76
|
+
response summary (Claude's notification message is already the summary) and the tmux
|
|
77
|
+
session:window.pane title (unavailable to hooks; the plugin title suffices).
|
|
78
|
+
|
|
79
|
+
## `skill-stats/` → Reject (no equivalent)
|
|
80
|
+
|
|
81
|
+
pi tracks skills loaded into the system prompt, `/skill:` invocations, SKILL.md
|
|
82
|
+
reads, and turns, exposing a `/skill-stats` query. Claude Code exposes none of
|
|
83
|
+
the required observability to hooks:
|
|
84
|
+
|
|
85
|
+
- **No "loaded" event** — nothing fires when a skill enters context, and hooks
|
|
86
|
+
never see system-prompt contents, so the primary "loaded" metric has no source.
|
|
87
|
+
- **Partial invocation/read observability only** — `PreToolUse` on the `Skill`
|
|
88
|
+
tool and `UserPromptExpansion` on slash commands would approximate
|
|
89
|
+
invocations, and `PostToolUse` on `Read` would approximate skill reads, but
|
|
90
|
+
the signals are fuzzy (Read covers any file; direct `/skill` typing bypasses
|
|
91
|
+
`PreToolUse`).
|
|
92
|
+
- **No query surface** — Claude Code plugin commands are markdown files, not
|
|
93
|
+
scripts, so there is no equivalent of the pi `/skill-stats` command, and
|
|
94
|
+
persistent state would live outside the plugin model.
|
|
95
|
+
|
|
96
|
+
A half-observable port would diverge from the pi semantics and add moving parts
|
|
97
|
+
for little signal. Rejected; Claude Code ships its own usage analytics
|
|
98
|
+
(`/usage`, sessions list, statsig) if insights are needed.
|
|
99
|
+
|
|
100
|
+
## `subagent/` → Reject (native)
|
|
101
|
+
|
|
102
|
+
pi's `subagent` tool spawns isolated `pi --mode json` processes. Claude Code has
|
|
103
|
+
native subagents — the plugin already ships `claude/agents/*.md` (including
|
|
104
|
+
`ralph`, `plan`, `strategy`, `ralph-plan`) executed via the built-in Agent/Task
|
|
105
|
+
tools with per-session context isolation — so a hook-based workaround would be
|
|
106
|
+
strictly worse.
|
|
107
|
+
|
|
108
|
+
## `agent-modes/` → Reject (no equivalent)
|
|
109
|
+
|
|
110
|
+
pi switches system prompts + tool restrictions at runtime with a TUI mode
|
|
111
|
+
selector. Claude Code exposes no hook or settings surface for dynamic
|
|
112
|
+
tool-restriction/prompt-switching of the main agent; the closest equivalents are
|
|
113
|
+
native (permission modes like plan mode configured via settings, and subagents
|
|
114
|
+
— already covered above). The `--agent <name>` start flag is covered by
|
|
115
|
+
`claude --agent` in newer versions. Rejected.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Idea: Auto-Model Selection Plugin
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
Backlog idea (not implementation-ready) — **direction: evaluate and adopt existing package**
|
|
5
|
+
|
|
6
|
+
## Why it might be useful
|
|
7
|
+
PI has no intelligent model selection. Users must manually choose models, which means they either over-provision (expensive models for simple tasks) or under-provision (weak models for complex work). Rate limits hit without warning, forcing manual model switching mid-session. An auto-selection plugin would optimize cost/performance by matching model capability to task complexity, and provide seamless fallbacks when rate limits are hit.
|
|
8
|
+
|
|
9
|
+
## How we might do it
|
|
10
|
+
**Evaluate and adopt an existing PI extension** rather than building from scratch. The ecosystem already has well-maintained packages that cover task-based routing and rate-limit fallbacks. The goal is to:
|
|
11
|
+
|
|
12
|
+
1. **Evaluate the top candidates** (see "Packages to evaluate" below)
|
|
13
|
+
2. **Pick the best fit** for agent-cortex's workflow (beads, pipeline stages, HITL/AFK classification)
|
|
14
|
+
3. **Install and configure** it, possibly with light customisation if needed
|
|
15
|
+
4. **Document** the chosen package and configuration in agent-cortex docs
|
|
16
|
+
|
|
17
|
+
## Packages to evaluate (in priority order)
|
|
18
|
+
**Top candidates — cover both task-based routing AND fallbacks:**
|
|
19
|
+
1. **`@kylebrodeur/pi-model-router`** — per-turn routing to high/medium/low tiers based on task intent, context size, budget, with automatic fallback chains and rate-limit recovery. Well-documented fork of yeliu84's original.
|
|
20
|
+
2. **`pi-auto-router`** — multi-provider routing with same-request failover, budget-aware policies, and quota-aware fallback.
|
|
21
|
+
3. **`pi-tiered-router`** — routes different *phases* (planner/validator/executor/tool-parser) to different models. Quality-first, not cost-saving.
|
|
22
|
+
|
|
23
|
+
**Fallback-only (simpler, if routing is overkill):**
|
|
24
|
+
- **`pi-auto-models`** — Claude→Codex quota switching with 429/529 recovery
|
|
25
|
+
- **`pi-provider-fallback`** — cross-provider fallback chain with TUI config
|
|
26
|
+
|
|
27
|
+
**Evaluation criteria:**
|
|
28
|
+
- Does it integrate cleanly with PI's existing provider/model system?
|
|
29
|
+
- Does it respect user's explicit model choice, or override it?
|
|
30
|
+
- How does it handle context window mismatches on fallback?
|
|
31
|
+
- Is it configurable per-project?
|
|
32
|
+
- Does it have fallback chains or just single fallback?
|
|
33
|
+
- Rate-limit detection and retry logic
|
|
34
|
+
- Documentation quality and maintenance status
|
|
35
|
+
|
|
36
|
+
## When to think about it
|
|
37
|
+
- After current feature stabilisation (refactor-to-template epic, npm publishing, system prompt improvements)
|
|
38
|
+
- Not blocked, but benefits from stable extension infrastructure
|
|
39
|
+
|
|
40
|
+
## Priority
|
|
41
|
+
Medium / backlog — valuable for cost optimisation and reliability, but not urgent. Current manual model selection works, just isn't optimal.
|
|
42
|
+
|
|
43
|
+
## Open questions
|
|
44
|
+
- How to classify task complexity? Heuristics (file count, prompt length, keywords)? Or let user tag tasks?
|
|
45
|
+
- What defines a "model class"? Cost tier, context window size, reasoning capability, speed?
|
|
46
|
+
- Should the plugin override the user's explicit model choice, or only activate when no model is selected?
|
|
47
|
+
- How to handle context window mismatches when falling back (e.g., 200k → 128k)?
|
|
48
|
+
- Should this be configurable per-project (different policies for different repos)?
|
|
49
|
+
|
|
50
|
+
## Existing packages in the ecosystem
|
|
51
|
+
Several published packages already address parts of this problem:
|
|
52
|
+
|
|
53
|
+
### Fallback / rate-limit recovery
|
|
54
|
+
- **`pi-provider-fallback`** — cross-provider fallback with interactive TUI config
|
|
55
|
+
- **`pi-auto-models`** — primary/fallback switching on quota (Claude→Codex default), 429/529 recovery
|
|
56
|
+
|
|
57
|
+
### Task-based / tier routing
|
|
58
|
+
- **`pi-model-router`** (yeliu84, forked by @kdejaeger and @kylebrodeur) — per-turn routing to high/medium/low tiers based on task intent, context size, budget, with automatic fallbacks
|
|
59
|
+
- **`pi-model-auto`** — routes by Low/Medium/High/Ultra capability modes per turn
|
|
60
|
+
- **`pi-tiered-router`** — routes different phases (planner/validator/executor/tool-parser) to different models
|
|
61
|
+
|
|
62
|
+
### Full auto-router with failover
|
|
63
|
+
- **`pi-auto-router`** — multi-provider routing with same-request failover, budget-aware policies
|
|
64
|
+
- **`@ifi/pi-extension-adaptive-routing`** — adaptive routing with local telemetry persistence
|
|
65
|
+
|
|
66
|
+
### Model selection (manual)
|
|
67
|
+
- **`pi-model-switch`** — direct model switching tool
|
|
68
|
+
- **`pi-model-select`** — `/select-model` with favourites and fuzzy search
|
|
69
|
+
|
|
70
|
+
## Notes
|
|
71
|
+
- **The ecosystem is active** — this space is already well-served. Before building, evaluate whether an existing package (especially `pi-model-router` or `pi-auto-router`) already meets the need.
|
|
72
|
+
- **Gap analysis needed**: compare existing packages against the original requirements (task-based class selection + rate-limit fallbacks) to see if anything is genuinely missing.
|
|
73
|
+
- **Partial solutions exist in PI core**: OpenRouter's routing config supports fallbacks and provider ordering, but only within OpenRouter. Cross-provider fallback requires an extension.
|
|
74
|
+
- **Implementation approach** (if building): likely a PI extension that registers a "smart-router" provider, which internally delegates to real providers based on task classification and availability.
|
|
75
|
+
- **Research done**: reviewed PI docs on providers, models, and extensions. Searched npm and pi.dev for existing packages.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Idea: extension-manifests
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
Backlog idea (not implementation-ready)
|
|
5
|
+
|
|
6
|
+
## Created
|
|
7
|
+
2026-08-25
|
|
8
|
+
|
|
9
|
+
## Problem
|
|
10
|
+
PI extensions and Claude/Copilot plugins are installed individually (`pi install <ext>`) and
|
|
11
|
+
live implicit in the machine's state (`~/.pi/agent/extensions/`) with no declared manifest of
|
|
12
|
+
what the author uses or where it came from. A fresh machine, clean `~/.pi`, or a failed update
|
|
13
|
+
leaves the environment without the expected extensions. The toolset isn't reproducible and
|
|
14
|
+
isn't documented anywhere in the author's repos. Experimenting with an extension (install, try,
|
|
15
|
+
remove) is also all manual, and there's no way to uninstall cleanly.
|
|
16
|
+
|
|
17
|
+
## Who benefits
|
|
18
|
+
The author. Installing/updating agent-cortex becomes a reliable way to restore a known PI +
|
|
19
|
+
Claude environment (agent-cortex + declared extensions in one step). The manifests document and
|
|
20
|
+
reproduce the toolset across machines. A prune CLI makes extension experimentation fast and safe.
|
|
21
|
+
|
|
22
|
+
## Proposed outcome
|
|
23
|
+
agent-cortex ships **committed extension manifests** (reviewed and stored on GitHub) declaring
|
|
24
|
+
which extensions to install — **per harness**: one manifest for PI extensions, one for
|
|
25
|
+
Claude/Copilot plugins. On install or update of agent-cortex, it reads the manifests and
|
|
26
|
+
installs the declared extensions. The manifests are the single source of truth.
|
|
27
|
+
|
|
28
|
+
Key decisions from the interview:
|
|
29
|
+
|
|
30
|
+
1. **No monitoring** — nothing observes installs, and the CLI never writes the manifests.
|
|
31
|
+
Adding an extension = edit the manifest, commit it, ship it. This keeps the source of truth
|
|
32
|
+
in GitHub where it belongs (and gets the usual PR/review flow).
|
|
33
|
+
2. **Per-harness manifests** — separate records for the pi harness vs the Claude harness, each
|
|
34
|
+
carrying the extension source (git URL / package name) for that harness's installer. The
|
|
35
|
+
install-on-update path handles each harness with its own mechanism.
|
|
36
|
+
3. **Prune CLI with a TUI** — a CLI command (e.g. `agent-cortex ext prune`) opens an interactive
|
|
37
|
+
TUI listing locally-installed extensions; selecting one **uninstalls** it from the local
|
|
38
|
+
environment. Removing from the manifest is done manually on GitHub. This supports the
|
|
39
|
+
experimentation loop: install → try → prune locally, then curate the manifest separately.
|
|
40
|
+
|
|
41
|
+
agent-cortex's own bundled extensions (auto-discovered via `pi install`, e.g. `skill-stats`)
|
|
42
|
+
are deliberately excluded from the manifests — only third-party extensions are declared.
|
|
43
|
+
|
|
44
|
+
## Validity check
|
|
45
|
+
- Evidence we already have: agent-cortex already has an install surface to hang this on
|
|
46
|
+
(`pi install` package discovery for the pi harness, plus the existing `bin/agent-cortex.mjs`
|
|
47
|
+
install command and `postinstall` script). The repo already carries a `plugin.json` (Claude
|
|
48
|
+
harness) alongside `package.json` (pi harness), showing the per-harness split is natural.
|
|
49
|
+
- Riskiest assumption: that an automated install-on-update of declared extensions is safe and
|
|
50
|
+
desirable (auto-installing on every update could surprise, or fail mid-flight on a new
|
|
51
|
+
machine lacking auth/network). Also, the TUI prune needs the local extension store's shape
|
|
52
|
+
(`~/.pi/agent/extensions/` for pi; whatever Claude uses) to be introspectable.
|
|
53
|
+
- What would invalidate this idea: if auto-install-on-update proves too disruptive (better as
|
|
54
|
+
an explicit `agent-cortex ext install` command), or if the pi/Claude installers don't expose
|
|
55
|
+
the store in a way that supports listing + uninstall for the TUI.
|
|
56
|
+
|
|
57
|
+
## Constraints
|
|
58
|
+
- Manifests live in this repo, committed via the normal PR flow — the CLI never edits them.
|
|
59
|
+
- Install-on-update must be idempotent and safe to skip/fail gracefully (no hard breakage of
|
|
60
|
+
agent-cortex's own install on extension failure).
|
|
61
|
+
- Follow the repo's extension conventions where relevant (lightweight, no internal LLM calls).
|
|
62
|
+
- If any local data is persisted (e.g. prune history), write to `~/.pi/agent-cortex/`.
|
|
63
|
+
|
|
64
|
+
## Next validation step
|
|
65
|
+
Confirm the install surface for each harness: how `pi install <source>` works for the pi side,
|
|
66
|
+
and how Claude/Copilot plugins get installed, plus whether each store can be listed and
|
|
67
|
+
uninstalled programmatically (needed for the prune TUI). Then prototype the manifest + one
|
|
68
|
+
harness's install-on-update path.
|
|
69
|
+
|
|
70
|
+
## Notes
|
|
71
|
+
Recorded 2026-08-25. The idea was refined during the interview: initially framed as
|
|
72
|
+
"record the extensions I use" (observer-based), corrected to a **committed manifest** model —
|
|
73
|
+
recording happens by editing + committing, not by monitoring. Prune uninstalls locally only;
|
|
74
|
+
the manifest stays GitHub-managed. This idea is adjacent to `record-ideas-as-beads`: both make
|
|
75
|
+
agent-cortex the declared source of truth for the author's environment and workflow.
|