AgentScaffold.js
13.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
/**
* ═══════════════════════════════════════════════════════════════
* AgentScaffold — Agent 目录脚手架
* ═══════════════════════════════════════════════════════════════
*
* 创建 Agent = 生成一个标准目录结构 + 写入 Bootstrap Files
*
* 用法:
* const scaffold = new AgentScaffold('data/agents');
* const agentDir = await scaffold.create({
* id: 'cxo-ceo-001',
* type: 'cxo',
* name: 'Lemon CEO',
* parentId: 'master-001',
* });
*/
import { mkdir, writeFile } from 'node:fs/promises';
import { join } from 'node:path';
/**
* Agent 目录内的标准子目录
*/
const STANDARD_SUBDIRS = [
'.claude/skills',
'.claude/skills/main_skill',
'memory',
'memory/short-term',
'memory/long-term',
'memory/sessions',
'memory/daily',
'memory/cerebellum', // v5: 小脑 — 固化的执行方案
'knowledge',
'workspace',
'workspace/code',
'workspace/data',
'workspace/assets',
'conversations', // v5: 对话持久化
'logs',
];
export class AgentScaffold {
/**
* @param {string} agentsBaseDir - Agent 实例的根目录 (如 data/agents)
*/
constructor(agentsBaseDir) {
this.baseDir = agentsBaseDir;
}
/**
* 创建一个完整的 Agent 目录
*
* @param {Object} options
* @param {string} options.id - Agent 唯一标识 (如 'cxo-ceo-001')
* @param {string} options.type - Agent 类型 ('master' | 'cxo' | 'role' | 'skill')
* @param {string} options.name - 显示名称
* @param {string} [options.parentId] - 上级 Agent ID
* @param {string} [options.goalId] - 绑定的 Goal ID
* @param {Object} [options.bootstrap] - 自定义 Bootstrap Files 内容
*
* @returns {Promise<string>} 创建的 Agent 目录路径
*/
async create(options) {
const { id, type, name, parentId, goalId, bootstrap = {} } = options;
const agentDir = join(this.baseDir, id);
// 1. 创建目录结构
await this._createDirectories(agentDir);
// 2. 生成并写入 Bootstrap Files
await this._writeBootstrapFiles(agentDir, { id, type, name, parentId, ...bootstrap });
// 3. 写入 config.json
await this._writeConfig(agentDir, { id, type, name, parentId, goalId });
// 4. 写入 skills.md 空索引
await this._writeSkillsIndex(agentDir);
// 5. 写入 memory.md 空索引
await this._writeMemoryIndex(agentDir);
// 6. v5: 写入 todo.md + plan.md + hippocampus.md
await this._writeTodo(agentDir);
await this._writePlan(agentDir);
await this._writeHippocampus(agentDir);
// 7. v5: 写入 cron.json (定时任务声明)
await this._writeCronJson(agentDir, type);
return agentDir;
}
// ─────────────────────────────────────────
// 目录创建
// ─────────────────────────────────────────
async _createDirectories(agentDir) {
// 创建 agent 根目录
await mkdir(agentDir, { recursive: true });
// 创建所有标准子目录
for (const subdir of STANDARD_SUBDIRS) {
await mkdir(join(agentDir, subdir), { recursive: true });
}
}
// ─────────────────────────────────────────
// Bootstrap Files 生成
// ─────────────────────────────────────────
async _writeBootstrapFiles(agentDir, opts) {
const { id, type, name, parentId } = opts;
// agent.md — 如果上层提供了自定义内容则使用, 否则生成默认模板
const agentMd = opts.agentMd || this._defaultAgentMd(id, type, name);
await writeFile(join(agentDir, 'agent.md'), agentMd, 'utf-8');
// soul.md
const soulMd = opts.soulMd || this._defaultSoulMd(type, name);
await writeFile(join(agentDir, 'soul.md'), soulMd, 'utf-8');
// identity.md
const identityMd = opts.identityMd || this._defaultIdentityMd(type, name);
await writeFile(join(agentDir, 'identity.md'), identityMd, 'utf-8');
// user.md
const userMd = opts.userMd || this._defaultUserMd(parentId);
await writeFile(join(agentDir, 'user.md'), userMd, 'utf-8');
// tools.md
const toolsMd = opts.toolsMd || this._defaultToolsMd();
await writeFile(join(agentDir, 'tools.md'), toolsMd, 'utf-8');
// heartbeat.md
const heartbeatMd = opts.heartbeatMd || this._defaultHeartbeatMd(type);
await writeFile(join(agentDir, 'heartbeat.md'), heartbeatMd, 'utf-8');
}
// ─────────────────────────────────────────
// 默认模板
// ─────────────────────────────────────────
_defaultAgentMd(id, type, name) {
const toolsByType = {
master: [
'- cxo.create: 创建 CXO 战略层 Agent',
'- cxo.redefine: 调整 CXO 的职责定义',
'- cxo.destroy: 销毁 CXO Agent',
'- org.status: 查看全局组织状态',
'- goal.set: 设定公司 Goal',
],
cxo: [
'- role.create: 创建职能部门 Role Agent',
'- role.redefine: 调整部门职责定义',
'- role.destroy: 裁撤部门',
'- pipeline.set: 设计工作流',
'- pipeline.adjust: 调整工作流',
],
role: [
'- skill.create: 创建 Skill Agent',
'- skill.redefine: 调整 Skill 定义',
'- skill.destroy: 销毁 Skill Agent',
'- skill.reuse: 复用其他 Role 的 Skill',
],
skill: [
'# 无管理工具 — Skill 只负责执行, 不管理其他 Agent',
],
};
const tools = (toolsByType[type] || toolsByType.skill).join('\n');
return `# ${name}
## 身份
你是 ${name}。
## 职责
(待上层 Agent 定义)
## Never Rules
- 不要越级管理不属于你的 Agent
## Always Rules
- 按心跳频率主动检查工作进展
## 可用工具
${tools}
`;
}
_defaultSoulMd(type, name) {
return `# ${name} 的灵魂
## 思维方式
(待上层 Agent 定义)
## 沟通风格
- 清晰、简洁
## 价值观
- 高质量交付
- 持续改进
`;
}
_defaultIdentityMd(type, name) {
const emojiByType = { master: '👑', cxo: '👔', role: '🏢', skill: '⚙️' };
return `# 身份信息
## 基础信息
- 名称: ${name}
- Emoji: ${emojiByType[type] || '🤖'}
- 类型: ${type}
## 问候语
"你好,我是 ${name}。"
`;
}
_defaultUserMd(parentId) {
if (!parentId) {
return `# 上层上下文
## 我的上级
- 直接向用户汇报 (无上级 Agent)
## 用户偏好
(待用户定义)
`;
}
return `# 上层上下文
## 我的上级
- ${parentId}
## 上级偏好
(待上级 Agent 定义)
`;
}
_defaultToolsMd() {
return `# 工具使用备注
## 安全规则
- 不要在日志中输出 API Key
- 不要在 memory 中存储密码
- API Token 使用 env 变量, 不要硬编码
## 文件操作
- 所有自主创建的文件仅限在 workspace/ 内操作
`;
}
_defaultHeartbeatMd(type) {
const heartbeatByType = {
master: `# 心跳任务
> 使用 Claude Code 原生 CronCreate 工具创建定时调度。
## 首次对话时创建
### Plan 检查 (每 5 分钟)
CronCreate: \`*/5 * * * *\`
读取 plan.md,检查已分发任务的进度,更新状态。
### Todo 扫描 (每 3 分钟)
CronCreate: \`*/3 * * * *\`
读取 todo.md,按优先级执行未开始的任务。
### 日报 (每 30 分钟)
CronCreate: \`*/30 * * * *\`
统计所有 Agent 状态,写入 memory/daily/。
## 注意
- 任务仅在会话运行且空闲时触发
- 关闭会话后定时任务自动取消
- 循环任务 3 天后过期
`,
cxo: `# 心跳任务
> 使用 CronCreate 创建定时调度。
## 首次对话时创建
### 下属状态检查 (每 5 分钟)
CronCreate: \`*/5 * * * *\`
扫描下属 Agent 的 todo.md 和 plan.md,更新进度。
### 日报 (每小时)
CronCreate: \`0 * * * *\`
汇总关键指标,写入 memory/daily/。
`,
role: `# 心跳任务
## 每轮任务后
- [ ] 检查下属 Skill Agent 任务完成情况
- [ ] 评估产出质量
- [ ] 向上级汇报进展
## 每日
- [ ] 写入每日总结到 memory/daily/
`,
skill: `# 心跳任务
## 每次任务后
- [ ] 验证执行结果正确性
- [ ] 记录执行指标到 memory/
`,
};
return heartbeatByType[type] || heartbeatByType.skill;
}
// ─────────────────────────────────────────
// config.json 与索引文件
// ─────────────────────────────────────────
async _writeConfig(agentDir, opts) {
// 工具隔离策略:编排型 Agent 禁用所有原生工具,执行型保留全部
const TOOL_POLICY_BY_TYPE = {
master: { allowedTools: '' }, // 编排型:禁用全部原生工具
meta: { allowedTools: '' }, // 元 Agent:禁用全部原生工具
orchestrator: { allowedTools: '' }, // 编排型:禁用全部原生工具
cxo: { allowedTools: '' }, // CXO 战略层:禁用全部
role: {}, // 职能层:保留全部工具
skill: {}, // 执行层:保留全部工具
executor: {}, // 执行层:保留全部工具
};
const config = {
id: opts.id,
type: opts.type,
name: opts.name,
parent_id: opts.parentId || null,
goal_id: opts.goalId || null,
status: 'ready',
cli: {
toolPolicy: TOOL_POLICY_BY_TYPE[opts.type] || {},
},
gateway: { channels: [] },
api: { endpoints: [] },
mcp: { servers: [] },
sandbox: {
maxMemoryMB: 512,
maxDiskMB: 1024,
maxProcesses: 5,
},
};
await writeFile(
join(agentDir, 'config.json'),
JSON.stringify(config, null, 2),
'utf-8',
);
}
async _writeSkillsIndex(agentDir) {
const content = `# 我的技能
## 技能清单
(尚未添加技能)
## 说明
- 每个技能是 skills/ 目录下的一个子文件夹
- 每个技能文件夹内必须包含 SKILL.md 定义文件
`;
await writeFile(join(agentDir, '.claude/skills', 'skills.md'), content, 'utf-8');
}
async _writeMemoryIndex(agentDir) {
const content = `# 我的记忆
## 关键事实
(尚无记录)
## 已验证的模式
(尚无记录)
## 失败教训
(尚无记录)
`;
await writeFile(join(agentDir, 'memory', 'memory.md'), content, 'utf-8');
}
// ─────────────────────────────────────────
// v5: 任务管理 + 认知架构
// ─────────────────────────────────────────
async _writeTodo(agentDir) {
const content = `# Todo List
> 收到的任务会自动追加到此表。按优先级顺序执行。
| # | 任务 | 状态 | 分配人 | 优先级 | 接收时间 | 上次检查 |
|---|------|------|--------|--------|----------|----------|
| | (暂无待办) | | | | | |
`;
await writeFile(join(agentDir, 'todo.md'), content, 'utf-8');
}
async _writePlan(agentDir) {
const content = `# Plan
> 将大任务分解为子任务,分配给下级 Agent,并定期检查进度。
| # | 子任务 | 责任人 | 状态 | 上次检查 | 备注 |
|---|--------|--------|------|----------|------|
| | (暂无计划) | | | | |
`;
await writeFile(join(agentDir, 'plan.md'), content, 'utf-8');
}
async _writeHippocampus(agentDir) {
const content = `# 海马体 — 经验记忆索引
> 记录过往处理过的情景模式。遇到相似任务时,优先调用小脑中的固化方案。
| # | 情景模式 | 匹配条件 | 方案文件 | 置信度 | 使用次数 | 上次使用 |
|---|---------|---------|---------|--------|---------|----------|
| | (暂无经验记录) | | | | | |
`;
await writeFile(join(agentDir, 'memory', 'hippocampus.md'), content, 'utf-8');
}
/**
* 写入 cron.json — 定时任务声明文件
* 会话重建时自动读取并注入 CronCreate 恢复指令
* 参考: docs/claude-code-cron.md
*/
async _writeCronJson(agentDir, type) {
const cronByType = {
master: [
{ schedule: '*/5 * * * *', prompt: '读取 plan.md,检查已分发任务的进度,更新状态。', recurring: true, enabled: true },
{ schedule: '*/3 * * * *', prompt: '读取 todo.md,按优先级执行未开始的任务。', recurring: true, enabled: true },
{ schedule: '*/30 * * * *', prompt: '统计所有 Agent 状态,写入 memory/daily/ 日报。', recurring: true, enabled: true },
],
cxo: [
{ schedule: '*/5 * * * *', prompt: '扫描下属 Agent 的 todo.md 和 plan.md,更新进度。', recurring: true, enabled: true },
{ schedule: '0 * * * *', prompt: '汇总关键指标,写入 memory/daily/ 日报。', recurring: true, enabled: true },
],
role: [
{ schedule: '*/10 * * * *', prompt: '读取 todo.md,检查未完成的任务并按优先级执行。', recurring: true, enabled: true },
],
skill: [
{ schedule: '*/10 * * * *', prompt: '读取 todo.md,检查未完成的任务并按优先级执行。', recurring: true, enabled: true },
],
};
const crons = cronByType[type] || cronByType.skill;
await writeFile(join(agentDir, 'cron.json'), JSON.stringify(crons, null, 2), 'utf-8');
}
}
export default AgentScaffold;