@soleri/forge 5.11.0 → 5.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/facades/forge.facade.js +3 -3
- package/dist/facades/forge.facade.js.map +1 -1
- package/dist/lib.d.ts +2 -2
- package/dist/lib.js +1 -1
- package/dist/lib.js.map +1 -1
- package/dist/scaffolder.js +137 -20
- package/dist/scaffolder.js.map +1 -1
- package/dist/templates/agents-md.d.ts +5 -0
- package/dist/templates/agents-md.js +33 -0
- package/dist/templates/agents-md.js.map +1 -0
- package/dist/templates/entry-point.js +15 -2
- package/dist/templates/entry-point.js.map +1 -1
- package/dist/templates/package-json.js +7 -0
- package/dist/templates/package-json.js.map +1 -1
- package/dist/templates/readme.js +80 -27
- package/dist/templates/readme.js.map +1 -1
- package/dist/templates/setup-script.d.ts +1 -1
- package/dist/templates/setup-script.js +135 -53
- package/dist/templates/setup-script.js.map +1 -1
- package/dist/templates/skills.d.ts +0 -7
- package/dist/templates/skills.js +0 -21
- package/dist/templates/skills.js.map +1 -1
- package/dist/templates/telegram-agent.d.ts +6 -0
- package/dist/templates/telegram-agent.js +212 -0
- package/dist/templates/telegram-agent.js.map +1 -0
- package/dist/templates/telegram-bot.d.ts +6 -0
- package/dist/templates/telegram-bot.js +450 -0
- package/dist/templates/telegram-bot.js.map +1 -0
- package/dist/templates/telegram-config.d.ts +6 -0
- package/dist/templates/telegram-config.js +81 -0
- package/dist/templates/telegram-config.js.map +1 -0
- package/dist/templates/telegram-supervisor.d.ts +6 -0
- package/dist/templates/telegram-supervisor.js +148 -0
- package/dist/templates/telegram-supervisor.js.map +1 -0
- package/dist/types.d.ts +15 -5
- package/dist/types.js +7 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/scaffolder.test.ts +62 -0
- package/src/facades/forge.facade.ts +3 -3
- package/src/lib.ts +3 -1
- package/src/scaffolder.ts +170 -28
- package/src/templates/agents-md.ts +35 -0
- package/src/templates/entry-point.ts +15 -2
- package/src/templates/package-json.ts +7 -0
- package/src/templates/readme.ts +89 -27
- package/src/templates/setup-script.ts +141 -54
- package/src/templates/skills.ts +0 -23
- package/src/templates/telegram-agent.ts +214 -0
- package/src/templates/telegram-bot.ts +452 -0
- package/src/templates/telegram-config.ts +83 -0
- package/src/templates/telegram-supervisor.ts +150 -0
- package/src/types.ts +12 -2
package/src/scaffolder.ts
CHANGED
|
@@ -22,14 +22,37 @@ import { generateInjectClaudeMd } from './templates/inject-claude-md.js';
|
|
|
22
22
|
import { generateActivate } from './templates/activate.js';
|
|
23
23
|
import { generateReadme } from './templates/readme.js';
|
|
24
24
|
import { generateSetupScript } from './templates/setup-script.js';
|
|
25
|
+
import { generateAgentsMd } from './templates/agents-md.js';
|
|
25
26
|
import { generateSkills } from './templates/skills.js';
|
|
26
27
|
import { generateExtensionsIndex, generateExampleOp } from './templates/extensions.js';
|
|
28
|
+
import { generateTelegramBot } from './templates/telegram-bot.js';
|
|
29
|
+
import { generateTelegramConfig } from './templates/telegram-config.js';
|
|
30
|
+
import { generateTelegramAgent } from './templates/telegram-agent.js';
|
|
31
|
+
import { generateTelegramSupervisor } from './templates/telegram-supervisor.js';
|
|
32
|
+
|
|
33
|
+
function getSetupTarget(config: AgentConfig): 'claude' | 'codex' | 'both' {
|
|
34
|
+
return config.setupTarget ?? 'claude';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function includesClaudeSetup(config: AgentConfig): boolean {
|
|
38
|
+
const target = getSetupTarget(config);
|
|
39
|
+
return target === 'claude' || target === 'both';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function includesCodexSetup(config: AgentConfig): boolean {
|
|
43
|
+
const target = getSetupTarget(config);
|
|
44
|
+
return target === 'codex' || target === 'both';
|
|
45
|
+
}
|
|
27
46
|
|
|
28
47
|
/**
|
|
29
48
|
* Preview what scaffold will create without writing anything.
|
|
30
49
|
*/
|
|
31
50
|
export function previewScaffold(config: AgentConfig): ScaffoldPreview {
|
|
32
51
|
const agentDir = join(config.outputDir, config.id);
|
|
52
|
+
const claudeSetup = includesClaudeSetup(config);
|
|
53
|
+
const codexSetup = includesCodexSetup(config);
|
|
54
|
+
const setupLabel =
|
|
55
|
+
claudeSetup && codexSetup ? 'Claude Code + Codex' : claudeSetup ? 'Claude Code' : 'Codex';
|
|
33
56
|
|
|
34
57
|
const files = [
|
|
35
58
|
{ path: 'package.json', description: 'NPM package with MCP SDK, SQLite, Zod dependencies' },
|
|
@@ -80,7 +103,7 @@ export function previewScaffold(config: AgentConfig): ScaffoldPreview {
|
|
|
80
103
|
},
|
|
81
104
|
{
|
|
82
105
|
path: 'scripts/setup.sh',
|
|
83
|
-
description:
|
|
106
|
+
description: `Automated setup — Node.js check, build, ${setupLabel} MCP registration`,
|
|
84
107
|
},
|
|
85
108
|
{
|
|
86
109
|
path: 'skills/',
|
|
@@ -90,13 +113,35 @@ export function previewScaffold(config: AgentConfig): ScaffoldPreview {
|
|
|
90
113
|
},
|
|
91
114
|
];
|
|
92
115
|
|
|
93
|
-
if (
|
|
116
|
+
if (codexSetup) {
|
|
117
|
+
files.push({
|
|
118
|
+
path: 'AGENTS.md',
|
|
119
|
+
description: 'Codex project instructions and activation workflow',
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (claudeSetup && config.hookPacks?.length) {
|
|
94
124
|
files.push({
|
|
95
125
|
path: '.claude/',
|
|
96
126
|
description: `Hook pack files (${config.hookPacks.join(', ')})`,
|
|
97
127
|
});
|
|
98
128
|
}
|
|
99
129
|
|
|
130
|
+
if (config.telegram) {
|
|
131
|
+
files.push(
|
|
132
|
+
{
|
|
133
|
+
path: 'src/telegram-bot.ts',
|
|
134
|
+
description: 'Telegram bot entry point with Grammy middleware',
|
|
135
|
+
},
|
|
136
|
+
{ path: 'src/telegram-config.ts', description: 'Telegram config loading (env + file)' },
|
|
137
|
+
{ path: 'src/telegram-agent.ts', description: 'Agent loop wired to MCP tools' },
|
|
138
|
+
{
|
|
139
|
+
path: 'src/telegram-supervisor.ts',
|
|
140
|
+
description: 'Process supervisor with restart and logging',
|
|
141
|
+
},
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
100
145
|
const facades = [
|
|
101
146
|
...config.domains.map((d) => ({
|
|
102
147
|
name: `${config.id}_${d.replace(/-/g, '_')}`,
|
|
@@ -208,6 +253,8 @@ export function scaffold(config: AgentConfig): ScaffoldResult {
|
|
|
208
253
|
greeting: `Hello! I'm ${config.name}, your AI assistant for ${config.role}.`,
|
|
209
254
|
};
|
|
210
255
|
}
|
|
256
|
+
const claudeSetup = includesClaudeSetup(config);
|
|
257
|
+
const codexSetup = includesCodexSetup(config);
|
|
211
258
|
const agentDir = join(config.outputDir, config.id);
|
|
212
259
|
const filesCreated: string[] = [];
|
|
213
260
|
|
|
@@ -238,7 +285,7 @@ export function scaffold(config: AgentConfig): ScaffoldResult {
|
|
|
238
285
|
'src/extensions/middleware',
|
|
239
286
|
];
|
|
240
287
|
|
|
241
|
-
if (config.hookPacks?.length) {
|
|
288
|
+
if (claudeSetup && config.hookPacks?.length) {
|
|
242
289
|
dirs.push('.claude');
|
|
243
290
|
}
|
|
244
291
|
|
|
@@ -265,6 +312,10 @@ export function scaffold(config: AgentConfig): ScaffoldResult {
|
|
|
265
312
|
['scripts/setup.sh', generateSetupScript(config)],
|
|
266
313
|
];
|
|
267
314
|
|
|
315
|
+
if (codexSetup) {
|
|
316
|
+
projectFiles.push(['AGENTS.md', generateAgentsMd(config)]);
|
|
317
|
+
}
|
|
318
|
+
|
|
268
319
|
for (const [path, content] of projectFiles) {
|
|
269
320
|
writeFileSync(join(agentDir, path), content, 'utf-8');
|
|
270
321
|
filesCreated.push(path);
|
|
@@ -285,6 +336,16 @@ export function scaffold(config: AgentConfig): ScaffoldResult {
|
|
|
285
336
|
['src/extensions/ops/example.ts', generateExampleOp(config)],
|
|
286
337
|
];
|
|
287
338
|
|
|
339
|
+
// Telegram transport files (optional)
|
|
340
|
+
if (config.telegram) {
|
|
341
|
+
sourceFiles.push(
|
|
342
|
+
['src/telegram-bot.ts', generateTelegramBot(config)],
|
|
343
|
+
['src/telegram-config.ts', generateTelegramConfig(config)],
|
|
344
|
+
['src/telegram-agent.ts', generateTelegramAgent(config)],
|
|
345
|
+
['src/telegram-supervisor.ts', generateTelegramSupervisor(config)],
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
|
|
288
349
|
// Empty intelligence data bundles (domain facades come from @soleri/core at runtime)
|
|
289
350
|
for (const domain of config.domains) {
|
|
290
351
|
sourceFiles.push([`src/intelligence/data/${domain}.json`, generateEmptyBundle(domain)]);
|
|
@@ -325,16 +386,41 @@ export function scaffold(config: AgentConfig): ScaffoldResult {
|
|
|
325
386
|
buildError = err instanceof Error ? err.message : String(err);
|
|
326
387
|
}
|
|
327
388
|
|
|
328
|
-
// Register the agent as an MCP server in
|
|
329
|
-
|
|
330
|
-
if (
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
389
|
+
// Register the agent as an MCP server in selected host configs (only if build succeeded)
|
|
390
|
+
const mcpRegistrations: Array<{ host: 'Claude Code' | 'Codex'; result: RegistrationResult }> = [];
|
|
391
|
+
if (claudeSetup) {
|
|
392
|
+
if (buildSuccess) {
|
|
393
|
+
mcpRegistrations.push({
|
|
394
|
+
host: 'Claude Code',
|
|
395
|
+
result: registerClaudeMcpServer(config.id, agentDir),
|
|
396
|
+
});
|
|
397
|
+
} else {
|
|
398
|
+
mcpRegistrations.push({
|
|
399
|
+
host: 'Claude Code',
|
|
400
|
+
result: {
|
|
401
|
+
registered: false,
|
|
402
|
+
path: join(homedir(), '.claude.json'),
|
|
403
|
+
error: 'Skipped — build failed',
|
|
404
|
+
},
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
if (codexSetup) {
|
|
409
|
+
if (buildSuccess) {
|
|
410
|
+
mcpRegistrations.push({
|
|
411
|
+
host: 'Codex',
|
|
412
|
+
result: registerCodexMcpServer(config.id, agentDir),
|
|
413
|
+
});
|
|
414
|
+
} else {
|
|
415
|
+
mcpRegistrations.push({
|
|
416
|
+
host: 'Codex',
|
|
417
|
+
result: {
|
|
418
|
+
registered: false,
|
|
419
|
+
path: join(homedir(), '.codex', 'config.toml'),
|
|
420
|
+
error: 'Skipped — build failed',
|
|
421
|
+
},
|
|
422
|
+
});
|
|
423
|
+
}
|
|
338
424
|
}
|
|
339
425
|
|
|
340
426
|
const summaryLines = [
|
|
@@ -354,22 +440,31 @@ export function scaffold(config: AgentConfig): ScaffoldResult {
|
|
|
354
440
|
summaryLines.push(` Run manually: cd ${agentDir} && npm install && npm run build`);
|
|
355
441
|
}
|
|
356
442
|
|
|
357
|
-
if (config.hookPacks?.length) {
|
|
443
|
+
if (claudeSetup && config.hookPacks?.length) {
|
|
358
444
|
summaryLines.push(`${config.hookPacks.length} hook pack(s) bundled in .claude/`);
|
|
359
445
|
}
|
|
360
446
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
447
|
+
for (const registration of mcpRegistrations) {
|
|
448
|
+
if (registration.result.registered) {
|
|
449
|
+
summaryLines.push(
|
|
450
|
+
`${registration.host} MCP server registered in ${registration.result.path}`,
|
|
451
|
+
);
|
|
452
|
+
} else {
|
|
453
|
+
summaryLines.push(
|
|
454
|
+
`Warning: Failed to register ${registration.host} MCP server in ${registration.result.path}: ${registration.result.error}`,
|
|
455
|
+
);
|
|
456
|
+
}
|
|
365
457
|
}
|
|
366
458
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
'
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
);
|
|
459
|
+
const nextSteps = ['', 'Next steps:'];
|
|
460
|
+
if (claudeSetup) {
|
|
461
|
+
nextSteps.push(' Restart Claude Code');
|
|
462
|
+
}
|
|
463
|
+
if (codexSetup) {
|
|
464
|
+
nextSteps.push(' Restart Codex');
|
|
465
|
+
}
|
|
466
|
+
nextSteps.push(` Say "Hello, ${config.name}!" to activate the persona`);
|
|
467
|
+
summaryLines.push(...nextSteps);
|
|
373
468
|
|
|
374
469
|
return {
|
|
375
470
|
success: true,
|
|
@@ -432,14 +527,20 @@ export function listAgents(parentDir: string): AgentInfo[] {
|
|
|
432
527
|
return agents;
|
|
433
528
|
}
|
|
434
529
|
|
|
530
|
+
/**
|
|
531
|
+
* Registration result for host config updates.
|
|
532
|
+
*/
|
|
533
|
+
interface RegistrationResult {
|
|
534
|
+
registered: boolean;
|
|
535
|
+
path: string;
|
|
536
|
+
error?: string;
|
|
537
|
+
}
|
|
538
|
+
|
|
435
539
|
/**
|
|
436
540
|
* Register the agent as an MCP server in ~/.claude.json (User MCPs).
|
|
437
541
|
* Idempotent — updates existing entry if present.
|
|
438
542
|
*/
|
|
439
|
-
function
|
|
440
|
-
agentId: string,
|
|
441
|
-
agentDir: string,
|
|
442
|
-
): { registered: boolean; path: string; error?: string } {
|
|
543
|
+
function registerClaudeMcpServer(agentId: string, agentDir: string): RegistrationResult {
|
|
443
544
|
const claudeJsonPath = join(homedir(), '.claude.json');
|
|
444
545
|
|
|
445
546
|
try {
|
|
@@ -472,6 +573,47 @@ function registerMcpServer(
|
|
|
472
573
|
}
|
|
473
574
|
}
|
|
474
575
|
|
|
576
|
+
/**
|
|
577
|
+
* Register the agent as an MCP server in ~/.codex/config.toml.
|
|
578
|
+
* Idempotent — updates existing section if present.
|
|
579
|
+
*/
|
|
580
|
+
function registerCodexMcpServer(agentId: string, agentDir: string): RegistrationResult {
|
|
581
|
+
const codexDir = join(homedir(), '.codex');
|
|
582
|
+
const codexConfigPath = join(codexDir, 'config.toml');
|
|
583
|
+
const sectionHeader = `[mcp_servers.${agentId}]`;
|
|
584
|
+
const sectionBlock = `${sectionHeader}
|
|
585
|
+
command = "node"
|
|
586
|
+
args = ["${join(agentDir, 'dist', 'index.js')}"]
|
|
587
|
+
`;
|
|
588
|
+
|
|
589
|
+
try {
|
|
590
|
+
mkdirSync(codexDir, { recursive: true });
|
|
591
|
+
|
|
592
|
+
let content = existsSync(codexConfigPath) ? readFileSync(codexConfigPath, 'utf-8') : '';
|
|
593
|
+
const start = content.indexOf(sectionHeader);
|
|
594
|
+
|
|
595
|
+
if (start === -1) {
|
|
596
|
+
const trimmed = content.trimEnd();
|
|
597
|
+
content = trimmed.length === 0 ? `${sectionBlock}\n` : `${trimmed}\n\n${sectionBlock}\n`;
|
|
598
|
+
} else {
|
|
599
|
+
const afterHeader = start + sectionHeader.length;
|
|
600
|
+
const tail = content.slice(afterHeader);
|
|
601
|
+
const nextSectionOffset = tail.search(/\n\[[^\]]+\]/);
|
|
602
|
+
const end = nextSectionOffset === -1 ? content.length : afterHeader + nextSectionOffset;
|
|
603
|
+
content = `${content.slice(0, start).trimEnd()}\n\n${sectionBlock}\n${content.slice(end).trimStart()}`;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
writeFileSync(codexConfigPath, content.replace(/\n{3,}/g, '\n\n'), 'utf-8');
|
|
607
|
+
return { registered: true, path: codexConfigPath };
|
|
608
|
+
} catch (err) {
|
|
609
|
+
return {
|
|
610
|
+
registered: false,
|
|
611
|
+
path: codexConfigPath,
|
|
612
|
+
error: err instanceof Error ? err.message : String(err),
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
475
617
|
function generateEmptyBundle(domain: string): string {
|
|
476
618
|
return JSON.stringify(
|
|
477
619
|
{
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { AgentConfig } from '../types.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generate AGENTS.md content for Codex sessions.
|
|
5
|
+
*/
|
|
6
|
+
export function generateAgentsMd(config: AgentConfig): string {
|
|
7
|
+
const principles = config.principles.map((p) => `- ${p}`).join('\n');
|
|
8
|
+
const domains = config.domains.map((d) => `- ${d}`).join('\n');
|
|
9
|
+
|
|
10
|
+
return `# AGENTS.md instructions for this project
|
|
11
|
+
|
|
12
|
+
## Agent Identity
|
|
13
|
+
- Name: ${config.name}
|
|
14
|
+
- Role: ${config.role}
|
|
15
|
+
- Agent MCP prefix: \`${config.id}\`
|
|
16
|
+
|
|
17
|
+
## Activation
|
|
18
|
+
- Say "Hello, ${config.name}!" to activate persona behavior via \`${config.id}_core\`.
|
|
19
|
+
- Say "Goodbye, ${config.name}!" to deactivate.
|
|
20
|
+
|
|
21
|
+
## Domains
|
|
22
|
+
${domains}
|
|
23
|
+
|
|
24
|
+
## Principles
|
|
25
|
+
${principles}
|
|
26
|
+
|
|
27
|
+
## Skills
|
|
28
|
+
- Local skills live in \`skills/<skill>/SKILL.md\`.
|
|
29
|
+
- If a user explicitly names a skill, open that \`SKILL.md\` and follow it for that turn.
|
|
30
|
+
|
|
31
|
+
## Setup Notes
|
|
32
|
+
- This repository was scaffolded with Codex support.
|
|
33
|
+
- Session model/reasoning is selected at session start and does not auto-switch per prompt.
|
|
34
|
+
`;
|
|
35
|
+
}
|
|
@@ -257,10 +257,23 @@ async function main(): Promise<void> {
|
|
|
257
257
|
messages: [{ role: 'assistant' as const, content: { type: 'text' as const, text: getPersonaPrompt() } }],
|
|
258
258
|
}));
|
|
259
259
|
|
|
260
|
-
|
|
260
|
+
// Hot ops — promoted to standalone MCP tools with full schema discovery
|
|
261
|
+
const hotOps = new Set([
|
|
262
|
+
'search_intelligent',
|
|
263
|
+
'capture_knowledge',
|
|
264
|
+
'orchestrate_plan',
|
|
265
|
+
'orchestrate_execute',
|
|
266
|
+
'orchestrate_complete',
|
|
267
|
+
]);
|
|
268
|
+
|
|
269
|
+
registerAllFacades(server, allFacades, {
|
|
270
|
+
agentId: '${config.id}',
|
|
271
|
+
hotOps,
|
|
272
|
+
authPolicy: () => runtime.authPolicy,
|
|
273
|
+
});
|
|
261
274
|
|
|
262
275
|
console.error(\`[\${tag}] \${PERSONA.name} — \${PERSONA.role}\`);
|
|
263
|
-
console.error(\`[\${tag}] Registered \${allFacades.length} facades with \${allFacades.reduce((sum, f) => sum + f.ops.length, 0)} operations\`);
|
|
276
|
+
console.error(\`[\${tag}] Registered \${allFacades.length} facades with \${allFacades.reduce((sum, f) => sum + f.ops.length, 0)} operations (\${hotOps.size} hot)\`);
|
|
264
277
|
|
|
265
278
|
// ─── Transport + shutdown ──────────────────────────────────────
|
|
266
279
|
const transport = new StdioServerTransport();
|
|
@@ -16,6 +16,12 @@ export function generatePackageJson(config: AgentConfig): string {
|
|
|
16
16
|
test: 'vitest run',
|
|
17
17
|
'test:watch': 'vitest',
|
|
18
18
|
'test:coverage': 'vitest run --coverage',
|
|
19
|
+
...(config.telegram
|
|
20
|
+
? {
|
|
21
|
+
'telegram:start': 'node dist/telegram-supervisor.js',
|
|
22
|
+
'telegram:dev': 'tsx src/telegram-bot.ts',
|
|
23
|
+
}
|
|
24
|
+
: {}),
|
|
19
25
|
},
|
|
20
26
|
keywords: ['mcp', 'agent', config.id, ...config.domains.slice(0, 5)],
|
|
21
27
|
license: 'MIT',
|
|
@@ -24,6 +30,7 @@ export function generatePackageJson(config: AgentConfig): string {
|
|
|
24
30
|
'@modelcontextprotocol/sdk': '^1.12.1',
|
|
25
31
|
'@soleri/core': '^2.0.0',
|
|
26
32
|
zod: '^3.24.2',
|
|
33
|
+
...(config.telegram ? { grammy: '^1.35.0' } : {}),
|
|
27
34
|
},
|
|
28
35
|
optionalDependencies: {
|
|
29
36
|
'@anthropic-ai/sdk': '^0.39.0',
|
package/src/templates/readme.ts
CHANGED
|
@@ -4,12 +4,92 @@ import type { AgentConfig } from '../types.js';
|
|
|
4
4
|
* Generate a README.md for the scaffolded agent.
|
|
5
5
|
*/
|
|
6
6
|
export function generateReadme(config: AgentConfig): string {
|
|
7
|
+
const setupTarget = config.setupTarget ?? 'claude';
|
|
8
|
+
const claudeSetup = setupTarget === 'claude' || setupTarget === 'both';
|
|
9
|
+
const codexSetup = setupTarget === 'codex' || setupTarget === 'both';
|
|
7
10
|
const domainRows = config.domains
|
|
8
11
|
.map((d) => `| ${d} | *Ready for knowledge capture* |`)
|
|
9
12
|
.join('\n');
|
|
10
13
|
|
|
11
14
|
const principleLines = config.principles.map((p) => `- ${p}`).join('\n');
|
|
12
15
|
|
|
16
|
+
const quickStartSession =
|
|
17
|
+
claudeSetup && codexSetup
|
|
18
|
+
? 'Start a new Claude Code or Codex session, then say:'
|
|
19
|
+
: claudeSetup
|
|
20
|
+
? 'Start a new Claude Code session, then say:'
|
|
21
|
+
: 'Start a new Codex session, then say:';
|
|
22
|
+
|
|
23
|
+
const prerequisites = [
|
|
24
|
+
'- **Node.js 18+** — `node --version` to check',
|
|
25
|
+
...(claudeSetup ? ['- **Claude Code** — Anthropic CLI (`claude` command)'] : []),
|
|
26
|
+
...(codexSetup ? ['- **Codex** — desktop/CLI with `~/.codex/config.toml`'] : []),
|
|
27
|
+
].join('\n');
|
|
28
|
+
|
|
29
|
+
const helloFlow = [
|
|
30
|
+
`- ${config.name} returns its persona, principles, and tool recommendations`,
|
|
31
|
+
...(claudeSetup ? [`- Claude can adopt the ${config.name} persona for the session`] : []),
|
|
32
|
+
...(claudeSetup
|
|
33
|
+
? [`- ${config.name} can inject/check CLAUDE.md integration when requested`]
|
|
34
|
+
: []),
|
|
35
|
+
...(codexSetup
|
|
36
|
+
? ['- Codex uses project-level AGENTS.md guidance and local skills for routing']
|
|
37
|
+
: []),
|
|
38
|
+
].join('\n');
|
|
39
|
+
|
|
40
|
+
const manualSetupBlocks = [
|
|
41
|
+
...(claudeSetup
|
|
42
|
+
? [
|
|
43
|
+
[
|
|
44
|
+
'### Claude Code',
|
|
45
|
+
'',
|
|
46
|
+
'Add this to `~/.claude/settings.json` under `mcpServers`:',
|
|
47
|
+
'',
|
|
48
|
+
'```json',
|
|
49
|
+
'{',
|
|
50
|
+
' "mcpServers": {',
|
|
51
|
+
` "${config.id}": {`,
|
|
52
|
+
' "command": "node",',
|
|
53
|
+
' "args": ["dist/index.js"],',
|
|
54
|
+
` "cwd": "/absolute/path/to/${config.id}"`,
|
|
55
|
+
' }',
|
|
56
|
+
' }',
|
|
57
|
+
'}',
|
|
58
|
+
'```',
|
|
59
|
+
].join('\n'),
|
|
60
|
+
]
|
|
61
|
+
: []),
|
|
62
|
+
...(codexSetup
|
|
63
|
+
? [
|
|
64
|
+
[
|
|
65
|
+
'### Codex',
|
|
66
|
+
'',
|
|
67
|
+
'Add this to `~/.codex/config.toml`:',
|
|
68
|
+
'',
|
|
69
|
+
'```toml',
|
|
70
|
+
`[mcp_servers.${config.id}]`,
|
|
71
|
+
'command = "node"',
|
|
72
|
+
`args = ["/absolute/path/to/${config.id}/dist/index.js"]`,
|
|
73
|
+
'```',
|
|
74
|
+
].join('\n'),
|
|
75
|
+
]
|
|
76
|
+
: []),
|
|
77
|
+
].join('\n\n');
|
|
78
|
+
|
|
79
|
+
const skillsLead =
|
|
80
|
+
claudeSetup && codexSetup
|
|
81
|
+
? `${config.name} ships with 17 structured workflow skills. In Claude Code they are invocable via \`/<skill-name>\`; in Codex they are available via generated AGENTS.md + local skill files.`
|
|
82
|
+
: claudeSetup
|
|
83
|
+
? `${config.name} ships with 17 structured workflow skills, invocable via \`/<skill-name>\` in Claude Code:`
|
|
84
|
+
: `${config.name} ships with 17 structured workflow skills, available via generated AGENTS.md + local skill files in Codex:`;
|
|
85
|
+
|
|
86
|
+
const skillsInstallNote =
|
|
87
|
+
claudeSetup && codexSetup
|
|
88
|
+
? 'Skills are installed to `~/.claude/commands/` and `~/.codex/skills/` during setup. Run `./scripts/setup.sh` to install or reinstall.'
|
|
89
|
+
: claudeSetup
|
|
90
|
+
? 'Skills are installed to `~/.claude/commands/` during setup. Run `./scripts/setup.sh` to install or reinstall.'
|
|
91
|
+
: 'Skills are installed to `~/.codex/skills/` during setup. Run `./scripts/setup.sh` to install or reinstall.';
|
|
92
|
+
|
|
13
93
|
return `# ${config.name} — ${config.role}
|
|
14
94
|
|
|
15
95
|
${config.description}
|
|
@@ -35,10 +115,10 @@ cd ${config.id}
|
|
|
35
115
|
npm install
|
|
36
116
|
npm run build
|
|
37
117
|
|
|
38
|
-
# 2.
|
|
118
|
+
# 2. Run setup
|
|
39
119
|
./scripts/setup.sh
|
|
40
120
|
|
|
41
|
-
# 3.
|
|
121
|
+
# 3. ${quickStartSession}
|
|
42
122
|
# "Hello, ${config.name}!"
|
|
43
123
|
\`\`\`
|
|
44
124
|
|
|
@@ -46,33 +126,15 @@ That's it. ${config.name} will activate, check your setup, and offer to configur
|
|
|
46
126
|
|
|
47
127
|
## Prerequisites
|
|
48
128
|
|
|
49
|
-
|
|
50
|
-
- **Claude Code** — Anthropic's CLI for Claude (\`claude\` command)
|
|
129
|
+
${prerequisites}
|
|
51
130
|
|
|
52
131
|
## What Happens When You Say "Hello, ${config.name}!"
|
|
53
132
|
|
|
54
|
-
|
|
55
|
-
2. Claude adopts the ${config.name} persona for the rest of the session
|
|
56
|
-
3. ${config.name} checks if your project has CLAUDE.md integration
|
|
57
|
-
4. If not, it offers to inject its configuration (facades table, intent detection, knowledge protocol)
|
|
133
|
+
${helloFlow}
|
|
58
134
|
|
|
59
135
|
## Manual Setup (if setup.sh doesn't work)
|
|
60
136
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
\`\`\`json
|
|
64
|
-
{
|
|
65
|
-
"mcpServers": {
|
|
66
|
-
"${config.id}": {
|
|
67
|
-
"command": "node",
|
|
68
|
-
"args": ["dist/index.js"],
|
|
69
|
-
"cwd": "/absolute/path/to/${config.id}"
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
\`\`\`
|
|
74
|
-
|
|
75
|
-
Then restart Claude Code.
|
|
137
|
+
${manualSetupBlocks}
|
|
76
138
|
|
|
77
139
|
## Domains
|
|
78
140
|
|
|
@@ -86,7 +148,7 @@ ${principleLines}
|
|
|
86
148
|
|
|
87
149
|
## Built-in Skills
|
|
88
150
|
|
|
89
|
-
${
|
|
151
|
+
${skillsLead}
|
|
90
152
|
|
|
91
153
|
**Development Workflows:**
|
|
92
154
|
|
|
@@ -120,7 +182,7 @@ ${config.name} ships with 17 structured workflow skills, invocable via \`/<skill
|
|
|
120
182
|
| \`/onboard-me\` | Instant project knowledge tour for newcomers |
|
|
121
183
|
| \`/health-check\` | Vault maintenance — duplicates, contradictions, stale entries |
|
|
122
184
|
|
|
123
|
-
|
|
185
|
+
${skillsInstallNote}
|
|
124
186
|
|
|
125
187
|
## Features
|
|
126
188
|
|
|
@@ -176,8 +238,8 @@ Use \`llm_status\` to check provider availability and key pool health.
|
|
|
176
238
|
|
|
177
239
|
### Activating and Deactivating
|
|
178
240
|
|
|
179
|
-
- **"Hello, ${config.name}!"** — Activate the persona.
|
|
180
|
-
- **"Goodbye, ${config.name}!"** — Deactivate
|
|
241
|
+
- **"Hello, ${config.name}!"** — Activate the persona. Your active client session adopts ${config.name}'s identity, principles, and tool access.
|
|
242
|
+
- **"Goodbye, ${config.name}!"** — Deactivate and return to default assistant behavior.
|
|
181
243
|
|
|
182
244
|
### Daily Workflow
|
|
183
245
|
|