@soleri/forge 5.2.0 → 5.4.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.
@@ -123,6 +123,29 @@ ${domainDescribes}
123
123
  if (stats.totalEntries === 0) {
124
124
  recommendations.push('Vault is empty');
125
125
  }
126
+ // Check hook status
127
+ const { readdirSync } = await import('node:fs');
128
+ const agentClaudeDir = joinPath(__dirname, '..', '.claude');
129
+ const globalClaudeDir = joinPath(homedir(), '.claude');
130
+ const hookStatus = { agent: [] as string[], global: [] as string[], missing: [] as string[] };
131
+ if (exists(agentClaudeDir)) {
132
+ try {
133
+ const agentHooks = readdirSync(agentClaudeDir)
134
+ .filter((f: string) => f.startsWith('hookify.') && f.endsWith('.local.md'))
135
+ .map((f: string) => f.replace('hookify.', '').replace('.local.md', ''));
136
+ hookStatus.agent = agentHooks;
137
+ for (const hook of agentHooks) {
138
+ if (exists(joinPath(globalClaudeDir, \`hookify.\${hook}.local.md\`))) {
139
+ hookStatus.global.push(hook);
140
+ } else {
141
+ hookStatus.missing.push(hook);
142
+ }
143
+ }
144
+ } catch { /* ignore */ }
145
+ }
146
+ if (hookStatus.missing.length > 0) {
147
+ recommendations.push(\`\${hookStatus.missing.length} hook(s) not installed globally — run scripts/setup.sh\`);
148
+ }
126
149
  if (recommendations.length === 0) {
127
150
  recommendations.push('${config.name} is fully set up and ready!');
128
151
  }
@@ -133,6 +156,7 @@ ${domainDescribes}
133
156
  global: { exists: exists(globalClaudeMd), has_agent_section: hasAgentMarker(globalClaudeMd) },
134
157
  },
135
158
  vault: { entries: stats.totalEntries, domains: Object.keys(stats.byDomain) },
159
+ hooks: hookStatus,
136
160
  recommendations,
137
161
  };
138
162
  },
@@ -169,6 +193,10 @@ ${domainDescribes}
169
193
  expect(opNames).toContain('brain_archive_sessions');
170
194
  expect(opNames).toContain('brain_promote_proposals');
171
195
  expect(opNames).toContain('brain_lifecycle');
196
+ // Enhanced brain ops (3)
197
+ expect(opNames).toContain('brain_feedback');
198
+ expect(opNames).toContain('brain_feedback_stats');
199
+ expect(opNames).toContain('brain_reset_extracted');
172
200
  // Agent-specific ops (5)
173
201
  expect(opNames).toContain('health');
174
202
  expect(opNames).toContain('identity');
@@ -184,8 +212,122 @@ ${domainDescribes}
184
212
  expect(opNames).toContain('route_intent');
185
213
  expect(opNames).toContain('morph');
186
214
  expect(opNames).toContain('get_behavior_rules');
187
- // Total: 50
188
- expect(facade.ops.length).toBe(50);
215
+ // Cognee ops (5)
216
+ expect(opNames).toContain('cognee_status');
217
+ expect(opNames).toContain('cognee_search');
218
+ expect(opNames).toContain('cognee_add');
219
+ expect(opNames).toContain('cognee_cognify');
220
+ expect(opNames).toContain('cognee_config');
221
+ // LLM ops (2)
222
+ expect(opNames).toContain('llm_rotate');
223
+ expect(opNames).toContain('llm_call');
224
+ // Governance ops (5)
225
+ expect(opNames).toContain('governance_policy');
226
+ expect(opNames).toContain('governance_proposals');
227
+ expect(opNames).toContain('governance_stats');
228
+ expect(opNames).toContain('governance_expire');
229
+ expect(opNames).toContain('governance_dashboard');
230
+ // Planning Extra ops (9)
231
+ expect(opNames).toContain('plan_iterate');
232
+ expect(opNames).toContain('plan_split');
233
+ expect(opNames).toContain('plan_reconcile');
234
+ expect(opNames).toContain('plan_complete_lifecycle');
235
+ expect(opNames).toContain('plan_dispatch');
236
+ expect(opNames).toContain('plan_review');
237
+ expect(opNames).toContain('plan_archive');
238
+ expect(opNames).toContain('plan_list_tasks');
239
+ expect(opNames).toContain('plan_stats');
240
+ // Memory Extra ops (8)
241
+ expect(opNames).toContain('memory_delete');
242
+ expect(opNames).toContain('memory_stats');
243
+ expect(opNames).toContain('memory_export');
244
+ expect(opNames).toContain('memory_import');
245
+ expect(opNames).toContain('memory_prune');
246
+ expect(opNames).toContain('memory_deduplicate');
247
+ expect(opNames).toContain('memory_topics');
248
+ expect(opNames).toContain('memory_by_project');
249
+ // Vault Extra ops (12)
250
+ expect(opNames).toContain('vault_get');
251
+ expect(opNames).toContain('vault_update');
252
+ expect(opNames).toContain('vault_remove');
253
+ expect(opNames).toContain('vault_bulk_add');
254
+ expect(opNames).toContain('vault_bulk_remove');
255
+ expect(opNames).toContain('vault_tags');
256
+ expect(opNames).toContain('vault_domains');
257
+ expect(opNames).toContain('vault_recent');
258
+ expect(opNames).toContain('vault_import');
259
+ expect(opNames).toContain('vault_seed');
260
+ expect(opNames).toContain('vault_backup');
261
+ expect(opNames).toContain('vault_age_report');
262
+ // Admin ops (8)
263
+ expect(opNames).toContain('admin_health');
264
+ expect(opNames).toContain('admin_tool_list');
265
+ expect(opNames).toContain('admin_config');
266
+ expect(opNames).toContain('admin_vault_size');
267
+ expect(opNames).toContain('admin_uptime');
268
+ expect(opNames).toContain('admin_version');
269
+ expect(opNames).toContain('admin_reset_cache');
270
+ expect(opNames).toContain('admin_diagnostic');
271
+ // Loop ops (7)
272
+ expect(opNames).toContain('loop_start');
273
+ expect(opNames).toContain('loop_iterate');
274
+ expect(opNames).toContain('loop_status');
275
+ expect(opNames).toContain('loop_cancel');
276
+ expect(opNames).toContain('loop_history');
277
+ expect(opNames).toContain('loop_is_active');
278
+ expect(opNames).toContain('loop_complete');
279
+ // Orchestrate ops (5)
280
+ expect(opNames).toContain('orchestrate_plan');
281
+ expect(opNames).toContain('orchestrate_execute');
282
+ expect(opNames).toContain('orchestrate_complete');
283
+ expect(opNames).toContain('orchestrate_status');
284
+ expect(opNames).toContain('orchestrate_quick_capture');
285
+ // Capture ops (4)
286
+ expect(opNames).toContain('capture_knowledge');
287
+ expect(opNames).toContain('capture_quick');
288
+ expect(opNames).toContain('search_intelligent');
289
+ expect(opNames).toContain('search_feedback');
290
+ // Grading ops (5)
291
+ expect(opNames).toContain('plan_grade');
292
+ expect(opNames).toContain('plan_check_history');
293
+ expect(opNames).toContain('plan_latest_check');
294
+ expect(opNames).toContain('plan_meets_grade');
295
+ expect(opNames).toContain('plan_auto_improve');
296
+ // Admin Extra ops (10)
297
+ expect(opNames).toContain('admin_telemetry');
298
+ expect(opNames).toContain('admin_telemetry_recent');
299
+ expect(opNames).toContain('admin_telemetry_reset');
300
+ expect(opNames).toContain('admin_permissions');
301
+ expect(opNames).toContain('admin_vault_analytics');
302
+ expect(opNames).toContain('admin_search_insights');
303
+ expect(opNames).toContain('admin_module_status');
304
+ expect(opNames).toContain('admin_env');
305
+ expect(opNames).toContain('admin_gc');
306
+ expect(opNames).toContain('admin_export_config');
307
+ // Curator Extra ops (4)
308
+ expect(opNames).toContain('curator_entry_history');
309
+ expect(opNames).toContain('curator_record_snapshot');
310
+ expect(opNames).toContain('curator_queue_stats');
311
+ expect(opNames).toContain('curator_enrich');
312
+ // Project ops (12)
313
+ expect(opNames).toContain('project_get');
314
+ expect(opNames).toContain('project_list');
315
+ expect(opNames).toContain('project_unregister');
316
+ expect(opNames).toContain('project_get_rules');
317
+ expect(opNames).toContain('project_list_rules');
318
+ expect(opNames).toContain('project_add_rule');
319
+ expect(opNames).toContain('project_remove_rule');
320
+ expect(opNames).toContain('project_link');
321
+ expect(opNames).toContain('project_unlink');
322
+ expect(opNames).toContain('project_get_links');
323
+ expect(opNames).toContain('project_linked_projects');
324
+ expect(opNames).toContain('project_touch');
325
+ // Cross-project memory ops (3)
326
+ expect(opNames).toContain('memory_promote_to_global');
327
+ expect(opNames).toContain('memory_configure');
328
+ expect(opNames).toContain('memory_cross_project_search');
329
+ // Total: 152 (147 core + 5 agent-specific)
330
+ expect(facade.ops.length).toBe(152);
189
331
  });
190
332
 
191
333
  it('search should query across all domains with ranked results', async () => {
@@ -277,7 +419,9 @@ ${domainDescribes}
277
419
  const setupOp = facade.ops.find((o) => o.name === 'setup')!;
278
420
  const result = (await setupOp.handler({ projectPath: '/tmp/nonexistent-test' })) as {
279
421
  agent: { name: string };
422
+ claude_md: { project: { exists: boolean; has_agent_section: boolean }; global: { exists: boolean; has_agent_section: boolean } };
280
423
  vault: { entries: number };
424
+ hooks: { agent: string[]; global: string[]; missing: string[] };
281
425
  recommendations: string[];
282
426
  };
283
427
  expect(result.agent.name).toBe('${escapeQuotes(config.name)}');
@@ -327,6 +471,32 @@ ${domainDescribes}
327
471
  const result = (await healthOp.handler({})) as { score: number };
328
472
  expect(result.score).toBeGreaterThan(0);
329
473
  });
474
+
475
+ it('governance_policy get should return default policy', async () => {
476
+ const facade = buildCoreFacade();
477
+ const policyOp = facade.ops.find((o) => o.name === 'governance_policy')!;
478
+ const result = (await policyOp.handler({ action: 'get', projectPath: '/test' })) as {
479
+ projectPath: string;
480
+ quotas: { maxEntriesTotal: number };
481
+ autoCapture: { enabled: boolean };
482
+ };
483
+ expect(result.projectPath).toBe('/test');
484
+ expect(result.quotas.maxEntriesTotal).toBe(500);
485
+ expect(result.autoCapture.enabled).toBe(true);
486
+ });
487
+
488
+ it('governance_dashboard should return combined view', async () => {
489
+ const facade = buildCoreFacade();
490
+ const dashOp = facade.ops.find((o) => o.name === 'governance_dashboard')!;
491
+ const result = (await dashOp.handler({ projectPath: '/test' })) as {
492
+ vaultSize: number;
493
+ quotaPercent: number;
494
+ pendingProposals: number;
495
+ };
496
+ expect(typeof result.vaultSize).toBe('number');
497
+ expect(typeof result.quotaPercent).toBe('number');
498
+ expect(result.pendingProposals).toBe(0);
499
+ });
330
500
  });
331
501
  });
332
502
  `;
@@ -382,7 +552,7 @@ function generateDomainDescribe(agentId, domain) {
382
552
  severity: 'warning',
383
553
  description: 'A captured pattern.',
384
554
  tags: ['captured'],
385
- })) as { captured: boolean };
555
+ })) as { captured: boolean; governance?: { action: string } };
386
556
  expect(result.captured).toBe(true);
387
557
  const entry = runtime.vault.get('${domain}-cap1');
388
558
  expect(entry).not.toBeNull();
@@ -1 +1 @@
1
- {"version":3,"file":"test-facades.js","sourceRoot":"","sources":["../../src/templates/test-facades.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAmB;IACrD,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO;SACnC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,sBAAsB,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;SAChD,IAAI,CAAC,MAAM,CAAC,CAAC;IAEhB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAmCS,MAAM,CAAC,EAAE;;;;;;;;;;;EAWzB,eAAe;;cAEH,MAAM,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sCAsEe,MAAM,CAAC,IAAI;;;;;;;;;;;;;;;iBAehC,MAAM,CAAC,EAAE;;;;;;;;kCAQQ,MAAM,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iDA8CM,MAAM,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mCAmCvB,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC;mCACzB,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC;;;;;;;;;;;0CAWlB,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;qCA0B9B,MAAM,CAAC,EAAE;;;;;;;;;;;;;;wCAcN,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiDhE,CAAC;AACF,CAAC;AAED,SAAS,sBAAsB,CAAC,OAAe,EAAE,MAAc;IAC7D,MAAM,UAAU,GAAG,GAAG,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;IAE7D,OAAO,eAAe,UAAU;;4CAEU,OAAO,OAAO,MAAM;;;;;kCAK9B,UAAU;;;;;;;;;iDASK,MAAM;;2BAE5B,MAAM,mBAAmB,MAAM;;;;;;kDAMR,MAAM;;;iCAGvB,MAAM;;2BAEZ,MAAM,kBAAkB,MAAM;;;;;;;wDAOD,MAAM;;;wCAGtB,MAAM;;;;eAI/B,MAAM;;;;;;;;yCAQoB,MAAM;;oCAEX,MAAM;;;;6CAIG,MAAM,mBAAmB,MAAM;;;gDAG5B,MAAM;gCACtB,MAAM;;;;6CAIO,MAAM,mBAAmB,MAAM;;;gDAG5B,MAAM;;kCAEpB,MAAM;;MAElC,CAAC;AACP,CAAC;AAED,SAAS,YAAY,CAAC,CAAS;IAC7B,OAAO,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AACvD,CAAC"}
1
+ {"version":3,"file":"test-facades.js","sourceRoot":"","sources":["../../src/templates/test-facades.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAmB;IACrD,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO;SACnC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,sBAAsB,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;SAChD,IAAI,CAAC,MAAM,CAAC,CAAC;IAEhB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAmCS,MAAM,CAAC,EAAE;;;;;;;;;;;EAWzB,eAAe;;cAEH,MAAM,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sCA6Fe,MAAM,CAAC,IAAI;;;;;;;;;;;;;;;;iBAgBhC,MAAM,CAAC,EAAE;;;;;;;;kCAQQ,MAAM,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iDAoKM,MAAM,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mCAmCvB,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC;mCACzB,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC;;;;;;;;;;;0CAWlB,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;qCA0B9B,MAAM,CAAC,EAAE;;;;;;;;;;;;;;;;wCAgBN,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2EhE,CAAC;AACF,CAAC;AAED,SAAS,sBAAsB,CAAC,OAAe,EAAE,MAAc;IAC7D,MAAM,UAAU,GAAG,GAAG,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;IAE7D,OAAO,eAAe,UAAU;;4CAEU,OAAO,OAAO,MAAM;;;;;kCAK9B,UAAU;;;;;;;;;iDASK,MAAM;;2BAE5B,MAAM,mBAAmB,MAAM;;;;;;kDAMR,MAAM;;;iCAGvB,MAAM;;2BAEZ,MAAM,kBAAkB,MAAM;;;;;;;wDAOD,MAAM;;;wCAGtB,MAAM;;;;eAI/B,MAAM;;;;;;;;yCAQoB,MAAM;;oCAEX,MAAM;;;;6CAIG,MAAM,mBAAmB,MAAM;;;gDAG5B,MAAM;gCACtB,MAAM;;;;6CAIO,MAAM,mBAAmB,MAAM;;;gDAG5B,MAAM;;kCAEpB,MAAM;;MAElC,CAAC;AACP,CAAC;AAED,SAAS,YAAY,CAAC,CAAS;IAC7B,OAAO,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AACvD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soleri/forge",
3
- "version": "5.2.0",
3
+ "version": "5.4.0",
4
4
  "description": "Scaffold AI agents that learn, remember, and grow with you.",
5
5
  "keywords": [
6
6
  "agent",
@@ -59,9 +59,9 @@ describe('Scaffolder', () => {
59
59
  expect(preview.facades).toHaveLength(4); // 3 domains + core
60
60
  expect(preview.facades[0].name).toBe('atlas_data_pipelines');
61
61
 
62
- // Core facade should list all 31 ops
62
+ // Core facade should list all 152 ops (147 core + 5 agent-specific)
63
63
  const coreFacade = preview.facades.find((f) => f.name === 'atlas_core')!;
64
- expect(coreFacade.ops.length).toBe(31);
64
+ expect(coreFacade.ops.length).toBe(152);
65
65
  expect(coreFacade.ops).toContain('curator_status');
66
66
  expect(coreFacade.ops).toContain('health');
67
67
 
package/src/scaffolder.ts CHANGED
@@ -77,6 +77,13 @@ export function previewScaffold(config: AgentConfig): ScaffoldPreview {
77
77
  },
78
78
  ];
79
79
 
80
+ if (config.hookPacks?.length) {
81
+ files.push({
82
+ path: '.claude/',
83
+ description: `Hook pack files (${config.hookPacks.join(', ')})`,
84
+ });
85
+ }
86
+
80
87
  const facades = [
81
88
  ...config.domains.map((d) => ({
82
89
  name: `${config.id}_${d.replace(/-/g, '_')}`,
@@ -85,7 +92,7 @@ export function previewScaffold(config: AgentConfig): ScaffoldPreview {
85
92
  {
86
93
  name: `${config.id}_core`,
87
94
  ops: [
88
- // From createCoreOps() — 26 generic ops
95
+ // From createCoreOps() — 144 generic ops
89
96
  'search',
90
97
  'vault_stats',
91
98
  'list_all',
@@ -101,9 +108,32 @@ export function previewScaffold(config: AgentConfig): ScaffoldPreview {
101
108
  'update_task',
102
109
  'complete_plan',
103
110
  'record_feedback',
111
+ 'brain_feedback',
112
+ 'brain_feedback_stats',
104
113
  'rebuild_vocabulary',
105
114
  'brain_stats',
106
115
  'llm_status',
116
+ 'brain_session_context',
117
+ 'brain_strengths',
118
+ 'brain_global_patterns',
119
+ 'brain_recommend',
120
+ 'brain_build_intelligence',
121
+ 'brain_export',
122
+ 'brain_import',
123
+ 'brain_extract_knowledge',
124
+ 'brain_archive_sessions',
125
+ 'brain_promote_proposals',
126
+ 'brain_lifecycle',
127
+ 'brain_reset_extracted',
128
+ // Cognee ops — 5
129
+ 'cognee_status',
130
+ 'cognee_search',
131
+ 'cognee_add',
132
+ 'cognee_cognify',
133
+ 'cognee_config',
134
+ // LLM ops — 2
135
+ 'llm_rotate',
136
+ 'llm_call',
107
137
  'curator_status',
108
138
  'curator_detect_duplicates',
109
139
  'curator_contradictions',
@@ -112,6 +142,119 @@ export function previewScaffold(config: AgentConfig): ScaffoldPreview {
112
142
  'curator_groom_all',
113
143
  'curator_consolidate',
114
144
  'curator_health_audit',
145
+ 'get_identity',
146
+ 'update_identity',
147
+ 'add_guideline',
148
+ 'remove_guideline',
149
+ 'rollback_identity',
150
+ 'route_intent',
151
+ 'morph',
152
+ 'get_behavior_rules',
153
+ // Governance ops — 5
154
+ 'governance_policy',
155
+ 'governance_proposals',
156
+ 'governance_stats',
157
+ 'governance_expire',
158
+ 'governance_dashboard',
159
+ // Planning Extra ops — 9
160
+ 'plan_iterate',
161
+ 'plan_split',
162
+ 'plan_reconcile',
163
+ 'plan_complete_lifecycle',
164
+ 'plan_dispatch',
165
+ 'plan_review',
166
+ 'plan_archive',
167
+ 'plan_list_tasks',
168
+ 'plan_stats',
169
+ // Memory Extra ops — 8
170
+ 'memory_delete',
171
+ 'memory_stats',
172
+ 'memory_export',
173
+ 'memory_import',
174
+ 'memory_prune',
175
+ 'memory_deduplicate',
176
+ 'memory_topics',
177
+ 'memory_by_project',
178
+ // Vault Extra ops — 12
179
+ 'vault_get',
180
+ 'vault_update',
181
+ 'vault_remove',
182
+ 'vault_bulk_add',
183
+ 'vault_bulk_remove',
184
+ 'vault_tags',
185
+ 'vault_domains',
186
+ 'vault_recent',
187
+ 'vault_import',
188
+ 'vault_seed',
189
+ 'vault_backup',
190
+ 'vault_age_report',
191
+ // Admin ops — 8
192
+ 'admin_health',
193
+ 'admin_tool_list',
194
+ 'admin_config',
195
+ 'admin_vault_size',
196
+ 'admin_uptime',
197
+ 'admin_version',
198
+ 'admin_reset_cache',
199
+ 'admin_diagnostic',
200
+ // Loop ops — 7
201
+ 'loop_start',
202
+ 'loop_iterate',
203
+ 'loop_status',
204
+ 'loop_cancel',
205
+ 'loop_history',
206
+ 'loop_is_active',
207
+ 'loop_complete',
208
+ // Orchestrate ops — 5
209
+ 'orchestrate_plan',
210
+ 'orchestrate_execute',
211
+ 'orchestrate_complete',
212
+ 'orchestrate_status',
213
+ 'orchestrate_quick_capture',
214
+ // Grading ops — 5
215
+ 'plan_grade',
216
+ 'plan_check_history',
217
+ 'plan_latest_check',
218
+ 'plan_meets_grade',
219
+ 'plan_auto_improve',
220
+ // Capture ops — 4
221
+ 'capture_knowledge',
222
+ 'capture_quick',
223
+ 'search_intelligent',
224
+ 'search_feedback',
225
+ // Admin Extra ops — 10
226
+ 'admin_telemetry',
227
+ 'admin_telemetry_recent',
228
+ 'admin_telemetry_reset',
229
+ 'admin_permissions',
230
+ 'admin_vault_analytics',
231
+ 'admin_search_insights',
232
+ 'admin_module_status',
233
+ 'admin_env',
234
+ 'admin_gc',
235
+ 'admin_export_config',
236
+ // Curator Extra ops — 4
237
+ 'curator_entry_history',
238
+ 'curator_record_snapshot',
239
+ 'curator_queue_stats',
240
+ 'curator_enrich',
241
+ // Project ops — 12
242
+ 'project_get',
243
+ 'project_list',
244
+ 'project_unregister',
245
+ 'project_get_rules',
246
+ 'project_list_rules',
247
+ 'project_add_rule',
248
+ 'project_remove_rule',
249
+ 'project_link',
250
+ 'project_unlink',
251
+ 'project_get_links',
252
+ 'project_linked_projects',
253
+ 'project_touch',
254
+ // Cross-project memory ops — 3
255
+ 'memory_promote_to_global',
256
+ 'memory_configure',
257
+ 'memory_cross_project_search',
115
258
  // Agent-specific ops — 5
116
259
  'health',
117
260
  'identity',
@@ -160,6 +303,10 @@ export function scaffold(config: AgentConfig): ScaffoldResult {
160
303
  'src/__tests__',
161
304
  ];
162
305
 
306
+ if (config.hookPacks?.length) {
307
+ dirs.push('.claude');
308
+ }
309
+
163
310
  for (const dir of dirs) {
164
311
  mkdirSync(join(agentDir, dir), { recursive: true });
165
312
  }
@@ -211,7 +358,7 @@ export function scaffold(config: AgentConfig): ScaffoldResult {
211
358
  filesCreated.push(path);
212
359
  }
213
360
 
214
- const totalOps = config.domains.length * 5 + 31; // 5 per domain + 26 core (from createCoreOps) + 5 agent-specific
361
+ const totalOps = config.domains.length * 5 + 61; // 5 per domain + 56 core (from createCoreOps) + 5 agent-specific
215
362
 
216
363
  // Register the agent as an MCP server in ~/.claude.json
217
364
  const mcpReg = registerMcpServer(config.id, agentDir);
@@ -225,6 +372,10 @@ export function scaffold(config: AgentConfig): ScaffoldResult {
225
372
  `1 test suite — facades (vault, brain, planner, llm tests provided by @soleri/core)`,
226
373
  ];
227
374
 
375
+ if (config.hookPacks?.length) {
376
+ summaryLines.push(`${config.hookPacks.length} hook pack(s) bundled in .claude/`);
377
+ }
378
+
228
379
  if (mcpReg.registered) {
229
380
  summaryLines.push(`MCP server registered in ${mcpReg.path}`);
230
381
  } else {
@@ -57,6 +57,9 @@ export function generateClaudeMdTemplate(config: AgentConfig): string {
57
57
  `| Session capture | ${bt}${toolPrefix}_core${bt} | ${bt}session_capture${bt} |`,
58
58
  `| Export knowledge | ${bt}${toolPrefix}_core${bt} | ${bt}export${bt} |`,
59
59
  `| Record feedback | ${bt}${toolPrefix}_core${bt} | ${bt}record_feedback${bt} |`,
60
+ `| Enhanced feedback | ${bt}${toolPrefix}_core${bt} | ${bt}brain_feedback${bt} |`,
61
+ `| Feedback stats | ${bt}${toolPrefix}_core${bt} | ${bt}brain_feedback_stats${bt} |`,
62
+ `| Reset extracted | ${bt}${toolPrefix}_core${bt} | ${bt}brain_reset_extracted${bt} |`,
60
63
  `| Rebuild vocabulary | ${bt}${toolPrefix}_core${bt} | ${bt}rebuild_vocabulary${bt} |`,
61
64
  `| Brain stats | ${bt}${toolPrefix}_core${bt} | ${bt}brain_stats${bt} |`,
62
65
  `| LLM status | ${bt}${toolPrefix}_core${bt} | ${bt}llm_status${bt} |`,
@@ -73,6 +76,117 @@ export function generateClaudeMdTemplate(config: AgentConfig): string {
73
76
  `| Add guideline | ${bt}${toolPrefix}_core${bt} | ${bt}add_guideline${bt} |`,
74
77
  `| Remove guideline | ${bt}${toolPrefix}_core${bt} | ${bt}remove_guideline${bt} |`,
75
78
  `| Rollback identity | ${bt}${toolPrefix}_core${bt} | ${bt}rollback_identity${bt} |`,
79
+ `| Cognee status | ${bt}${toolPrefix}_core${bt} | ${bt}cognee_status${bt} |`,
80
+ `| Cognee search | ${bt}${toolPrefix}_core${bt} | ${bt}cognee_search${bt} |`,
81
+ `| Cognee add | ${bt}${toolPrefix}_core${bt} | ${bt}cognee_add${bt} |`,
82
+ `| Cognee cognify | ${bt}${toolPrefix}_core${bt} | ${bt}cognee_cognify${bt} |`,
83
+ `| Cognee config | ${bt}${toolPrefix}_core${bt} | ${bt}cognee_config${bt} |`,
84
+ `| LLM rotate key | ${bt}${toolPrefix}_core${bt} | ${bt}llm_rotate${bt} |`,
85
+ `| LLM call | ${bt}${toolPrefix}_core${bt} | ${bt}llm_call${bt} |`,
86
+ `| Governance policy | ${bt}${toolPrefix}_core${bt} | ${bt}governance_policy${bt} |`,
87
+ `| Governance proposals | ${bt}${toolPrefix}_core${bt} | ${bt}governance_proposals${bt} |`,
88
+ `| Governance stats | ${bt}${toolPrefix}_core${bt} | ${bt}governance_stats${bt} |`,
89
+ `| Expire proposals | ${bt}${toolPrefix}_core${bt} | ${bt}governance_expire${bt} |`,
90
+ `| Governance dashboard | ${bt}${toolPrefix}_core${bt} | ${bt}governance_dashboard${bt} |`,
91
+ // Planning Extra ops
92
+ `| Iterate plan | ${bt}${toolPrefix}_core${bt} | ${bt}plan_iterate${bt} |`,
93
+ `| Split plan tasks | ${bt}${toolPrefix}_core${bt} | ${bt}plan_split${bt} |`,
94
+ `| Reconcile plan | ${bt}${toolPrefix}_core${bt} | ${bt}plan_reconcile${bt} |`,
95
+ `| Complete lifecycle | ${bt}${toolPrefix}_core${bt} | ${bt}plan_complete_lifecycle${bt} |`,
96
+ `| Dispatch tasks | ${bt}${toolPrefix}_core${bt} | ${bt}plan_dispatch${bt} |`,
97
+ `| Review plan | ${bt}${toolPrefix}_core${bt} | ${bt}plan_review${bt} |`,
98
+ `| Archive plan | ${bt}${toolPrefix}_core${bt} | ${bt}plan_archive${bt} |`,
99
+ `| List plan tasks | ${bt}${toolPrefix}_core${bt} | ${bt}plan_list_tasks${bt} |`,
100
+ `| Plan stats | ${bt}${toolPrefix}_core${bt} | ${bt}plan_stats${bt} |`,
101
+ // Memory Extra ops
102
+ `| Delete memory | ${bt}${toolPrefix}_core${bt} | ${bt}memory_delete${bt} |`,
103
+ `| Memory stats | ${bt}${toolPrefix}_core${bt} | ${bt}memory_stats${bt} |`,
104
+ `| Export memories | ${bt}${toolPrefix}_core${bt} | ${bt}memory_export${bt} |`,
105
+ `| Import memories | ${bt}${toolPrefix}_core${bt} | ${bt}memory_import${bt} |`,
106
+ `| Prune memories | ${bt}${toolPrefix}_core${bt} | ${bt}memory_prune${bt} |`,
107
+ `| Deduplicate memories | ${bt}${toolPrefix}_core${bt} | ${bt}memory_deduplicate${bt} |`,
108
+ `| Memory topics | ${bt}${toolPrefix}_core${bt} | ${bt}memory_topics${bt} |`,
109
+ `| Memories by project | ${bt}${toolPrefix}_core${bt} | ${bt}memory_by_project${bt} |`,
110
+ // Vault Extra ops
111
+ `| Get vault entry | ${bt}${toolPrefix}_core${bt} | ${bt}vault_get${bt} |`,
112
+ `| Update entry | ${bt}${toolPrefix}_core${bt} | ${bt}vault_update${bt} |`,
113
+ `| Remove entry | ${bt}${toolPrefix}_core${bt} | ${bt}vault_remove${bt} |`,
114
+ `| Bulk add | ${bt}${toolPrefix}_core${bt} | ${bt}vault_bulk_add${bt} |`,
115
+ `| Bulk remove | ${bt}${toolPrefix}_core${bt} | ${bt}vault_bulk_remove${bt} |`,
116
+ `| Vault tags | ${bt}${toolPrefix}_core${bt} | ${bt}vault_tags${bt} |`,
117
+ `| Vault domains | ${bt}${toolPrefix}_core${bt} | ${bt}vault_domains${bt} |`,
118
+ `| Recent entries | ${bt}${toolPrefix}_core${bt} | ${bt}vault_recent${bt} |`,
119
+ `| Import entries | ${bt}${toolPrefix}_core${bt} | ${bt}vault_import${bt} |`,
120
+ `| Seed entries | ${bt}${toolPrefix}_core${bt} | ${bt}vault_seed${bt} |`,
121
+ `| Backup vault | ${bt}${toolPrefix}_core${bt} | ${bt}vault_backup${bt} |`,
122
+ `| Vault age report | ${bt}${toolPrefix}_core${bt} | ${bt}vault_age_report${bt} |`,
123
+ // Admin ops
124
+ `| Admin health | ${bt}${toolPrefix}_core${bt} | ${bt}admin_health${bt} |`,
125
+ `| Tool list | ${bt}${toolPrefix}_core${bt} | ${bt}admin_tool_list${bt} |`,
126
+ `| Config | ${bt}${toolPrefix}_core${bt} | ${bt}admin_config${bt} |`,
127
+ `| Vault size | ${bt}${toolPrefix}_core${bt} | ${bt}admin_vault_size${bt} |`,
128
+ `| Uptime | ${bt}${toolPrefix}_core${bt} | ${bt}admin_uptime${bt} |`,
129
+ `| Version | ${bt}${toolPrefix}_core${bt} | ${bt}admin_version${bt} |`,
130
+ `| Reset cache | ${bt}${toolPrefix}_core${bt} | ${bt}admin_reset_cache${bt} |`,
131
+ `| Diagnostic | ${bt}${toolPrefix}_core${bt} | ${bt}admin_diagnostic${bt} |`,
132
+ // Loop ops
133
+ `| Start loop | ${bt}${toolPrefix}_core${bt} | ${bt}loop_start${bt} |`,
134
+ `| Loop iterate | ${bt}${toolPrefix}_core${bt} | ${bt}loop_iterate${bt} |`,
135
+ `| Loop status | ${bt}${toolPrefix}_core${bt} | ${bt}loop_status${bt} |`,
136
+ `| Cancel loop | ${bt}${toolPrefix}_core${bt} | ${bt}loop_cancel${bt} |`,
137
+ `| Loop history | ${bt}${toolPrefix}_core${bt} | ${bt}loop_history${bt} |`,
138
+ `| Loop active | ${bt}${toolPrefix}_core${bt} | ${bt}loop_is_active${bt} |`,
139
+ `| Complete loop | ${bt}${toolPrefix}_core${bt} | ${bt}loop_complete${bt} |`,
140
+ // Orchestrate ops
141
+ `| Orchestrate plan | ${bt}${toolPrefix}_core${bt} | ${bt}orchestrate_plan${bt} |`,
142
+ `| Orchestrate execute | ${bt}${toolPrefix}_core${bt} | ${bt}orchestrate_execute${bt} |`,
143
+ `| Orchestrate complete | ${bt}${toolPrefix}_core${bt} | ${bt}orchestrate_complete${bt} |`,
144
+ `| Orchestrate status | ${bt}${toolPrefix}_core${bt} | ${bt}orchestrate_status${bt} |`,
145
+ `| Quick capture | ${bt}${toolPrefix}_core${bt} | ${bt}orchestrate_quick_capture${bt} |`,
146
+ // Capture ops
147
+ `| Capture knowledge | ${bt}${toolPrefix}_core${bt} | ${bt}capture_knowledge${bt} |`,
148
+ `| Quick capture entry | ${bt}${toolPrefix}_core${bt} | ${bt}capture_quick${bt} |`,
149
+ `| Intelligent search | ${bt}${toolPrefix}_core${bt} | ${bt}search_intelligent${bt} |`,
150
+ `| Search feedback | ${bt}${toolPrefix}_core${bt} | ${bt}search_feedback${bt} |`,
151
+ // Grading ops
152
+ `| Grade plan | ${bt}${toolPrefix}_core${bt} | ${bt}plan_grade${bt} |`,
153
+ `| Check history | ${bt}${toolPrefix}_core${bt} | ${bt}plan_check_history${bt} |`,
154
+ `| Latest check | ${bt}${toolPrefix}_core${bt} | ${bt}plan_latest_check${bt} |`,
155
+ `| Meets grade | ${bt}${toolPrefix}_core${bt} | ${bt}plan_meets_grade${bt} |`,
156
+ `| Auto improve plan | ${bt}${toolPrefix}_core${bt} | ${bt}plan_auto_improve${bt} |`,
157
+ // Admin Extra ops
158
+ `| Telemetry stats | ${bt}${toolPrefix}_core${bt} | ${bt}admin_telemetry${bt} |`,
159
+ `| Recent calls | ${bt}${toolPrefix}_core${bt} | ${bt}admin_telemetry_recent${bt} |`,
160
+ `| Reset telemetry | ${bt}${toolPrefix}_core${bt} | ${bt}admin_telemetry_reset${bt} |`,
161
+ `| Permissions | ${bt}${toolPrefix}_core${bt} | ${bt}admin_permissions${bt} |`,
162
+ `| Vault analytics | ${bt}${toolPrefix}_core${bt} | ${bt}admin_vault_analytics${bt} |`,
163
+ `| Search insights | ${bt}${toolPrefix}_core${bt} | ${bt}admin_search_insights${bt} |`,
164
+ `| Module status | ${bt}${toolPrefix}_core${bt} | ${bt}admin_module_status${bt} |`,
165
+ `| Environment | ${bt}${toolPrefix}_core${bt} | ${bt}admin_env${bt} |`,
166
+ `| Garbage collect | ${bt}${toolPrefix}_core${bt} | ${bt}admin_gc${bt} |`,
167
+ `| Export config | ${bt}${toolPrefix}_core${bt} | ${bt}admin_export_config${bt} |`,
168
+ // Curator Extra ops
169
+ `| Entry history | ${bt}${toolPrefix}_core${bt} | ${bt}curator_entry_history${bt} |`,
170
+ `| Record snapshot | ${bt}${toolPrefix}_core${bt} | ${bt}curator_record_snapshot${bt} |`,
171
+ `| Queue stats | ${bt}${toolPrefix}_core${bt} | ${bt}curator_queue_stats${bt} |`,
172
+ `| Enrich metadata | ${bt}${toolPrefix}_core${bt} | ${bt}curator_enrich${bt} |`,
173
+ // Project ops
174
+ `| Get project | ${bt}${toolPrefix}_core${bt} | ${bt}project_get${bt} |`,
175
+ `| List projects | ${bt}${toolPrefix}_core${bt} | ${bt}project_list${bt} |`,
176
+ `| Unregister project | ${bt}${toolPrefix}_core${bt} | ${bt}project_unregister${bt} |`,
177
+ `| Project rules | ${bt}${toolPrefix}_core${bt} | ${bt}project_get_rules${bt} |`,
178
+ `| All project rules | ${bt}${toolPrefix}_core${bt} | ${bt}project_list_rules${bt} |`,
179
+ `| Add rule | ${bt}${toolPrefix}_core${bt} | ${bt}project_add_rule${bt} |`,
180
+ `| Remove rule | ${bt}${toolPrefix}_core${bt} | ${bt}project_remove_rule${bt} |`,
181
+ `| Link projects | ${bt}${toolPrefix}_core${bt} | ${bt}project_link${bt} |`,
182
+ `| Unlink projects | ${bt}${toolPrefix}_core${bt} | ${bt}project_unlink${bt} |`,
183
+ `| Project links | ${bt}${toolPrefix}_core${bt} | ${bt}project_get_links${bt} |`,
184
+ `| Linked projects | ${bt}${toolPrefix}_core${bt} | ${bt}project_linked_projects${bt} |`,
185
+ `| Touch project | ${bt}${toolPrefix}_core${bt} | ${bt}project_touch${bt} |`,
186
+ // Cross-project memory ops
187
+ `| Promote to global | ${bt}${toolPrefix}_core${bt} | ${bt}memory_promote_to_global${bt} |`,
188
+ `| Configure memory | ${bt}${toolPrefix}_core${bt} | ${bt}memory_configure${bt} |`,
189
+ `| Cross-project search | ${bt}${toolPrefix}_core${bt} | ${bt}memory_cross_project_search${bt} |`,
76
190
  );
77
191
 
78
192
  mdLines.push(
@@ -130,6 +244,73 @@ export function generateClaudeMdTemplate(config: AgentConfig): string {
130
244
  `<!-- /${marker} -->`,
131
245
  );
132
246
 
247
+ // ─── Hook Packs section (when configured) ─────────────────────
248
+ if (config.hookPacks?.length) {
249
+ const PACK_INFO: Record<string, { description: string; hooks: Record<string, string> }> = {
250
+ 'typescript-safety': {
251
+ description: 'Block unsafe TypeScript patterns',
252
+ hooks: {
253
+ 'no-any-types': '`:any`, `as any`, `<any>`, `Record<string, any>`',
254
+ 'no-console-log': '`console.log` in committed code',
255
+ },
256
+ },
257
+ a11y: {
258
+ description: 'Accessibility enforcement',
259
+ hooks: {
260
+ 'semantic-html': 'Generic divs where semantic HTML should be used',
261
+ 'focus-ring-required': 'Missing visible focus indicators',
262
+ 'ux-touch-targets': 'Touch targets smaller than 44px',
263
+ },
264
+ },
265
+ 'css-discipline': {
266
+ description: 'CSS best practices',
267
+ hooks: {
268
+ 'no-important': '`!important` in CSS',
269
+ 'no-inline-styles': 'Inline style attributes',
270
+ },
271
+ },
272
+ 'clean-commits': {
273
+ description: 'Clean git history',
274
+ hooks: {
275
+ 'no-ai-attribution': 'AI attribution in commits',
276
+ },
277
+ },
278
+ };
279
+
280
+ // Build rows — expand 'full' to constituent packs
281
+ const rows: Array<{ pack: string; hook: string; blocks: string }> = [];
282
+ for (const packName of config.hookPacks) {
283
+ if (packName === 'full') {
284
+ // Composed pack — expand all constituent packs
285
+ for (const [subPack, info] of Object.entries(PACK_INFO)) {
286
+ for (const [hook, blocks] of Object.entries(info.hooks)) {
287
+ rows.push({ pack: subPack, hook, blocks });
288
+ }
289
+ }
290
+ } else if (PACK_INFO[packName]) {
291
+ for (const [hook, blocks] of Object.entries(PACK_INFO[packName].hooks)) {
292
+ rows.push({ pack: packName, hook, blocks });
293
+ }
294
+ }
295
+ }
296
+
297
+ if (rows.length > 0) {
298
+ // Insert before the closing marker
299
+ const closingMarkerIndex = mdLines.length - 1;
300
+ const hookLines = [
301
+ '',
302
+ '## Hook Packs',
303
+ '',
304
+ 'Quality gates installed in `.claude/`. Run `scripts/setup.sh` to install globally.',
305
+ '',
306
+ '| Pack | Hook | Blocks |',
307
+ '|------|------|--------|',
308
+ ...rows.map((r) => `| ${r.pack} | ${r.hook} | ${r.blocks} |`),
309
+ ];
310
+ mdLines.splice(closingMarkerIndex, 0, ...hookLines);
311
+ }
312
+ }
313
+
133
314
  // Escape each markdown line for use in a single-quoted TS string literal
134
315
  const quotedLines = mdLines.map((line) => {
135
316
  const escaped = line.replace(/\\/g, '\\\\').replace(/'/g, "\\'");