5c68bb9324
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
230 lines
19 KiB
HTML
230 lines
19 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Maestro · 任务执行规则参考</title>
|
||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,400;0,500;0,600;1,400&display=swap" rel="stylesheet">
|
||
<style>
|
||
:root{--bg:#0d0d0d;--bg2:#141414;--bg3:#1a1a1a;--border:#252525;--border2:#333;--text:#e8e8e8;--text2:#a0a0a0;--text3:#555;--cyan:#00d4d4;--cyan2:#009999;--green:#4ec94e;--green2:#2d6e2d;--amber:#f0a500;--amber2:#9c6a00;--violet:#9b7bff;--violet2:#6644cc;--red:#ff5555;--red2:#aa2222;--blue:#5599ff;--blue2:#2255cc;--code-bg:#0a0a0a;--shadow:0 4px 32px rgba(0,0,0,.7)}
|
||
*{box-sizing:border-box;margin:0;padding:0}
|
||
body{font-family:'IBM Plex Mono',monospace;background:var(--bg);color:var(--text);font-size:13px;line-height:1.7}
|
||
.topbar{position:sticky;top:0;z-index:100;background:var(--bg2);border-bottom:1px solid var(--border);height:48px;display:flex;align-items:center;padding:0 24px;gap:12px}
|
||
.topbar-brand{font-size:13px;font-weight:600;color:var(--cyan);letter-spacing:.06em}
|
||
.topbar-sub{font-size:11px;color:var(--text3)}
|
||
.topbar a{margin-left:auto;font-size:11px;color:var(--text3);text-decoration:none}
|
||
.topbar a:hover{color:var(--cyan)}
|
||
.wrap{max-width:1000px;margin:0 auto;padding:32px 24px 80px}
|
||
.lead{font-size:13px;color:var(--text2);margin:0 0 10px;line-height:1.8}
|
||
.lead strong{color:var(--text)}
|
||
.meta{font-size:11px;color:var(--text3);margin:0 0 26px}
|
||
h2{font-size:17px;color:var(--text);margin:36px 0 14px;padding-bottom:8px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:10px}
|
||
h2 .n{font-size:12px;color:var(--cyan);border:1px solid var(--cyan2);border-radius:4px;padding:1px 8px;font-weight:400}
|
||
h3{font-size:14px;color:var(--cyan);margin:22px 0 8px}
|
||
p{color:var(--text2);margin:8px 0}
|
||
strong{color:var(--text)}
|
||
em{color:var(--amber);font-style:normal}
|
||
code{font-family:inherit;background:var(--code-bg);border:1px solid var(--border);border-radius:3px;padding:1px 5px;color:var(--cyan);font-size:12px}
|
||
ul{margin:8px 0 8px 4px;padding-left:20px;color:var(--text2)}
|
||
ol{margin:8px 0 8px 4px;padding-left:22px;color:var(--text2)}
|
||
li{margin:4px 0}
|
||
li::marker{color:var(--green)}
|
||
table{width:100%;border-collapse:collapse;margin:12px 0;font-size:12px}
|
||
th,td{border:1px solid var(--border);padding:7px 10px;text-align:left;vertical-align:top}
|
||
th{background:var(--bg3);color:var(--text);font-weight:600}
|
||
td{color:var(--text2)}
|
||
td code,th code{font-size:11.5px}
|
||
.card{background:var(--bg2);border:1px solid var(--border);border-left:3px solid var(--cyan2);border-radius:6px;padding:14px 16px;margin:12px 0}
|
||
.card.violet{border-left-color:var(--violet2)}
|
||
.card.green{border-left-color:var(--green2)}
|
||
.card.amber{border-left-color:var(--amber2)}
|
||
.card.red{border-left-color:var(--red2)}
|
||
.card-ttl{font-size:13px;font-weight:600;color:var(--text);margin-bottom:6px;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
|
||
.tag{font-size:10px;padding:1px 7px;border-radius:3px;border:1px solid}
|
||
.tag.hard{color:var(--red);border-color:var(--red2);background:rgba(255,85,85,.08)}
|
||
.tag.med{color:var(--amber);border-color:var(--amber2);background:rgba(240,165,0,.08)}
|
||
.tag.easy{color:var(--green);border-color:var(--green2);background:rgba(78,201,78,.08)}
|
||
.tag.ro{color:var(--blue);border-color:var(--blue2);background:rgba(85,153,255,.08)}
|
||
.tag.wr{color:var(--violet);border-color:var(--violet2);background:rgba(155,123,255,.08)}
|
||
.note{background:rgba(0,212,212,.06);border:1px solid var(--cyan2);border-radius:5px;padding:10px 13px;margin:12px 0;font-size:12px;color:var(--text2)}
|
||
.note.warn{background:rgba(240,165,0,.06);border-color:var(--amber2)}
|
||
.note strong{color:var(--text)}
|
||
.foot{margin-top:40px;font-size:11px;color:var(--text3);border-top:1px solid var(--border);padding-top:14px}
|
||
.src{color:var(--text3);font-size:11px}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="topbar">
|
||
<span class="topbar-brand">MAESTRO</span>
|
||
<span class="topbar-sub">· 任务执行规则参考</span>
|
||
<a href="index.html">← 文档索引</a>
|
||
</div>
|
||
<div class="wrap">
|
||
<p class="lead">Maestro 后台 agent 处理任务的<strong>当前实现规则</strong>(非设计提案,是线上真实行为)。按<strong>复杂度路由</strong>分四类执行路径:① 任务拆解(HARD)· ② 方案撰写(MEDIUM)· ③ 任务执行(executor)· ④ 解冲突(conflict),外加跨类通用规则与模型档位。</p>
|
||
<p class="meta">真相源:<code>src/executor/runner.ts</code> · <code>src/daemon/orchestrator.ts</code> · <code>src/daemon/ingest.ts</code> · <code>src/executor/pipeline.ts</code> · <code>src/executor/models.ts</code> · <code>src/model/status.ts</code>。如与代码不符,以代码为准。</p>
|
||
|
||
<!-- ───────── 概览 ───────── -->
|
||
<h2><span class="n">0</span> 复杂度 → 生命周期路由</h2>
|
||
<p>任务按 <code>complexity</code>(可由 <code>auto</code> 让模型判定)走不同路径;只有产生代码改动的任务才过 <code>exec_review</code>(双复审 + 合并)。</p>
|
||
<table>
|
||
<thead><tr><th>复杂度</th><th>路径</th><th>人审闸</th><th>谁来做</th></tr></thead>
|
||
<tbody>
|
||
<tr><td><span class="tag easy">EASY</span></td><td><code>init → ready → queued → executing → exec_review → done</code></td><td>exec_review</td><td>executor(直接执行)</td></tr>
|
||
<tr><td><span class="tag med">MEDIUM</span></td><td><code>init → speccing → spec_review → ready → … → exec_review → done</code></td><td>spec_review + exec_review</td><td>planner 写方案 → executor 执行</td></tr>
|
||
<tr><td><span class="tag hard">HARD</span></td><td><code>init → analyzing → plan_review → decomposed →(子任务各自跑)→ done</code></td><td>plan_review +(各子任务的闸)</td><td>planner 拆解 → 子任务递归</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<div class="note">三种 run 类型(<code>runs.kind</code>):<strong>planner</strong>(拆解 HARD / 写 MEDIUM 方案,只读)· <strong>executor</strong>(worktree 内改代码)· <strong>reviewer / security</strong>(执行后双复审,只读)· <strong>conflict</strong>(解合并冲突,本会话新增)。</div>
|
||
|
||
<!-- ───────── ① 拆解 ───────── -->
|
||
<h2><span class="n">①</span> 任务拆解(decompose)<span class="tag hard">HARD only</span> <span class="tag ro">只读</span></h2>
|
||
<div class="card">
|
||
<div class="card-ttl">触发 + 执行环境</div>
|
||
<ul>
|
||
<li>仅 <strong>HARD</strong> 任务拆解;编排器把它领进 <code>analyzing</code> 态,起一个 <strong>planner run</strong>。</li>
|
||
<li><strong>只读</strong>:cwd = 主仓(<em>不建 worktree、不改任何文件</em>);工具白名单仅 <code>Read / Glob / Grep</code> + <code>Bash(git log/diff/show)</code>。</li>
|
||
<li>模型:planner 档,<strong>默认 <code>claude-opus-4-8</code></strong>(项目可配);<code>maxTurns=90</code>。</li>
|
||
<li>触发前提:叶子任务 · 不在退避冷却 · 依赖全 <code>done</code> · 项目 <code>autonomy ≠ manual</code>。</li>
|
||
</ul>
|
||
</div>
|
||
<div class="card">
|
||
<div class="card-ttl">拆解约束(prompt 硬性要求)</div>
|
||
<ul>
|
||
<li>拆成 <strong>2–6 个</strong>更小、可独立交付的子任务。</li>
|
||
<li><strong>层级闸</strong>:<code>depth ≤ 4</code>(根=1),prompt 注入「剩余可拆层数」;子任务只有在<em>剩余层数 > 0</em> 时才允许再标 <code>hard</code>(防无限拆)。</li>
|
||
<li>每个子任务 5 个字段:<code>title</code> · <code>complexity</code>(easy/medium/hard) · <code>priority</code>(0/1/2) · <code>deps</code>(依赖<em>本列表的 0-based 序号</em>) · <code>files</code>(文件范围 glob)。</li>
|
||
<li><code>files</code> = 该子任务预计改动的文件范围;执行时改<strong>越界文件会被硬闸拦截</strong>,故须尽量精确,不确定留空数组(不限)。</li>
|
||
</ul>
|
||
</div>
|
||
<div class="card">
|
||
<div class="card-ttl">输出格式(三段)</div>
|
||
<ol>
|
||
<li><strong>Markdown 表格总览</strong>(序号 / 标题 / 复杂度 / 优先级 / 依赖 / 文件范围)——给人审看;</li>
|
||
<li>一段<strong>分析与拆解理由</strong>正文;</li>
|
||
<li>末尾<strong>唯一一个 fenced JSON</strong> <code>{plan, subtasks:[…]}</code>——给机器解析。解析失败 = planner 失败、退避重试。</li>
|
||
</ol>
|
||
</div>
|
||
<div class="card amber">
|
||
<div class="card-ttl">落库(ingest 处理结果)</div>
|
||
<ul>
|
||
<li>JSON 的 <code>plan</code>(一句话理由)→ 存父任务 <code>plan</code> 字段(即评审界面的「说明」);</li>
|
||
<li>每个 subtask 建成子任务:<code>priority</code>、<code>files→scopeFiles</code> 直接落库;<code>deps</code> 先全建好子任务再做<strong>「序号→taskId」二次映射</strong>写依赖;</li>
|
||
<li><strong>⚠ 表格 + 分析正文那两段被丢弃</strong>,只留在该 run 的 <em>transcript</em> 里(评审界面「拆解轨迹」可展开查看)。</li>
|
||
</ul>
|
||
</div>
|
||
<div class="card violet">
|
||
<div class="card-ttl">审批 + 之后调度</div>
|
||
<ul>
|
||
<li>默认 → 转 <code>plan_review</code> <strong>人审</strong>。</li>
|
||
<li><strong>可选自动放行</strong>(默认关):项目 <code>auto-approved</code> + <code>autoApprovePlan</code> 开 + 拆解结果<strong>全 easy</strong> + <strong>子任务数 ≤ 5</strong>,四条全满足才跳过人审直接 <code>decomposed</code>。</li>
|
||
<li>父任务在 <code>plan_review</code> / <code>analyzing</code> 期间,<strong>子任务被冻结</strong>(不可领取,UI 显示「待拆解确认」)。</li>
|
||
<li>批准后(plan_review→decomposed),子任务解冻,按 <strong>deps + priority</strong> 调度,<strong>各自独立 worktree</strong>(都从 main 拉出)执行、独立合并回 main。</li>
|
||
</ul>
|
||
</div>
|
||
<div class="card red">
|
||
<div class="card-ttl">失败 + 收口</div>
|
||
<ul>
|
||
<li>解析失败 / run 失败 → <code>failPlanAttempt</code> 退避重试,超 <code>maxRetries</code>(默认 2)→ 转 <code>needs_attention</code> 待人工;</li>
|
||
<li>父任务 <code>decomposed</code> 后,<strong>子任务全 done → 父任务自动 done</strong>。</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<!-- ───────── ② 方案 ───────── -->
|
||
<h2><span class="n">②</span> 方案撰写(spec)<span class="tag med">MEDIUM</span> <span class="tag ro">只读</span></h2>
|
||
<ul>
|
||
<li>MEDIUM 任务进 <code>speccing</code> 态,起 <strong>planner run</strong>(与拆解同为 planner kind,但只读写「方案」不拆子任务)。</li>
|
||
<li>只读跑在主仓;工具同拆解(Read/Glob/Grep + git 只读);<code>maxTurns=60</code>。</li>
|
||
<li>输出 = 一份 Markdown 方案正文(改动什么 / 为什么 / 验收),存任务 <code>spec</code> 字段。</li>
|
||
<li>→ 转 <code>spec_review</code> <strong>人审</strong>;批准后 → <code>ready</code> 进执行队列。reject 须带意见,回流 <code>speccing</code> 重写。</li>
|
||
</ul>
|
||
|
||
<!-- ───────── ③ 执行 ───────── -->
|
||
<h2><span class="n">③</span> 任务执行(executor)<span class="tag wr">改代码</span></h2>
|
||
<div class="card">
|
||
<div class="card-ttl">执行环境</div>
|
||
<ul>
|
||
<li>每个任务独立 <strong>worktree</strong>(分支 <code>maestro/<taskId></code>,从 <code>defaultBranch</code>(main) 拉出);<code>permissionMode=acceptEdits</code>。</li>
|
||
<li>工具:<code>Read/Edit/Write/Glob/Grep</code> + <code>git</code>(status/diff/log/add/commit,<em>无 push</em>) + 测试/构建(npm/go/pytest/make…,仍关在 worktree、不发包);<code>maxTurns=100</code>。</li>
|
||
<li>模型:executor 档(默认 opus-4-8,项目可配;旧 <code>project.model</code> 也覆盖 executor)。</li>
|
||
<li><strong>必须 commit</strong>,message 带任务 ID(<code>ensureCommitted</code> 兜底)。</li>
|
||
</ul>
|
||
</div>
|
||
<div class="card amber">
|
||
<div class="card-ttl">approve 前的硬闸(任一不过 = 不进 exec_review)</div>
|
||
<ol>
|
||
<li><strong>执行前同步 main + 分歧重评估(规则13)</strong>:起跑前把最新 <code>origin/main</code> 并进 worktree;若撞上<em>本任务声明范围内</em>的文件改动 → 转 <code>needs_attention</code> 待重评估(不盲目硬解)。</li>
|
||
<li><strong>verify 闸</strong>:项目 <code>verifyCmd</code> 在 worktree 内跑(10min,exit 0 才过;未配=视为通过)。</li>
|
||
<li><strong>分项检查闸 checks</strong>:独立的 lint / typecheck / build(项目可配,分项报告哪项挂)。</li>
|
||
<li><strong>diff 闸</strong>:体量超阈值、或改了<em>声明范围外文件</em>(task.scopeFiles 非空时)→ 拦截。</li>
|
||
<li><strong>双复审硬闸</strong>:code review + security audit <em>并行</em>跑(各只读、最强档不被 project.model 降档);<strong>任一 verdict=reject → 退回重执行</strong>(带复审意见),不进 exec_review。</li>
|
||
</ol>
|
||
</div>
|
||
<div class="card violet">
|
||
<div class="card-ttl">审批 + 合并</div>
|
||
<ul>
|
||
<li>全绿 → 转 <code>exec_review</code> <strong>人审</strong>;accept 触发 <code>--no-ff</code> 自动合并回 main(<code>merge:false</code> 可跳过合并)。</li>
|
||
<li><strong>可选自动放行</strong>(默认关):<code>auto-approved</code> + <code>autoApproveExec</code> 开 + 双复审均 approve → 跳过人审自动合并。</li>
|
||
<li>合并冲突 → 自动建 <strong>P0 解冲突补救任务</strong>(见 ④),原任务留 exec_review,补救成功后自动收口。</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<!-- ───────── ④ 解冲突 ───────── -->
|
||
<h2><span class="n">④</span> 解冲突(conflict)<span class="tag wr">改代码</span></h2>
|
||
<ul>
|
||
<li>exec_review 合并撞冲突时,自动建一个 <strong>P0 最高优先级</strong>补救任务,以专用 <code>runKind=conflict</code> 跑。</li>
|
||
<li>专用管线:worker 在补救 worktree 内<strong>真正发起 <code>git merge <原分支></code></strong> 触发冲突态,再交 CC 逐个解(白名单额外含 <code>Bash(git merge:*)</code>)。</li>
|
||
<li>专用 prompt:保留两边意图、解完跑测试验证、禁丢任一方改动、commit 沿用合并信息。</li>
|
||
<li>模型:conflict 角色,项目可配,<strong>默认 opus-4-8</strong>。</li>
|
||
<li>走 exec_review + 双复审;合并成功后<strong>自动收口</strong>原任务。P0 插队但<em>不中断在途任务</em>(No-preemption)。</li>
|
||
</ul>
|
||
|
||
<!-- ───────── 通用规则 ───────── -->
|
||
<h2><span class="n">⑤</span> 跨类通用规则</h2>
|
||
<table>
|
||
<thead><tr><th>规则</th><th>说明</th></tr></thead>
|
||
<tbody>
|
||
<tr><td><strong>执行期锁</strong></td><td>任务一旦有在途 run(planner/executor/reviewer/conflict)→ 锁定只读:禁改 title/spec/complexity/deps、禁再调度;run 结束(finish/fail/reap)解锁。</td></tr>
|
||
<tr><td><strong>worktree 隔离</strong></td><td>写类 run 只在自己 worktree 内改动,禁碰 worktree 外文件;planner/reviewer 只读、不建 worktree。</td></tr>
|
||
<tr><td><strong>不 push / 不部署</strong></td><td>任何 run 都不得 <code>git push</code> / 对外发布;解冲突的 merge 是受控本地合并。</td></tr>
|
||
<tr><td><strong>commit 含 task ID</strong></td><td>所有产出 commit message 必带任务 ID,<code>ensureCommitted</code> 兜底。</td></tr>
|
||
<tr><td><strong>重试退避 + 升级</strong></td><td>失败按退避重试,超 <code>maxRetries</code>(默认 2)→ <code>needs_attention</code> 转人工(planner 留原态、executor 走 failed)。</td></tr>
|
||
<tr><td><strong>自动放行默认关</strong></td><td>所有「跳过人审」(plan/exec)默认关闭,须项目级开关 + <code>auto-approved</code> 才生效。</td></tr>
|
||
<tr><td><strong>reject 必带意见</strong></td><td>plan/spec/exec 的驳回必须带 reason,按状态机回流重做。</td></tr>
|
||
<tr><td><strong>复审独立性</strong></td><td>复审只读、与执行分离、用最强模型、不被 <code>project.model</code> 降档;verdict=reject 是硬闸。</td></tr>
|
||
<tr><td><strong>daemon 唯一 DB 写者</strong></td><td>worker 不碰 DB,只读 job.json、写 outbox.ndjson;状态变更只经 <code>transition()</code> 守卫。</td></tr>
|
||
<tr><td><strong>超时分层</strong></td><td>planner/executor 30min(可配)· verify 10min · 复审 15min(并行)· conflict 给足强档时间。</td></tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<!-- ───────── 模型 ───────── -->
|
||
<h2><span class="n">⑥</span> 模型档位</h2>
|
||
<p>内置默认:<strong>每个角色 × 每个复杂度都是 <code>claude-opus-4-8</code></strong>(<code>DEFAULT_MODEL</code>)。可<strong>按项目</strong>经 <code>projects.models</code>(JSON) 配置。</p>
|
||
<p><strong>解析优先级</strong>(高→低):① <code>project.models[role]</code>(per-role,含 reviewer/conflict)→ ② 旧 <code>project.model</code>(仅 executor/planner)→ ③ env(<code>MAESTRO_MODEL_*</code> / <code>_REVIEW_*</code> / <code>_PLAN_*</code>)→ ④ <code>DEFAULT_MODEL</code>。</p>
|
||
<p>四角色:<code>executor</code> / <code>planner</code> / <code>reviewer</code> / <code>conflict</code>。不可用回退链:<code>opus-4-8 → sonnet-4-6 → fable-5</code>(单 run 内只重试一次)。</p>
|
||
<div class="note warn"><strong>注</strong>:<code>claude-fable-5</code> 在部分环境不可用,已移出内置默认;原「按复杂度分档(hard=fable / medium=opus / easy=sonnet)」的设计因此改为<strong>统一 opus-4-8 + 项目可配</strong>。</div>
|
||
|
||
<!-- ───────── 状态机 ───────── -->
|
||
<h2><span class="n">⑦</span> 关键状态转移</h2>
|
||
<table>
|
||
<thead><tr><th>从</th><th>到</th><th>触发</th></tr></thead>
|
||
<tbody>
|
||
<tr><td><code>init</code></td><td><code>analyzing</code> / <code>speccing</code> / <code>ready</code></td><td>按 hard / medium / easy 路由</td></tr>
|
||
<tr><td><code>analyzing</code></td><td><code>plan_review</code></td><td>拆解完成</td></tr>
|
||
<tr><td><code>plan_review</code></td><td><code>decomposed</code> / <code>analyzing</code></td><td>accept / reject(+意见)</td></tr>
|
||
<tr><td><code>speccing</code></td><td><code>spec_review</code></td><td>方案完成</td></tr>
|
||
<tr><td><code>spec_review</code></td><td><code>ready</code> / <code>speccing</code></td><td>accept / reject(+意见)</td></tr>
|
||
<tr><td><code>ready</code></td><td><code>queued</code> / <code>blocked</code></td><td>领取 / 依赖未满足</td></tr>
|
||
<tr><td><code>queued</code></td><td><code>executing</code></td><td>worker 起跑</td></tr>
|
||
<tr><td><code>executing</code></td><td><code>exec_review</code> / <code>failed</code></td><td>执行完成 / 失败</td></tr>
|
||
<tr><td><code>exec_review</code></td><td><code>done</code> / <code>ready</code></td><td>accept(合并) / reject(返工)</td></tr>
|
||
<tr><td><code>failed</code></td><td><code>queued</code> / <code>needs_attention</code></td><td>重试 / 超阈值</td></tr>
|
||
<tr><td><code>decomposed</code></td><td><code>done</code></td><td>子任务全 done</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class="src">完整合法转移表见 <code>src/model/status.ts</code> 的 <code>TRANSITIONS</code>;状态机/ER 全图见 <a href="optimization-plan.html" style="color:var(--cyan)">优化方案文档</a> ⑤⑥ 节。</p>
|
||
|
||
<div class="foot">单一入口见 <a href="index.html" style="color:var(--cyan)">docs/index.html</a> · 本文档描述当前线上规则,随实现演进更新 · 与代码不符以代码为准。</div>
|
||
</div>
|
||
</body>
|
||
</html>
|