① 架构决策总览
🗂 分期标注 :各章头部 Phase 1 = 本期核心重构(对应 ④具体实现 T1–T6);Phase 2 = 能力扩展(成本预算 / 安全沙箱 / 交互接管 / SSE 等);混合 = 章内分属两期,以卡片内标注为准。标注为建议范围 ,最终以实施计划为准。
六大核心决策
# 决策 选择 关键理由
D1 状态机架构 schedule_status × work_type 双轴 ,替代平铺 FSMschedule_status 对齐 OS 进程模型(OS 五态),描述资源调度;work_type 描述当前执行何种工作(plan/code/review/pr…);执行路径由混合模式动态决定,无需静态枚举所有路径
D2 任务类型扩展 work_type 注册表 (新类型 = 加 agent + dispatcher 分支)核心代码零改动;schedule_status 通用状态(ready/running/waiting…)完全复用,无需改状态机
D3 DB 状态存储 schedule_status + work_type + work_plan 队列(JSON) schedule_status / work_type 双列供 SQL 索引快速过滤与调度;work_plan 队列自带恢复位置,不引入 XState snapshot
D4 Agent 记忆 四层注入 (L1 失败原因 / L2 项目规范 / L3 跨任务上下文 / L4 全局规范)worker 不碰 DB,所有记忆由 daemon claimOne 组装进 job.json;ROI 由高到低
D5 流程硬闸 复审 reject 变硬闸 + 分项 checks + diff 体量闸 消除"复审仅建议"漏洞;静态检查前置防止无效执行进审批
D6 并发调度 CAS claimed_at + couplingPenalty(文件重叠降分) 防双重 claim 竞态;相同文件的任务并发执行概率降低,冲突减少
重构前后对比快览
现有设计(平铺 FSM)
• 16 状态平铺,全局 TRANSITIONS 表
• CANCEL/FAIL 每个子状态重复声明
• code + security 复审串行
• 暂停恢复需 paused_return_to 字段
• 新任务类型 = 修改核心转移表
• claimed_at 无 CAS,存在双重领取竞态
• reviewer reject 不挡流,仅建议
• agent prompt 无失败记忆 / 无规范注入
重构后(schedule × work_type + 四层记忆)
• schedule_status × work_type 双轴正交状态
• work_plan 队列动态决定执行路径(混合模式)
• waiting 人工闸不占并发名额,running 才占
• (paused, work_type) 自带恢复位置,无需额外字段
• 新 work_type = 加 agent + dispatcher 分支,零状态机改动
• CAS claimed_at + couplingPenalty 调度
• reviewer reject = 硬闸,回退重执行
• L1-L4 记忆注入 + 项目/全局规范
进程模型铁律(不改)
Daemon — 唯一 DB 写者
REST + WebSocket API(:4517)
Orchestrator 调度循环(ingest → reap → claim)
写 job.json 时组装全部记忆(L1-L4)
读 outbox.ndjson 入 DB,状态机 send(event)
Worker — 不碰 DB
读 runs/<runId>/job.json
执行 agent pipeline,追加 outbox.ndjson
任何 DB 数据 → daemon 组装进 job.json 下发
状态机 actor 在 daemon 侧管理
② 状态设计(schedule × work_type)Phase 1
任务提交与入口(Ingestion)
提交方式不变 ——主入口仍是网页表单 。提交后任务落 (init, 无 work_type),再由系统赋 work_type / 产 work_plan 进入调度。
三条入口
入口 路径 用途
网页表单 「+ 新建任务」→ POST /api/projects/:id/tasks 人手动提交(主入口 )
MCP 工具 create_task / decompose_taskClaude Code 会话 / agent 编程建任务
todo.json 同步 src/sync/ 单向同步legacy /todo 数据自动导入
GitHub issue(未来) webhook 入站 → 建任务 TODO #1 双向同步,本期不含
提交字段(极简 + 可选增强)
字段 必填? 说明
title✅ 必填 唯一硬要求
complexity默认 auto auto = LLM 异步分类回填(hard/medium/easy);也可手填
priority / deps可选 缺省 P2 / 无依赖
owned_files / scope / expected_output可选 新模型增强:喂调度 couplingPenalty + 给 planner 更准起点;缺省由 planner 补全
设计取向:提交极简(只逼 title),质量靠 planner 兜 ;可选字段让愿意填的人给更强的调度/拆解信号,但从不强制。
提交后流转
提交
→
(init, 无 work_type)
→
plan run:planner 产 work_plan
→
(ready, 首 work_type)
→
调度
Hard/Medium 走 plan(planner 拆解 / 写 spec 产 work_plan 队列);Easy 跳过 plan ,直接 work_plan=[code, review, pr] → ready。autonomy(manual / auto-easy / auto-approved)决定提交后是自动起跑 还是等人放行 。
附件支持(图片 / 文件)Phase 2
面 设计
表单 「+ 新建任务」支持拖拽 / 粘贴截图 + 上传文件 (bug 截图、设计稿、规格文档、数据样本)
API / 存储 POST /api/tasks/:id/attachments(multipart)→ 存 tasks/<taskId>/attachments/;tasks.attachments JSON 存 [{name, type, path}]
喂给 agent 附件路径随 job.json 下发 → worker 把图片直接喂进 agent 多模态输入 、文件作为 Read 目标;附件是任务上下文的一等部分(并入 ⑤ AgentContext)
AI 提任务(agent-initiated)Phase 2
已部分存在(MCP create_task + planner decompose 产子任务)。扩展为一等能力:
来源 设计
执行中衍生 agent 执行时发现额外工作 → 经 MCP 提关联任务 (parent / sibling),不打断当前 run
巡检 agent 可注册的 groomer agent(work_type,呼应 ⑤ 动态扩展)周期扫 repo / backlog / issue → 提议任务
来源标记 tasks.source(human|ai|sync|github)+ created_by(提交它的 agent run id),区分人提 vs AI 提
🛡 护栏 :AI 提的任务默认进「待确认新任务」人工闸 (不自动起跑),人审后才入调度——防 AI 自我增殖任务失控烧钱(呼应 ⑥ 预算护栏)。是否需人审由项目 autonomy + AI-task 开关决定;纯子任务拆解(planner decompose)已有 plan_review 闸覆盖。
schedule_status(调度状态,对齐 OS 进程模型)
状态 OS 类比 含义 可用 work_type
init New 任务刚创建,尚未确定执行路径,无 work_type —
ready Ready 有 work_type,等待 Orchestrator 调度 任意
running Running Worker 正在执行当前 work_type 对应的 agent 任意
waiting Blocked (I/O) 等待人工输入 (审批/拒绝),无 agent 在运行 保持完成步骤的 work_type(如 plan / review)
blocked Blocked (deps) 等待任务依赖 完成,deps 满足后自动回 ready 保持上次 work_type
paused Stopped 人工暂停,恢复时回到 ready(保持 work_type) 保持上次 work_type
failed Zombie 当前步骤失败,退避后自动重试(回 ready);超重试上限 → stuck 同失败时 work_type
stuck Stopped (wait human) 任务卡住需人工介入 :①重试耗尽 ②agent 主动上报歧义/不可解 ③审批超时兜底。自动化停止,等人决策 保持卡住时 work_type
done Terminated work_plan 队列全部完成,终态 —
cancelled Killed 人工取消,终态 —
✅ stuck 是一等 schedule_status 值,直接存 DB 列——可用 WHERE schedule_status = 'stuck' 直接查,无需 retry_count 联合判断。人工处理完成后可转 ready / done / cancelled。
work_type(工作类型,决定用哪个 Agent)
Agent 类型(schedule = ready → running)
work_type 执行者 主要工作
planPlanner Agent 分析任务,产出初始 work_plan(步骤队列 + 每步 spec)
codeExecutor Agent 在 worktree 里实现代码变更,commit
reviewReviewer Agent 代码审查 + 安全审计(run 内 Promise.all 并行),输出 verdict。独立 run 、不并入 code;可选 (work_plan 可省略)
prPR Agent review 通过后创建 PR + 完成合并(冲突 → conflict)
conflictConflict Agent git merge 制造冲突 → CC 解 → 复审
researchResearch Agent 技术调研,产出报告(无代码修改)
人工闸(schedule = waiting,无 Agent 运行)
waiting 的 work_type 直接沿用上一步完成时的值 ,不引入新枚举——waiting(plan) 等人审 plan 输出,waiting(review) 等人审代码复审结果。
当前 work_type 等待内容 通过 → 下一步 拒绝 → 下一步
plan人审 Planner 产出的 work_plan pop 队头,进 ready(下一 work_type) 重回 ready(plan),带拒绝原因重规划
review人审执行结果 + 复审 verdict pop → pr 步(提 PR + 合并)→ done ready(code),带拒绝原因重做
为什么 waiting ≠ running
人工闸没有 worker 进程在运行,Orchestrator 不应把并发名额算在它上面;running 才占名额,waiting 不占。
混合模式:下一步如何决定(Hybrid Next-Step)
Plan 阶段:产出初始 work_plan 队列
{
"type": "plan-complete",
"work_plan": [
{ "type": "code",
"spec": "实现 auth 模块",
"owned_files": ["src/auth/*.ts"],
"expected_output": "typecheck 通过" },
{ "type": "review" },
{ "type": "pr",
"spec": "创建 PR 到 main" }
]
}
// → waiting(plan) 等人审计划
// 人 approve → pop 队头 → ready(code)
执行阶段:每步可修改剩余队列
{
"type": "step-complete",
"result": "发现 auth 复杂,拆成2步",
"update_plan": [ // ← 可选,修改剩余队列
{ "type": "code",
"spec": "先实现 session 层" },
{ "type": "code", // ← 动态插入新步骤
"spec": "再实现 token 层" },
{ "type": "review" }
]
}
// 无 update_plan → pop 队头继续
// update_plan 非空 → 替换剩余队列
队列为空时
step-complete 后 work_plan 队列为空 → schedule_status = done,任务完成。
Easy 任务无需 plan 步骤:init 时 Orchestrator 直接写入默认队列 [code, review],跳过 plan。
完整转移规则
init
ready
running
waiting
done
paused
blocked
failed
stuck
cancelled
写入队列
claim
plan/review done
review approve→pr
approve / reject
pr merge
code→review (auto)
error
retry
retry 耗尽
agent 上报
人工: 重试
人工: 完成
人工: 取消
deps⬇
deps✓
暂停
恢复
自动
人工
异常
自动串联
执行路径示例
Hard 任务(需规划)
(init, -)
↓ Orchestrator 写队列 [plan, code, review, pr]
(ready, plan)
↓ worker 启动
(running, plan)
↓ plan 产出 work_plan(可拆多 code 步 / 决定免 review)
(waiting, plan)
↓ 人 approve
(ready, code) → (running, code)
↓ code agent 完成(commit;run 结束)
(running, review) ← 自动串联(独立 reviewer run,非 code 内联)
↓ review 完成(run 内并行双复审 verdict)
(waiting, review)
↓ 人 approve
(running, pr) ← approve 后串联
↓ pr agent 提 PR + 合并(冲突→conflict run)
done ✓
Easy 任务(跳过规划)
(init, -)
↓ Orchestrator 写队列 [code, review, pr]
(ready, code)
↓ worker 启动
(running, code)
↓ code agent 完成
(running, review) ← 自动串联(独立 reviewer run)
↓ review agent 完成
(waiting, review)
↓ 人 approve
(running, pr) → 提 PR + 合并 → done ✓
review 可选 :work_plan 不含 review 时,code 完成 → 直接 (running, pr);纯只读任务可仅 [research],无 code/review/pr。
动态拆步(运行中修改计划)
(running, code)
↓ agent 发现比预期复杂
↓ step-complete + update_plan:
[code(token层), review]
(ready, code) ← 新步骤(session 层)
(running, code) ← 再次 code(token 层)
(running, review) → (waiting, review) → done ✓
DB 字段(tasks 表关键变更)
字段 类型 说明
schedule_statusTEXT 取代旧 status:init|ready|running|waiting|blocked|paused|failed|stuck |done|cancelled
work_typeTEXT 当前工作类型:plan|code|review|pr|conflict|research|null
work_planTEXT JSON 剩余步骤队列 [{type, spec, owned_files, expected_output}]
work_historyTEXT JSON 已完成步骤记录(审计+重试上下文)
claimed_atTEXT CAS 锁,NULL=可领取,非NULL=已锁
Orchestrator 关键查询
-- 可调度任务(schedule 维度)
SELECT * FROM tasks
WHERE schedule_status = 'ready'
AND claimed_at IS NULL
AND (next_eligible_at IS NULL
OR next_eligible_at <= datetime('now'))
ORDER BY score DESC;
-- 派发 agent(work_type 维度)
switch (task.work_type) {
case 'plan': return runPlannerAgent(task);
case 'code': return runExecutorAgent(task);
case 'review': return runReviewerAgent(task);
case 'pr': return runPRAgent(task);
case 'conflict':return runConflictAgent(task);
}
⚠ waiting(人工闸)不占并发名额 :Orchestrator 的 inflight 计数只统计 schedule_status=running 的任务;waiting 的任务不计入,也不占 project.concurrency。
与旧设计对比
维度 旧设计(平铺 FSM) 新设计(schedule × work_type)
状态数量 16 个混合状态(analyzing/speccing/ready/executing/exec_review…) 10 个 schedule_status × N 个 work_type,正交组合
执行路径 静态,TRANSITIONS 表写死 动态,work_plan 队列运行时决定
新增工作类型 改 TRANSITIONS 表 + 加 status 枚举 加 work_type 枚举 + 加 agent dispatcher 分支
人工审批闸 plan_review/spec_review/exec_review 是独立 status(额外枚举) waiting(plan) / waiting(review),直接沿用卡住时 work_type,无新枚举
stuck 逻辑态:failed + retry_count ≥ max_retries 联合推导,无独立 DB 值 一等状态 :独立 DB 值,直接查询;人工处理后出 ready / done / cancelled
并发占用 所有非终态都计入 inflight 只有 running 计入 inflight;waiting / stuck 不占名额
暂停恢复 需 paused_return_to 字段记录位置 (paused, work_type) 自带位置,恢复即 (ready, same work_type)
可观测性 一个 status 字段,需要枚举含义 两个字段,(running, code) 直接表达"正在写代码"
实现复杂度 中(平铺 transition 守卫) 低(两字段 + 队列 pop/push)
并发调度(调度单位 · CAS 防双领 · couplingPenalty 错峰)
维度 决策
最小调度单位 task (一次一个 work_step);并发发生在不同 task 之间,不在 task 内部。work_plan 队列严格线性
阶段内并行 判据 = 是否需要独立 worktree / 写权限 :只读·汇总型 → agent 内 Promise.all(占 1 槽);需独立写 → 拆子任务交调度器(占 N 槽)
并行建模 并行 = 拆子任务 ,parent decomposed → 子全 done → done 做 join;不引入队列内并行分支节点(保队列模型简洁)
防双重 claim CAS claimed_at(见下);即「执行期锁」的 DB 落地
文件错峰 couplingPenalty(见下):与所有持未合并 worktree 的任务 (running + waiting(review) + 带改动 failed)的 owned_files 重叠扣分,软错峰非硬禁;agingBonus 兜底防饥饿
并发预算 槽只认 running;agent 内并行不额外占槽,调度器并行占 N 槽,project.concurrency 封顶
CAS 防双重 claim
-- 抢占:仅当未被锁定才成功
UPDATE tasks SET claimed_at = :now
WHERE id = :id AND claimed_at IS NULL ;
-- changes==1 → 抢到;==0 → 已被占,放弃
单条 SQL 行级原子,无论多少路径同时领同一任务,最多一个成功 。run 结束(finishRun / failAttempt / reap)置 NULL 释放。比"用 run.status 反推"更直接、可索引。
couplingPenalty 文件错峰
score(t) = rankU(t) + agingBonus(t)
− 0.5 × | t.owned_files ∩
(未合并 worktree 任务的 owned_files 并集) |
重叠越多分越低 → 越靠后领 → 大概率等冲突任务先跑完。按任务级 owned_files 并集算,覆盖所有分支上有未合并提交的任务 (running + waiting(review) 待合并 + 带改动 failed),不只 running ——否则 code 完进 waiting 等人审时分支已有提交,只看 running 会漏算、照样撞冲突。软错峰:实在没别的可干仍会跑,agingBonus 防永久饥饿。
阶段内并行:放调度器还是放 agent?
并行的性质 放哪 占槽 例子
共享同一 worktree、只读 / 汇总(不互相写) agent 自己并行 (worker 内 Promise.all)1 槽 双复审 code + security(都只读同一 diff)
各自要写、可隔离(不同文件 / 模块) 拆子任务交调度器 (各自 worktree)N 槽 feature 拆「auth 层」+「UI 层」
🔗 闭环 :planner 拆并行子任务时须给互斥的 owned_files ,它们才真并行;给重叠了 couplingPenalty 自动把它们串起来——拆解质量与调度错峰相互校正。 ⛔ 反模式 :同一 worktree 内多个写手并发(git index / 文件竞态)。要并行写就必须隔离 worktree,而隔离 worktree 即「子任务」——于是天然回到调度器并行。
交互平面 · stuck 任务人工接管(interactive run)Phase 2
自治流水线之外的第二执行平面 :任务卡在 stuck 时,人可「接管」,像终端一样与带完整上下文的 agent 长对话改完,再交回自治管道。不改造自治 Worker ,作为并列能力接入。
两个执行平面
维度 自治平面(现有) 交互平面(新增)
触发 orchestrator 按 score 调度 人显式接管(on-demand,POST /api/tasks/:id/takeover)
传输 纯文件 (job.json / outbox / heartbeat)实时双向 :runs/<runId>/console.sock(unix socket)↔ daemon ↔ 客户端 WS
节奏 跑完即退、可 reap 人驱动、按对话推进
重启可恢复 ✅ 文件协议保证 ❌ 牺牲,改由 session resume 找回
run kind plan / code / review / pr / conflict interactive
两平面共享 worktree / transcript+session / DB 状态(经 daemon)/ task 模型,只在传输 + 生命周期触发 上不同——自治内核保持纯净,交互作为边界清晰的独立能力。
接管会话流程
stuck
→
人点接管 /takeover
→
spawn interactive run(复用 worktree + resume session)
→
人 ↔ agent 长对话
→
人选出口
接管期间
schedule_status=running + run.kind=interactive
work_type 保持卡住时的值(不污染枚举)
reaper 对 interactive 关执行超时 ,heartbeat 仍发
idle-TTL 30min 无活动 → checkpoint session id → 退出 → 回 stuck;重连即 resume(挂起/恢复无缝)
结束出口(人选)
修好 → 交回:commit WIP,回 ready 进下一 work_type(review/pr)
修好 → 直接完成:走 pr / 合并 → done
放弃 → 回 stuck / cancelled
session id 落 work_history → 后续自治 run 可 resume,接管对话喂 L1–L4 记忆
关键决策(已定)
决策点 取定
schedule_status 复用 running + run.kind=interactive,不加状态枚举;reaper 单点特判
工具权限 有界可配 :项目级自定义白名单,但只能在允许超集 内勾选——effective = 用户选 ∩ 允许超集;git push / 部署等红线永不入超集
idle-TTL 30 分钟 挂起 + resume 重连
并发名额 占 1 个 project.concurrency(在用 worktree + agent),可单独配小池避免抢占自治吞吐
📦 Schema 影响极小 :runs.kind 扩枚举加 interactive(TEXT 兼容、非 work_type);session id 复用 work_history;console.sock 是 runs/<runId>/ 下的文件——无需新增列 。新增的是 daemon 的 takeover API + WS↔socket 桥接 + reaper 对 interactive 的特判 + 项目级 interactive_tools 配置(受允许超集约束)。
③ 数据库 Schema 变更Phase 1
★ 本方案新增 / 变更字段汇总(schedule × work_type 模型)
核心是 tasks 表的状态建模:用 schedule_status + work_type + work_plan 队列 取代旧 status 单字段;状态机以「队列驱动」实现(非 XState 快照),故 state_snapshot / sub_status 不引入。
表 字段 类型 用途 性质
tasksschedule_statusTEXT 调度状态机:init|ready|running|waiting|blocked|paused|failed|stuck |done|cancelled,取代旧 status 取代 status
taskswork_typeTEXT 当前工作类型,决定 dispatch 哪个 agent:plan|code|review|pr|conflict|research|null 新增
taskswork_planTEXT JSON 剩余步骤队列 [{type, spec, owned_files, expected_output}],运行时动态可改 新增
taskswork_historyTEXT JSON 已完成步骤记录(审计 + 重试上下文) 新增
tasksclaimed_atTEXT CAS 锁,NULL = 可领取、非 NULL = 已锁定(防双重领取) 新增
tasksversionINTEGER 乐观锁版本号,执行期任务修改检测 新增
tasksscopeTEXT file / module / service / cross-service 改动范围,喂调度 couplingPenalty 新增
tasksowned_filesTEXT JSON 任务声明的主要修改文件路径,喂 couplingPenalty 文件重叠 + diff 越界闸;planner decompose 给子任务赋值 新增
tasksexpected_outputTEXT 任务级一句话可验证完成标准(per-step 的在 work_plan 里) 新增
tasksattachmentsTEXT JSON 提交附件 [{name, type, path}](图片/文件);存 tasks/<id>/attachments/,喂 agent 多模态/Read 新增
taskssourceTEXT 任务来源 human|ai|sync|github;AI 提的默认进待确认闸 新增
taskscreated_byTEXT 创建者(人 / 提交它的 agent run id),配合 source 审计 新增
projectsagent_rulesTEXT 项目级 agent 专用规范(markdown),L2 记忆注入 新增
projectsdiff_max_filesINTEGER diff 体量闸阈值(默认 100 文件) 新增
projectschecksTEXT JSON 分项检查命令 {lint, typecheck, build}… 新增
projectsbudget_usdREAL 项目级预算上限(当期);当期 spend 超额 → 自动 paused 停领(见 ⑥ 护栏) 新增
projectsbudget_periodTEXT 预算周期 day|month(配合 budget_usd) 新增
runskindTEXT 对齐 work_type:plan|code|review|pr|conflict |research,外加 interactive (人工接管 run,非 work_type、不进调度队列) 扩枚举
runstrace_idTEXT 跨 run 追踪 ID,关联同任务多次运行 新增
runsusageTEXT JSON 每次模型调用的用量 [{model, input_tokens, output_tokens, cache_read, cache_write}],喂成本计算 新增
runscost_usdREAL 本 run 折算成本(按 模型×token 价目表);汇总到 task / project 新增
⛔ 已弃用(早期 XState 草案) :state_snapshot / sub_status(被 schedule_status + work_plan 队列取代)、task_type(任务性质由 work_plan 步骤组成表达,并入 work_type)、parent_version_id(无对应场景)。注:owned_files 同时存在「任务级」(声明级,喂调度/diff 闸)与「work_plan 每步级」(执行级,当前步声明),两者并存不冲突。
Entity Relationship 图(数据库表结构与关系)
projects
🔑 id TEXT PK
name TEXT
repo_path TEXT UNIQUE
default_branch TEXT
verify_cmd TEXT
autonomy TEXT
model TEXT
concurrency INTEGER
max_retries INTEGER
timeout_ms INTEGER
★ checks TEXT (JSON)
★ diff_max_files INTEGER
★ budget_usd REAL
★ budget_period TEXT
auto_approve_plan INTEGER
auto_approve_exec INTEGER
★ agent_rules TEXT
status TEXT
sort_order INTEGER
logo TEXT
last_sync_at TEXT
created_at TEXT
tasks
🔑 id TEXT PK
🔗 project_id → projects.id
🔗 parent_id → tasks.id (可空)
depth INTEGER
title TEXT
complexity TEXT
★ schedule_status TEXT
★ work_type TEXT
★ work_plan TEXT (JSON)
★ work_history TEXT (JSON)
priority INTEGER
deps TEXT (JSON)
★ scope TEXT
★ owned_files TEXT (JSON)
★ expected_output TEXT
★ claimed_at TEXT
★ version INTEGER
★ attachments TEXT (JSON)
★ source TEXT
★ created_by TEXT
result TEXT (JSON)
assignee TEXT
retry_baseline INTEGER
next_eligible_at TEXT
source_ref TEXT
created_at / updated_at TEXT
approvals
🔑 id TEXT PK
🔗 task_id → tasks.id
gate TEXT (plan|review)
action TEXT (accept|reject)
actor TEXT
reason TEXT
at TEXT
runs
🔑 id TEXT PK
🔗 task_id → tasks.id
kind TEXT (plan|code|review|pr|conflict|research)
★ trace_id TEXT
★ usage TEXT (JSON)
★ cost_usd REAL
worktree TEXT
branch TEXT
status TEXT
started_at / ended_at TEXT
transcript_ref TEXT
claude_session_id TEXT
error TEXT
worker_pid INTEGER
last_seq INTEGER
events
🔑 id TEXT PK
🔗 project_id (无 FK 约束)
🔗 task_id (可空, 无 FK 约束)
type TEXT
payload TEXT (JSON)
at TEXT
1:N
1:N
1:N
1:N
0..1:N (可空)
parent
图 例
★ = 本方案新增列
🔗 = 外键引用 🔑 = 主键
有 FK 约束
弱引用(无 FK)
关键字段说明
字段
所属表
含义
schedule_status
tasks
调度状态机,取代旧 status:init|ready|running|waiting|blocked|paused|failed|stuck|done|cancelled
work_type
tasks
当前工作类型,决定 dispatch 哪个 agent:plan|code|review|pr|conflict|research|null
work_plan
tasks
剩余步骤队列 [{type, spec, owned_files, expected_output}],运行时动态可改
work_history
tasks
已完成步骤记录,审计 + 重试上下文
claimed_at
tasks
CAS 锁,NULL=可领取、非 NULL=已锁定,防 Orchestrator 双重领取
version
tasks
乐观锁版本号,执行期任务修改检测(D6)
scope
tasks
改动范围 file/module/service/cross-service,喂调度 couplingPenalty
owned_files
tasks
任务声明的主要修改文件 JSON,喂 couplingPenalty 文件重叠 + diff 越界闸
expected_output
tasks
任务级一句话可验证完成标准(per-step 的在 work_plan 内)
agent_rules ★
projects
项目级 agent 专用规范文本,注入全部 agent prompt 头部(L2 记忆)
diff_max_files
projects
diff 体量闸阈值(默认 100),执行后改动文件数超限即拦截
checks
projects
分项静态检查命令 JSON {lint, typecheck, build},任一非 0 硬失败
budget_usd / budget_period
projects
项目级预算上限(当期 day|month),超额自动 paused 停领(⑥ 护栏)
kind
runs
run 类型,对齐 work_type:plan|code|review|pr|conflict|research + interactive(人工接管,非 work_type)
trace_id
runs
跨 run 追踪 ID,关联同一任务的多次运行
usage / cost_usd
runs
每次模型调用 token 用量 + 折算成本(模型×token 价目),汇总到 task / project
last_seq
runs
outbox.ndjson 已消费行号,daemon ingest 幂等重试游标
attachments
tasks
提交附件 [{name,type,path}](图片/文件),喂 agent 多模态 / Read
source / created_by
tasks
任务来源 human|ai|sync|github + 创建者,AI 提的默认进待确认闸
payload
events
事件附加数据 JSON,审计日志 + WebSocket 实时推送源
核心表说明
表 行数量级 作用 关键约束
projects少量(<100) 项目配置、自动化策略、并发/超时参数 repo_path UNIQUE
tasks中量(<10k) 任务主表,三类任务(hard/medium/easy)均在此表,以 complexity+status+run.kind 区分 FK project_id, parent_id(自引用)
approvals中量 审批闸记录(plan/spec/exec),reject 必须带 reason FK task_id
runs中量(<50k) 每次 agent 运行(planner/executor/reviewer/security/conflict),含 transcript 路径和 ingest 游标 FK task_id
events大量(仅追加) 审计日志 + WebSocket 实时推送源,无 FK 约束(高性能追加) INDEX (project_id, at)
★ 本方案新增列
projects.agent_rules (L2)
TEXT,项目级 agent 专用规范正文(markdown)
daemon 在 claimOne 写 job.json 时注入全部 4 类 agent 的 prompt 头部
文件:schema.sql + types.ts + mappers.ts + store.ts
非表字段(JobSpec.context)
protocol.ts 新增可选字段,由 daemon 组装、随 job.json 下发
内容:parentPlan(父任务拆解意图)+ siblings(兄弟任务状态摘要)
worker 读 job.json 即可,无需访问 DB
④ Agent 记忆注入P1 核心(L1) · P2(L2–L4)
当前缺口
buildPrompt executor:title/id + operations/spec/plan + 执行约束。无 lastRunError、无项目规范。
buildPlannerPrompt planner:title/id + 草稿 + depth。无 lastRunError、无项目规范。
buildReviewPrompt reviewer:任务要求 + 执行者自述 + diff 命令。无项目规范。
cc.ts:80 settingSources:['project'] → SDK 自动读项目 CLAUDE.md(现已生效 ✓)
task.lastRunError 字段已存在于 Task 类型,但从未注入任何 prompt
orchestrator claim 时拿到的 task 对象不带 last_run_error (仅审核 UI 子查询)
数据流铁律 → 决定方案形态
worker 进程完全不碰 DB ,只读 runs/<runId>/job.json(protocol.ts 铁律)
所有来自 DB 的记忆,必须由 daemon 在 claimOne 写 job.json 时组装进去
JobSpec 已携带完整 task + project 对象 → lastRunError 和 agentRules 天然可随 job.json 下发
L3 跨任务上下文 → 扩展 JobSpec.context? 可选字段
L1 — 注入 lastRunError(ROI 最高)
现状:last_run_error 是 pendingApprovals 子查询,claim 时的 task 不带它
改 store.ts:抽 lastRunErrorOf(taskId) 方法(复用现有子查询 SQL)
改 orchestrator.ts:claimOne 写 job 前赋值 task.lastRunError
改 runner.ts:3 处 build*Prompt 插「## 上次失败原因(重试任务)」段
5 行代码,零协议改动(字段已在 Task 上)
L2 — 项目级 agent 规范(存 DB projects 表)
schema.sql:projects 表加 agent_rules TEXT 列 + 幂等迁移
types.ts/mappers.ts:Project 加 agentRules?、row ↔ 字段映射
project 已随 job.json 下发 → worker 端 4 处 prompt 插「## 项目规范」头部
API/Web 编辑入口后续补;本期先打通存储+注入
L3 — 跨任务上下文
protocol.ts JobSpec 加 context?: { parentPlan?: string; siblings?: {...}[] }
store.ts:取 parent.plan + 同 parentId 兄弟摘要的方法
orchestrator.ts claimOne:若 task.parentId,组装 job.context 再下发
runner.ts buildPrompt:注入「## 拆解背景(父任务意图 + 兄弟状态)」
仅做 DB 读;不做 git 演化检索/RAG(留后续)
L4 — 全局 agent 规范(maestro 自维护)
不读 user 全局 ~/.claude/CLAUDE.md(避免个人习惯干扰受控执行)
settingSources:['project'] 保持不变
maestro 维护 ~/.maestro/agent-global.md
daemon 启动时读一次缓存,claimOne 随 job.json 下发,4 处 prompt 头部注入
文件不存在则跳过(可选,缺省空)
注入顺序(prompt 内记忆段排布)
[L4] ## 全局执行规范 →
[L2] ## 项目规范(必须遵守) →
[L3] ## 拆解背景(父任务意图 + 兄弟状态) →
## 任务内容 →
[L1] ## 上次失败原因(重试任务) →
## 执行约束
项目 CLAUDE.md 由 SDK 经 settingSources:['project'] 自动进 system prompt ,不在 user prompt 里重复。
⑤ Agent 规格与注册表Phase 1
Agent 注册表模型(work_type → AgentSpec,可动态扩展)
每个 work_type 对应一条 AgentSpec 。Orchestrator 派发 = 注册表查表 ,而非写死 switch。新增一种 agent = 注册一条 AgentSpec,调度内核 / 状态机零改动 。六个维度——流程 / 每步模型 / skills+subagents / prompt / 上下文 / 输出——全部声明在 AgentSpec 里。
interface AgentSpec {
workType: WorkType ; // 'plan'|'code'|'review'|'pr'|'conflict'|'research'|'writing'|…
runKind: string ; // 落 runs.kind
pickModel: (t, p) => ModelId ; // 每步档位(可按 complexity 分档)
tools: ToolPattern []; // 工具白名单(∩ 全局允许超集;红线永不入集)
skills?: SkillId []; // 注入的 skill(如 writing-plans / elements-of-style)
subagents?: AgentType []; // 可调度的 subagent(如 Explore / general-purpose)
needsWorktree: boolean ; // 写类 true(隔离改动)
buildPrompt: (ctx: AgentContext ) => string ; // 含 L1–L4 记忆
parseOutput: (raw: string ) => StepResult ; // 输出解析
gate?: 'plan' | 'review' | null ; // 完成后的人工闸
maxTurns: number ;
preempt?: boolean ; // 抢占调度(如 conflict)
}
// 派发 = 查表,不是写死 switch
const spec = AGENT_REGISTRY [task.work_type];
await spec.run (task); // run 内:buildPrompt → cc(model,tools,skills) → parseOutput → gate
AgentContext(上下文,daemon 在 claim 时组装进 job.json) :
{
task, project, // job.json 携带
step, // work_plan 当前步 {type, spec, owned_files, expected_output}
memory: { global, // L4 全局规范
projectRules,// L2 项目 agent_rules
decompCtx, // L3 父任务意图 + 兄弟状态
lastError },// L1 上次失败
diff?, reviewerNotes? // review / pr 用
}
plan Planner Agent
维度 内容
触发 (ready, plan);Hard→decompose / Medium→spec;只读、不建 worktree
流程 buildPlannerPrompt → runPlanner(CC 只读) → 解析输出 → (waiting, plan) 人审
模型/档 easy=sonnet-4-6 · medium=opus-4-8 · hard=opus-4-8(最强档)
skills/subagent skill superpowers:writing-plans(拆解质量);subagent Explore(大范围只读检索代码演化)
tools Read / Glob / Grep + Bash(git log/diff/show);maxTurns 90/60/40
prompt title/id + spec/plan 草稿 + depth + 剩余可拆层(≤3) + 「产子任务表格(人审) + 末尾 fenced JSON」
上下文 L4 全局 → L2 项目规范 → L3 拆解背景 → 任务内容 → L1 上次失败;project CLAUDE.md 经 settingSources 入 system
输出 decompose: 表格 + JSON{title,complexity,priority,deps,owned_files,expected_output};spec: 三段 md(改动/为什么/验收)
code Executor Agent
维度 内容
触发 (ready, code);建 worktree (隔离写)
流程 syncMain → createWorktree → buildPrompt → runTask(CC, acceptEdits) → 必须 commit → verify → checks 闸 → diff 体量闸
模型/档 easy=sonnet-4-6 · medium/hard=opus-4-8
skills/subagent subagent general-purpose / Explore(并行只读调研、省主上下文);skill:项目可配领域 skill
tools Read/Edit/Write/Glob/Grep + Bash(git 无 push , test) + WebSearch;maxTurns 100
prompt title/id + operations??spec??plan + owned_files 范围 + expected_output + 执行约束(禁越界 / 必 commit 含任务 ID)
上下文 L1–L4 + work_plan 当前 step.spec / step.owned_files
输出 执行自述 + 含任务 ID 的 commit
review Reviewer Agent
维度 内容
触发 (ready, review);code 完成自动串联;独立 run、只读 、可选
流程 Promise.all(reviewCode, reviewSecurity) 并行 → 合并 verdict → reject 硬拦截(回 code) / pass → (waiting, review)
模型/档 三档统一 opus-4-8(最强,不被 project.model 降档 ,保自审严格度)
skills/subagent skill:code-review 清单 / 安全审计清单;无 subagent (聚焦审单一 diff)
tools Read/Glob/Grep + Bash(git diff/show/log);maxTurns 40;不写、复用 code 的 worktree 只读
prompt 任务要求 + 执行者自述 + worktreeDiff + 「输出 VERDICT 模板(pass/reject + 理由)」
上下文 任务 spec + code 自述 + diff + L2 项目规范
输出 双 verdict + 意见;任一 reject → 硬退回 code(带意见)
pr PR Agent
维度 内容
触发 review 通过后 (ready, pr)
流程 创建 PR(gh) → --no-ff 合并 → 冲突? → 建 conflict run : done
模型/档 opus-4-8(PR 文案 / 合并决策;多为确定性操作)
skills/subagent skill:PR 描述模板;无 subagent
tools Bash(git, gh —受控 :建 PR / 合并,禁强推 );不建新 worktree
prompt 任务摘要 + commit 列表 + 关联 issue + PR 模板
上下文 任务 + 分支 + diff 摘要 + review 结论
输出 PR url + merge 结果(成功 → done / 冲突 → conflict run)
conflict Conflict Agent
维度 内容
触发 pr 合并冲突自动建(抢占调度 ,不排队等 score)
流程 补救 worktree git merge 制造冲突 → CC 解(保两边意图) → 跑测试 → commit → 双复审
模型/档 opus-4-8 固定(最强,不随原任务复杂度降档)
skills/subagent skill:解冲突纪律(禁丢任一方改动 / 解完验证);subagent Explore(查两边意图)
tools Read/Edit/Write + Bash(git merge —仅此分支 白名单, test)
prompt 专用解冲突模板(保留两边意图 + 禁丢改动 + 解完跑测试 + commit 沿用合并信息)
上下文 两分支 diff + 冲突文件 + 原任务意图 + L1 上次失败
输出 解冲突自述(解了哪些文件 / 取舍 / 测试结果)+ commit
另有 research(纯只读调研,不写、无 gate)与 interactive(人工接管,见「交互平面」专题)两个 work_type,规格同样登记在 AGENT_REGISTRY。
动态新增 Agent(写作 / 视频发布 示例)
三步加一个 agent :① work_type / runs.kind 加枚举值(TEXT 兼容、无需改表结构)→ ② 写一条 AgentSpec 注册进 AGENT_REGISTRY → ③(可选)模型档位表 + 工具允许超集补该角色。调度器 / 状态机零改动 ——一旦某任务的 work_plan 含该 work_type,Orchestrator 自动按注册表派发。
// 示例 1:写作 agent(后期加内容生产能力)
AGENT_REGISTRY ['writing' ] = {
workType:'writing' , runKind:'writing' ,
pickModel: () => 'claude-opus-4-8' ,
tools:['Read' ,'Write' ,'WebSearch' ], needsWorktree:true ,
skills:['elements-of-style:writing-clearly-and-concisely' ],
subagents:['Explore' ], // 查资料
buildPrompt: ctx => 写作 brief + L2 项目文风规范 + 素材,
gate:'review' , // 产出走人审
maxTurns:60,
};
// 示例 2:自动发视频 agent(对外副作用,须显式授权)
AGENT_REGISTRY ['video-publish' ] = {
workType:'video-publish' , runKind:'video-publish' ,
pickModel: () => 'claude-opus-4-8' ,
tools:['Read' ,'Bash(ffmpeg:*)' ,'Bash(youtube-upload:*)' ], // 受控发布工具
needsWorktree:false ,
buildPrompt: ctx => 视频元数据 + 平台 + 发布策略,
gate:'review' , // 对外发布强制人审闸
maxTurns:30,
};
🛡 红线护栏 :对外产生副作用的 agent(发布 / 部署 / push)默认强制 gate:'review' 人工闸,且工具受允许超集 约束——「未审不发」是硬约束,新 agent 不能绕过。纯生产/只读 agent(writing 草稿、research)可配 gate:null 自动放行。
⑥ 运维与护栏(Ops & Guardrails)Phase 2
成本与预算治理(精确到项目 · 按 模型 × token 计费)
自治系统自动 spawn 付费 agent,必须有成本闸防失控烧钱 。每个 run 从 Agent SDK 抓 token 用量 → 按每模型 价目算成本 → 落库 → 汇总到 task / project → 项目级预算闸 超额自动停领。
// 1. 每次模型调用的用量落 runs.usage(cc.ts 从 SDK message.usage 抓)
runs.usage = [{ model, input_tokens, output_tokens, cache_read, cache_write }, …]
// 2. 价目表($/Mtok,各模型 in/out/cache 单价不同)
const MODEL_PRICES = {
'claude-opus-4-8' : { in:15, out:75, cacheRead:1.5, cacheWrite:18.75 },
'claude-sonnet-4-6' : { in:3, out:15, cacheRead:0.3, cacheWrite:3.75 },
'claude-haiku-4-5' : { in:1, out:5, cacheRead:0.1, cacheWrite:1.25 },
};
// 3. run 成本 = Σ 每次调用(按该次的 model 单价)
cost_usd = Σ ( in_tok·P.in + out_tok·P.out + cache_read·P.cacheRead + cache_write·P.cacheWrite ) / 1e6
// 4. 汇总:task.cost = Σ runs.cost_usd ; project 当期 spend = Σ task.cost(按 budget_period)
// 5. 项目级预算闸(Orchestrator claim 前)
if (project.budget_usd && periodSpend(project, project.budget_period) >= project.budget_usd) {
pauseProject(project); // 新任务不再领取;在途 run 跑完不打断;通知人工
continue ;
}
维度 设计
计费粒度 per 模型调用 → per run(runs.cost_usd)→ per task → per project(当期)
预算闸 projects.budget_usd + budget_period(day|month);超额 → project 自动 paused 停领,可单独配全局日上限做二级保险
消费端 /api/usage(成本明细:项目/模型/时段)与 /api/metrics 由此填充,不再是空端点
价目维护 价目表为代码常量,模型变更/调价改一处;缓存命中(cacheRead)显著降本,纳入计算
限流与全局并发背压
机制 设计
两层并发闸 project.concurrency(单项目)+ 新增 MAESTRO_MAX_INFLIGHT(全局在途上限) ;claim 受 min(项目闸, 全局闸) —— 防多项目×并发把 API 打爆
API 429 / overloaded cc.ts 捕获 Anthropic 限流 → run 标 throttled(不计任务失败 、不消耗 max_retries)→ 退避后重排;与 failAttempt 严格区分
spawn 速率 令牌桶限制每秒新起 worker 数,避免 tick 一次性雷鸣群(thundering herd)冲击 API + 磁盘
与成本闸协同 budget 超 → 停领 (不再 claim);429 → 慢领 (退避);两者正交叠加
资源生命周期与 GC
资源 回收策略
worktree task done/cancelled/reap 后删 worktree;已合并 的临时分支删除,未合并 分支保留待人查
runs/<runId>/job.json / outbox / heartbeat / transcript 保留 retention_days(可配)→ 过期归档或删;transcript 大文件单独策略
events 表append-only → 定期 rollup (旧事件按 task 聚合)/ 归档到冷表,防无限增长拖慢看板查询
启动 GC daemon 启动扫孤儿 worktree (无对应活跃 run)→ 清理;扫残留 runs 目录对账
SQLite 周期 WAL checkpoint + 低峰 VACUUM,控制 DB 文件膨胀
可观测性(metrics / health / trace)
面 内容
/api/metrics队列深度(各 schedule_status 计数)· 吞吐(done/h)· agent 时延 + turn 数分布 · review 通过/reject 率 · 成本(per project / model)
/api/healthdaemon 存活 + DB 可写 + 在途 worker 数 + 最近一次 tick 时间(探活/告警用)
trace_id JobSpec.traceId 贯穿 outbox 每条 → 串起一次任务跨多 run(plan→code→review→pr)的全链;从 Phase 2 提前为一等公民 (成本/排障都依赖它聚合)
审计源 events 表已是审计 + WS 推送源,metrics 在其上做聚合,不另起存储
依赖图完整性(环检测 / 死锁)
时机 设计
decompose 落库时 planner 产出 deps → 建边前跑环检测 (拓扑排序 / DFS);发现环 → 拒绝该 decompose 结果 + planner 重试(带「deps 成环,请重排」意见)
运行时死锁 若存在非终态 task 但可运行集为空 (全部 blocked 互等)→ 标记死锁 + 通知人工,不空转
防御(prompt) planner prompt 明确「deps 用子任务序号引用、禁自环 / 互环」,从源头降低成环概率
⑦ 安全与沙箱(Security & Sandbox)Phase 2
安全模型(沙箱 · 凭证 · 脱敏 · 对外授权)
面 设计
沙箱 MAESTRO_SANDBOX:worker 进程 OS 级写围栏 (只允许写自己的 worktree + runs/<runId>/)+ ulimits(CPU/内存/fd);配置落 sandbox.sb。默认 off,生产建议 on
工具红线(全局) 任何 agent 不可逾越:禁 git push / 禁部署 / 禁对外发布 (除非显式授权 agent + 人审闸);实际工具 = AgentSpec.tools ∩ 全局允许超集,红线永不入超集
凭证 git / API 凭证不写进 worktree、不入 job.json ;由 daemon 以最小权限注入 worker env,按 run 生命周期回收;解冲突/PR 的 git 操作受控、不外推
secret 脱敏 outbox / transcript / events 落盘前过滤已知 secret 模式(token / key / 凭证),防泄漏到审计层与看板
对外副作用授权 产生外部副作用的 agent(video-publish / deploy)强制 gate:'review' 人审闸 + 项目级显式开关 ,未授权不执行——「未审不对外」是硬约束
与 ⑤ Agent 规格的工具白名单、交互平面的「有界可配工具」一脉相承:能力按需授予、红线全局兜底、对外副作用强制人审 。
⑧ 前端 API 契约(REST + WS)P1 现有 · P2 ★新路由
统一约定
项 约定
Base URL http://127.0.0.1:4517(MAESTRO_PORT);仅本地监听
Content-Type application/json;附件上传用 multipart/form-data;SSE 为 text/event-stream
鉴权 本地无鉴权(仅 127.0.0.1);如需远程暴露另加(本期不含)
错误格式 统一 { "error": "<message>" };StoreError → 400 、不存在 → 404 、状态机非法转移 → 400、内部 → 500
时间字段 ISO8601 字符串(TEXT)
Projects API
方法 路径 请求体(关键字段) 响应
GET /api/projects— Project[]
POST /api/projects{name*, repoPath*, defaultBranch?, autonomy?, concurrency?, model?}Project
GET /api/projects/:id— Project
PATCH /api/projects/:id部分字段:autonomy / concurrency / model / budget_usd / budget_period / checks / agent_rules / diff_max_files / verify_cmd Project
DELETE /api/projects/:id— {ok}
POST /api/projects/:id/sync— {created, done, skipped}
POST /api/projects/reorder{order: id[]}{ok}
GET /api/projects/:id/tasks— Task[](任务树)
GET /api/projects/:id/events— Event[]
Tasks API
方法 路径 请求体(关键字段) 响应
POST /api/projects/:id/tasks{title*, complexity?(auto|hard|medium|easy), priority?, deps?, parentId?, owned_files?, scope?, expected_output?}Task
GET /api/tasks/:id— Task
POST /api/tasks/:id/plan{plan*}Task
POST /api/tasks/:id/spec{spec*}Task
POST /api/tasks/:id/decide{action: accept|reject, actor?, reason?, merge?}(人工闸)Task
POST /api/tasks/:id/transition{to*, meta?}(守卫校验合法转移)Task
POST /api/tasks/:id/requeue— Task
POST /api/tasks/:id/cancel— Task
DELETE /api/tasks/:id— {ok}
POST ★ /api/tasks/:id/attachmentsmultipart: files[](图片/文件){attachments:[{name,type,path}]}
POST ★ /api/tasks/:id/takeover—(起交互接管 run) {runId, console}
Runs / 观测 API
方法 路径 请求体 / 查询 响应
GET /api/tasks/:id/runs— Run[]
GET /api/runs/:id/transcript— text/ndjson(transcript)
GET /api/tasks/:id/events— Event[]
GET ★ /api/tasks/:id/stream— text/event-stream(agent token SSE,Phase 2)
GET /api/agents— AgentSpec[](注册表)
GET ★ /api/usage?project&period{byProject, byModel, total} 成本明细
GET ★ /api/metrics— {queueDepth, throughput, latency, reviewPassRate, cost}
GET ★ /api/health— {ok, db, inflight, lastTickAt}
WebSocket 事件契约(/ws)
连接 ws://127.0.0.1:4517/ws,连上后服务端单向推送 (客户端无需发消息)。每条消息 = 一行 events 表记录,前端据 type 增量更新看板,无需轮询 。
// 消息封装(JSON)
{ type, projectId, taskId, payload, at }
type 触发 payload 关键
task.created新任务(任意入口) task
task.updated任务字段变更 task / 变更字段
status.changedschedule_status 变更from / to / work_type
complexity.changedAUTO 复杂度回填 complexity / reason
run.startedworker 起跑 runId / kind
run.finishedrun 结束 runId / result
approval.granted / approval.rejected人工闸决策 gate / reason
merge.failed / merge.remediated合并冲突 / 收口 branch
project.syncedtodo 同步完成 created / done / skipped
run.progress ★SSE 配套(Phase 2) runId / token 增量
budget.exceeded ★项目当期成本超预算 projectId / spend / budget
★ = 本次重构新增路由 / 事件。完整 Task / Project / Run / Event 结构见 ③ 数据库 Schema 的字段表(响应体即各表行的 camelCase 映射)。