/** * ═══════════════════════════════════════════════════════════════ * 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} 创建的 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;