create-claude-cabinet 0.11.1 → 0.12.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/README.md +6 -4
- package/lib/cli.js +86 -6
- package/lib/db-setup.js +4 -10
- package/lib/settings-merge.js +29 -3
- package/package.json +1 -1
- package/templates/EXTENSIONS.md +2 -2
- package/templates/README.md +188 -448
- package/templates/briefing/_briefing-template.md +14 -7
- package/templates/cabinet/directives-project.yaml +32 -0
- package/templates/cabinet/prompt-guide.md +14 -3
- package/templates/hooks/omega-memory-guard.sh +83 -0
- package/templates/scripts/merge-findings.js +1 -1
- package/templates/scripts/pib-db-schema.sql +2 -2
- package/templates/scripts/{pib-db.js → pib-db.mjs} +12 -12
- package/templates/scripts/work-tracker-server.mjs +1 -1
- package/templates/skills/audit/SKILL.md +1 -1
- package/templates/skills/cabinet-cc-health/SKILL.md +1 -1
- package/templates/skills/cabinet-record-keeper/SKILL.md +46 -13
- package/templates/skills/debrief/SKILL.md +60 -43
- package/templates/skills/debrief/phases/close-work.md +4 -4
- package/templates/skills/debrief/phases/record-lessons.md +6 -7
- package/templates/skills/execute-plans/SKILL.md +2 -2
- package/templates/skills/onboard/phases/post-onboard-audit.md +1 -1
- package/templates/skills/onboard/phases/work-tracking.md +2 -2
- package/templates/skills/orient/SKILL.md +20 -8
- package/templates/skills/orient/phases/work-scan.md +4 -4
- package/templates/skills/plan/SKILL.md +2 -2
- package/templates/skills/plan/phases/overlap-check.md +1 -1
- package/templates/skills/plan/phases/work-tracker.md +3 -3
- package/templates/skills/triage-audit/SKILL.md +1 -1
- package/templates/skills/triage-audit/phases/apply-verdicts.md +1 -1
- package/templates/skills/triage-audit/phases/load-findings.md +1 -1
- package/templates/skills/work-tracker/SKILL.md +3 -3
- package/templates/hooks/stop-hook.md +0 -56
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Claude Cabinet
|
|
2
2
|
|
|
3
3
|
A cabinet of expert advisors for your Claude Code project. One command
|
|
4
|
-
gives Claude a memory,
|
|
4
|
+
gives Claude a memory, 27 domain experts, a planning process, and the
|
|
5
5
|
habit of starting sessions informed and ending them properly.
|
|
6
6
|
|
|
7
7
|
Built by a guy who'd rather talk to Claude than write code. Most of it
|
|
@@ -12,7 +12,7 @@ was built by Claude. I just complained until it worked.
|
|
|
12
12
|
Your project gets a cabinet — specialist advisors who each own a domain
|
|
13
13
|
and weigh in when their expertise matters:
|
|
14
14
|
|
|
15
|
-
- **Cabinet members** —
|
|
15
|
+
- **Cabinet members** — 27 domain experts (security, accessibility,
|
|
16
16
|
architecture, QA, etc.) who review your project and surface what
|
|
17
17
|
you'd miss alone
|
|
18
18
|
- **Briefings** — project context members read before weighing in
|
|
@@ -37,7 +37,9 @@ say `/onboard`. It'll interview you about your project and set everything
|
|
|
37
37
|
up based on your answers.
|
|
38
38
|
|
|
39
39
|
**New to this?** See [GETTING-STARTED.md](GETTING-STARTED.md) for a
|
|
40
|
-
step-by-step walkthrough.
|
|
40
|
+
step-by-step walkthrough. Then [WORKFLOW-GUIDE.md](WORKFLOW-GUIDE.md)
|
|
41
|
+
for how to use everything — when to plan, when to audit, what the
|
|
42
|
+
cabinet does for you, and how the system grows with your project.
|
|
41
43
|
|
|
42
44
|
### For developers
|
|
43
45
|
|
|
@@ -183,7 +185,7 @@ source code.
|
|
|
183
185
|
└── settings.json # hook configuration
|
|
184
186
|
|
|
185
187
|
scripts/
|
|
186
|
-
├── pib-db.
|
|
188
|
+
├── pib-db.mjs # work tracking CLI (if installed)
|
|
187
189
|
└── ... # triage tools (if audit installed)
|
|
188
190
|
|
|
189
191
|
.ccrc.json # installation metadata
|
package/lib/cli.js
CHANGED
|
@@ -163,6 +163,70 @@ function generateSkillIndex(projectDir) {
|
|
|
163
163
|
const skillsDir = path.join(projectDir, '.claude', 'skills');
|
|
164
164
|
if (!fs.existsSync(skillsDir)) return 0;
|
|
165
165
|
|
|
166
|
+
// Read project directive overlay if it exists
|
|
167
|
+
const projectDirectives = {};
|
|
168
|
+
const directivesFile = path.join(projectDir, '.claude', 'cabinet', 'directives-project.yaml');
|
|
169
|
+
if (fs.existsSync(directivesFile)) {
|
|
170
|
+
const dContent = fs.readFileSync(directivesFile, 'utf8');
|
|
171
|
+
// Parse simple YAML: top-level keys are member names, nested keys are
|
|
172
|
+
// standing-mandate (list) and directives (map)
|
|
173
|
+
let currentMember = null;
|
|
174
|
+
let inDirectives = false;
|
|
175
|
+
let currentDirectiveKey = null;
|
|
176
|
+
let currentDirectiveValue = '';
|
|
177
|
+
for (const line of dContent.split('\n')) {
|
|
178
|
+
if (/^\s*#/.test(line) || line.trim() === '') continue;
|
|
179
|
+
const indent = line.length - line.trimStart().length;
|
|
180
|
+
const content = line.trim();
|
|
181
|
+
|
|
182
|
+
// Flush previous directive value
|
|
183
|
+
if (currentDirectiveKey && indent <= 4 && !/^\s/.test(line.charAt(0)) || (indent <= 4 && currentDirectiveKey)) {
|
|
184
|
+
if (currentMember && currentDirectiveKey) {
|
|
185
|
+
if (!projectDirectives[currentMember]) projectDirectives[currentMember] = {};
|
|
186
|
+
if (!projectDirectives[currentMember].directives) projectDirectives[currentMember].directives = {};
|
|
187
|
+
projectDirectives[currentMember].directives[currentDirectiveKey] = currentDirectiveValue.trim();
|
|
188
|
+
}
|
|
189
|
+
currentDirectiveKey = null;
|
|
190
|
+
currentDirectiveValue = '';
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (indent === 0) {
|
|
194
|
+
// Top-level: member name
|
|
195
|
+
const m = content.match(/^(cabinet-[\w-]+):\s*$/);
|
|
196
|
+
if (m) {
|
|
197
|
+
currentMember = m[1];
|
|
198
|
+
projectDirectives[currentMember] = projectDirectives[currentMember] || {};
|
|
199
|
+
inDirectives = false;
|
|
200
|
+
}
|
|
201
|
+
} else if (indent === 2 && currentMember) {
|
|
202
|
+
const kv = content.match(/^([\w-]+):\s*(.*)$/);
|
|
203
|
+
if (kv) {
|
|
204
|
+
if (kv[1] === 'standing-mandate') {
|
|
205
|
+
// Parse [item1, item2] or item1, item2
|
|
206
|
+
const val = kv[2].replace(/^\[|\]$/g, '');
|
|
207
|
+
projectDirectives[currentMember].standingMandate = val.split(/,\s*/).map(s => s.trim()).filter(Boolean);
|
|
208
|
+
inDirectives = false;
|
|
209
|
+
} else if (kv[1] === 'directives') {
|
|
210
|
+
inDirectives = true;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
} else if (indent === 4 && inDirectives && currentMember) {
|
|
214
|
+
const kv = content.match(/^([\w-]+):\s*(.*)$/);
|
|
215
|
+
if (kv) {
|
|
216
|
+
currentDirectiveKey = kv[1];
|
|
217
|
+
currentDirectiveValue = kv[2].replace(/^[>|]\s*$/, '');
|
|
218
|
+
}
|
|
219
|
+
} else if (indent >= 6 && currentDirectiveKey) {
|
|
220
|
+
currentDirectiveValue += ' ' + content;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// Flush last directive
|
|
224
|
+
if (currentMember && currentDirectiveKey) {
|
|
225
|
+
if (!projectDirectives[currentMember].directives) projectDirectives[currentMember].directives = {};
|
|
226
|
+
projectDirectives[currentMember].directives[currentDirectiveKey] = currentDirectiveValue.trim();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
166
230
|
const entries = [];
|
|
167
231
|
const dirs = fs.readdirSync(skillsDir, { withFileTypes: true });
|
|
168
232
|
for (const dir of dirs) {
|
|
@@ -202,6 +266,21 @@ function generateSkillIndex(projectDir) {
|
|
|
202
266
|
entry.directives = fm.directives;
|
|
203
267
|
}
|
|
204
268
|
|
|
269
|
+
// Merge project directive overlay (if any)
|
|
270
|
+
const overlay = projectDirectives[dir.name];
|
|
271
|
+
if (overlay) {
|
|
272
|
+
// Append project standing mandates (union, no duplicates)
|
|
273
|
+
if (overlay.standingMandate) {
|
|
274
|
+
const existing = entry.standingMandate || [];
|
|
275
|
+
const merged = [...new Set([...existing, ...overlay.standingMandate])];
|
|
276
|
+
entry.standingMandate = merged;
|
|
277
|
+
}
|
|
278
|
+
// Merge project directives (project wins on conflict)
|
|
279
|
+
if (overlay.directives) {
|
|
280
|
+
entry.directives = { ...(entry.directives || {}), ...overlay.directives };
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
205
284
|
entries.push(entry);
|
|
206
285
|
}
|
|
207
286
|
|
|
@@ -225,7 +304,7 @@ const MODULES = {
|
|
|
225
304
|
name: 'Session Loop (orient + debrief)',
|
|
226
305
|
description: 'The briefing cycle. Claude starts each session informed, ends by preparing the next briefing.',
|
|
227
306
|
mandatory: true,
|
|
228
|
-
templates: ['skills/orient', 'skills/orient-quick', 'skills/debrief', 'skills/debrief-quick', 'skills/debrief/phases/upstream-feedback.md', 'skills/menu'
|
|
307
|
+
templates: ['skills/orient', 'skills/orient-quick', 'skills/debrief', 'skills/debrief-quick', 'skills/debrief/phases/upstream-feedback.md', 'skills/menu'],
|
|
229
308
|
},
|
|
230
309
|
'hooks': {
|
|
231
310
|
name: 'Git Guardrails + Telemetry',
|
|
@@ -241,7 +320,7 @@ const MODULES = {
|
|
|
241
320
|
mandatory: false,
|
|
242
321
|
default: true,
|
|
243
322
|
lean: false,
|
|
244
|
-
templates: ['scripts/pib-db.
|
|
323
|
+
templates: ['scripts/pib-db.mjs', 'scripts/pib-db-schema.sql', 'scripts/work-tracker-server.mjs', 'scripts/work-tracker-ui.html', 'skills/work-tracker'],
|
|
245
324
|
needsDb: true,
|
|
246
325
|
},
|
|
247
326
|
'planning': {
|
|
@@ -311,7 +390,7 @@ const MODULES = {
|
|
|
311
390
|
default: true,
|
|
312
391
|
lean: false,
|
|
313
392
|
needsOmega: true,
|
|
314
|
-
templates: ['skills/memory', 'scripts/cabinet-memory-adapter.py', 'rules/memory-capture.md'],
|
|
393
|
+
templates: ['skills/memory', 'scripts/cabinet-memory-adapter.py', 'rules/memory-capture.md', 'hooks/omega-memory-guard.sh'],
|
|
315
394
|
},
|
|
316
395
|
};
|
|
317
396
|
|
|
@@ -542,7 +621,7 @@ async function run() {
|
|
|
542
621
|
selectedModules = Object.keys(MODULES);
|
|
543
622
|
if (flags.noDb) {
|
|
544
623
|
includeDb = false;
|
|
545
|
-
// work-tracking templates are still copied (pib-db.
|
|
624
|
+
// work-tracking templates are still copied (pib-db.mjs, schema) but
|
|
546
625
|
// the DB isn't initialized. Mark it as skipped so /onboard knows
|
|
547
626
|
// to ask about the alternative work tracking system.
|
|
548
627
|
selectedModules = selectedModules.filter(m => m !== 'work-tracking');
|
|
@@ -766,7 +845,8 @@ async function run() {
|
|
|
766
845
|
|
|
767
846
|
// --- Merge hooks into settings.json ---
|
|
768
847
|
if (selectedModules.includes('hooks') && !flags.dryRun) {
|
|
769
|
-
const
|
|
848
|
+
const includeMemory = selectedModules.includes('memory');
|
|
849
|
+
const settingsPath = mergeSettings(projectDir, { includeDb, includeMemory });
|
|
770
850
|
console.log(` ⚙️ Merged hooks into ${path.relative(projectDir, settingsPath)}`);
|
|
771
851
|
}
|
|
772
852
|
|
|
@@ -777,7 +857,7 @@ async function run() {
|
|
|
777
857
|
for (const r of dbResults) console.log(` 🗄️ ${r}`);
|
|
778
858
|
} catch (err) {
|
|
779
859
|
console.log(` ⚠ Database setup failed: ${err.message}`);
|
|
780
|
-
console.log(' You can set it up later: node scripts/pib-db.
|
|
860
|
+
console.log(' You can set it up later: node scripts/pib-db.mjs init');
|
|
781
861
|
}
|
|
782
862
|
}
|
|
783
863
|
|
package/lib/db-setup.js
CHANGED
|
@@ -4,7 +4,7 @@ const path = require('path');
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Set up the PIB database in the target project.
|
|
7
|
-
* - Copies pib-db.
|
|
7
|
+
* - Copies pib-db.mjs and schema to scripts/
|
|
8
8
|
* - Runs npm init if no package.json
|
|
9
9
|
* - Installs better-sqlite3
|
|
10
10
|
* - Runs pib-db init
|
|
@@ -21,14 +21,8 @@ function setupDb(projectDir) {
|
|
|
21
21
|
results.push('Created package.json');
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
// pib-db.
|
|
25
|
-
//
|
|
26
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
27
|
-
if (pkg.type !== 'module' && pkg.name !== 'create-claude-cabinet') {
|
|
28
|
-
pkg.type = 'module';
|
|
29
|
-
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
|
|
30
|
-
results.push('Set package.json type to "module"');
|
|
31
|
-
}
|
|
24
|
+
// pib-db.mjs uses ESM imports — .mjs extension lets Node treat it as ESM
|
|
25
|
+
// regardless of the project's package.json type field
|
|
32
26
|
|
|
33
27
|
// Install better-sqlite3 if not already installed
|
|
34
28
|
const nodeModules = path.join(projectDir, 'node_modules', 'better-sqlite3');
|
|
@@ -39,7 +33,7 @@ function setupDb(projectDir) {
|
|
|
39
33
|
}
|
|
40
34
|
|
|
41
35
|
// Initialize the database
|
|
42
|
-
const dbScript = path.join(scriptsDir, 'pib-db.
|
|
36
|
+
const dbScript = path.join(scriptsDir, 'pib-db.mjs');
|
|
43
37
|
if (fs.existsSync(dbScript)) {
|
|
44
38
|
console.log(' Initializing database...');
|
|
45
39
|
execSync(`node ${dbScript} init`, { cwd: projectDir, stdio: 'pipe' });
|
package/lib/settings-merge.js
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
|
|
4
|
+
const MEMORY_HOOKS = {
|
|
5
|
+
PreToolUse: [
|
|
6
|
+
{
|
|
7
|
+
matcher: 'Edit|Write',
|
|
8
|
+
hooks: [
|
|
9
|
+
{
|
|
10
|
+
type: 'command',
|
|
11
|
+
command: '.claude/hooks/omega-memory-guard.sh',
|
|
12
|
+
},
|
|
13
|
+
],
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
};
|
|
17
|
+
|
|
4
18
|
const DEFAULT_HOOKS = {
|
|
5
19
|
PreToolUse: [
|
|
6
20
|
{
|
|
@@ -50,7 +64,7 @@ const DEFAULT_HOOKS = {
|
|
|
50
64
|
* Merge PIB hooks into the project's .claude/settings.json.
|
|
51
65
|
* Creates the file if it doesn't exist. Preserves existing hooks.
|
|
52
66
|
*/
|
|
53
|
-
function mergeSettings(projectDir, { includeDb = true } = {}) {
|
|
67
|
+
function mergeSettings(projectDir, { includeDb = true, includeMemory = false } = {}) {
|
|
54
68
|
const settingsDir = path.join(projectDir, '.claude');
|
|
55
69
|
const settingsPath = path.join(settingsDir, 'settings.json');
|
|
56
70
|
|
|
@@ -81,8 +95,20 @@ function mergeSettings(projectDir, { includeDb = true } = {}) {
|
|
|
81
95
|
});
|
|
82
96
|
}
|
|
83
97
|
|
|
98
|
+
// Build the full hook set — include memory hooks if memory module is selected
|
|
99
|
+
const allHooks = { ...DEFAULT_HOOKS };
|
|
100
|
+
if (includeMemory) {
|
|
101
|
+
for (const [event, hooks] of Object.entries(MEMORY_HOOKS)) {
|
|
102
|
+
if (!allHooks[event]) {
|
|
103
|
+
allHooks[event] = hooks;
|
|
104
|
+
} else {
|
|
105
|
+
allHooks[event] = [...allHooks[event], ...hooks];
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
84
110
|
// Merge each hook event type
|
|
85
|
-
for (const [event, newHooks] of Object.entries(
|
|
111
|
+
for (const [event, newHooks] of Object.entries(allHooks)) {
|
|
86
112
|
if (!settings.hooks[event]) {
|
|
87
113
|
settings.hooks[event] = newHooks;
|
|
88
114
|
} else {
|
|
@@ -106,4 +132,4 @@ function mergeSettings(projectDir, { includeDb = true } = {}) {
|
|
|
106
132
|
return settingsPath;
|
|
107
133
|
}
|
|
108
134
|
|
|
109
|
-
module.exports = { mergeSettings, DEFAULT_HOOKS };
|
|
135
|
+
module.exports = { mergeSettings, DEFAULT_HOOKS, MEMORY_HOOKS };
|
package/package.json
CHANGED
package/templates/EXTENSIONS.md
CHANGED
|
@@ -226,8 +226,8 @@ command queue processing (needed by any project with an async work queue).
|
|
|
226
226
|
|
|
227
227
|
## Writing Domain-Specific Cabinet Members
|
|
228
228
|
|
|
229
|
-
CC ships
|
|
230
|
-
cabinet members. Here are three examples showing how to write your own.
|
|
229
|
+
CC ships 27 generic cabinet members. Your project can add domain-specific
|
|
230
|
+
cabinet members on top of these. Here are three examples showing how to write your own.
|
|
231
231
|
|
|
232
232
|
### Example 1: GTD (encoding domain expertise)
|
|
233
233
|
|