name: workflow-req-plan description: 需求级渐进式路线图规划与问题创建。将需求分解为收敛层或任务序列,通过 ccw issue create 创建问题,并生成 roadmap.md 供人工审查。问题存储在 .workflow/issues/issues.jsonl(单一事实来源)。 argument-hint: “[-y|–yes] [-c|–continue] [-m|–mode progressive|direct|auto] "需求描述"” allowed-tools: spawn_agent, wait, send_input, close_agent, AskUserQuestion, Read, Write, Edit, Bash, Glob, Grep
工作流 需求规划
使用方式
$workflow-req-plan "实现用户认证系统,支持 OAuth 和 2FA"
# 选择模式
$workflow-req-plan -m progressive "构建实时通知系统" # 分层 MVP→迭代
$workflow-req-plan -m direct "重构支付模块" # 拓扑排序任务序列
$workflow-req-plan -m auto "添加数据导出功能" # 自动选择策略
# 继续现有会话
$workflow-req-plan --continue "用户认证系统"
# 自动模式(跳过所有确认)
$workflow-req-plan -y "实现缓存层"
# 标志
-y, --yes 跳过所有确认(自动模式)
-c, --continue 继续现有会话
-m, --mode <progressive|direct|auto> 分解策略(默认:auto)
上下文来源:cli-explore-agent(可选)+ 需求分析
输出目录:.workflow/.req-plan/{会话-id}/
核心创新:需求分解 → 通过 ccw issue create 创建问题。问题存储在 .workflow/issues/issues.jsonl(单一事实来源);波次和依赖信息嵌入在问题标签和 extended_context.notes 中。team-planex 直接通过 ID 或标签查询消费问题。
概述
需求级分层路线图规划。将需求分解为 收敛层或任务序列,通过 ccw issue create 创建问题。问题是 .workflow/issues/issues.jsonl 中的单一事实来源;波次和依赖信息嵌入在问题标签和 extended_context.notes 中。
双重模式:
- 渐进式:分层 MVP→迭代,适用于高不确定性需求(先验证,后细化)
- 直接式:拓扑排序任务序列,适用于低不确定性需求(清晰任务,直接排序)
- 自动式:基于不确定性级别自动选择
核心工作流:需求理解 → 策略选择 → 上下文收集(可选) → 分解 + 问题创建 → 验证 → team-planex 交接
执行过程
阶段 0:初始化
├─ 解析参数(--yes、--continue、--mode)
├─ 生成会话 ID(RPLAN-{slug}-{date})
└─ 创建会话文件夹
阶段 1:需求理解与策略选择
├─ 解析需求:目标 / 约束 / 利益方
├─ 评估不确定性级别
│ ├─ 高不确定性 → 推荐渐进式
│ └─ 低不确定性 → 推荐直接式
├─ ASK_USER:确认策略(-m 跳过,-y 自动选择)
└─ 写入 strategy-assessment.json + roadmap.md 骨架
阶段 2:上下文收集(可选,子代理)
├─ 检测代码库:package.json / go.mod / src / ...
├─ 有代码库 → spawn_agent cli-explore-agent
│ ├─ 探索相关模块和模式
│ ├─ wait 等待完成
│ └─ close_agent 关闭代理
└─ 无代码库 → 跳过,纯需求分解
阶段 3:分解与问题创建(内联代理)
├─ 步骤 3.1:CLI 辅助分解
│ ├─ 构建 CLI 提示,包含需求 + 上下文 + 模式
│ ├─ 执行 Gemini(备用:Qwen → 手动分解)
│ └─ 解析 CLI 输出为结构化记录
├─ 步骤 3.2:记录增强与验证
│ ├─ 根据模式验证每条记录
│ ├─ 增强收敛标准质量
│ ├─ 验证依赖图(无循环)
│ └─ 渐进式:验证范围;直接式:验证输入/输出
├─ 步骤 3.3:问题创建与输出生成
│ ├─ 内部记录 → 问题数据映射
│ ├─ 为每个项目创建 ccw issue(获取 ISS-xxx ID)
│ └─ 生成 roadmap.md 带问题 ID 引用
└─ 步骤 3.4:分解质量检查(强制)
├─ 执行 CLI 质量检查(Gemini,Qwen 备用)
└─ 决定:通过 / 自动修复 / 需要审查
阶段 4:验证与 team-planex 交接
├─ 显示分解结果(表格 + 收敛标准)
├─ ASK_USER:反馈循环(最多 5 轮)
└─ ASK_USER:下一步(team-planex / 波次执行 / 查看 / 完成)
输出
.workflow/.req-plan/RPLAN-{slug}-YYYY-MM-DD/
├── roadmap.md # 人类可读路线图,带问题 ID 引用
├── strategy-assessment.json # 策略评估结果
└── exploration-codebase.json # 代码库上下文(可选)
| 文件 | 阶段 | 描述 |
|---|---|---|
strategy-assessment.json |
1 | 不确定性分析 + 模式推荐 + 提取的目标/约束/利益方 |
roadmap.md(骨架) |
1 | 初始骨架带占位符,阶段 3 最终化 |
exploration-codebase.json |
2 | 代码库上下文:相关模块、模式、集成点(仅当代码库存在时) |
roadmap.md(最终) |
3 | 人类可读路线图,带问题 ID 引用、收敛详情、team-planex 执行指南 |
子代理 API 参考
spawn_agent
创建新子代理并分配任务。
const agentId = spawn_agent({
message: `
## 任务分配
### 强制第一步(代理执行)
1. **读取角色定义**:~/.codex/agents/{agent-type}.md(必须先读)
2. 读取:.workflow/project-tech.json
3. 读取:.workflow/project-guidelines.json
## 任务上下文
${taskContext}
## 可交付物
${deliverables}
`
})
wait
从子代理获取结果(唯一检索结果的方式)。
const result = wait({
ids: [agentId],
timeout_ms: 600000 // 10 分钟
})
if (result.timed_out) {
// 处理超时 - 可以发送输入提示完成
}
close_agent
清理子代理资源(不可逆)。
close_agent({ id: agentId })
实现
阶段 0:初始化
步骤 0:确定项目根目录
PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString()
// 解析参数
const args = "$ARGUMENTS"
const AUTO_YES = args.includes('--yes') || args.includes('-y')
const continueMode = args.includes('--continue') || args.includes('-c')
const modeMatch = args.match(/(?:--mode|-m)\s+(progressive|direct|auto)/)
const requestedMode = modeMatch ? modeMatch[1] : 'auto'
// 清理需求文本(移除标志)
const requirement = args
.replace(/--yes|-y|--continue|-c|--mode\s+\w+|-m\s+\w+/g, '')
.trim()
const slug = requirement.toLowerCase()
.replace(/[^a-z0-9\u4e00-\u9fa5]+/g, '-')
.substring(0, 40)
const dateStr = getUtc8ISOString().substring(0, 10)
const sessionId = `RPLAN-${slug}-${dateStr}`
const sessionFolder = `${projectRoot}/.workflow/.req-plan/${sessionId}`
bash(`mkdir -p ${sessionFolder}`)
// 实用函数
function fileExists(p) {
try { return bash(`test -f "${p}" && echo "yes"`).includes('yes') } catch { return false }
}
阶段 1:需求理解与策略选择
目标:解析需求,评估不确定性,选择分解策略。
// 1. 解析需求
// - 提取核心目标(要实现什么)
// - 识别约束(技术栈、时间线、兼容性等)
// - 识别利益方(用户、管理员、开发者等)
// - 识别关键词以确定领域
// 2. 评估不确定性级别
const uncertaintyFactors = {
scope_clarity: '低|中|高',
technical_risk: '低|中|高',
dependency_unknown: '低|中|高',
domain_familiarity: '低|中|高',
requirement_stability: '低|中|高'
}
// 高不确定性(>=3 高) → 渐进式
// 低不确定性(>=3 低) → 直接式
// 其他 → 询问用户偏好
// 3. 策略选择
let selectedMode
if (requestedMode !== 'auto') {
selectedMode = requestedMode
} else if (AUTO_YES) {
selectedMode = recommendedMode // 使用默认值
} else {
const strategyAnswer = ASK_USER([
{
id: "strategy", type: "select",
prompt: `分解策略选择:
不确定性:${uncertaintyLevel}
推荐:${recommendedMode}
选择:`,
options: [
{ label: recommendedMode === 'progressive' ? "渐进式(推荐)" : "渐进式",
description: "分层 MVP→迭代,先验证核心" },
{ label: recommendedMode === 'direct' ? "直接式(推荐)" : "直接式",
description: "拓扑排序任务序列" }
]
}
]) // 阻塞(等待用户响应)
selectedMode = strategyAnswer.strategy.toLowerCase().includes('progressive') ? 'progressive' : 'direct'
}
// 4. 生成 strategy-assessment.json
const strategyAssessment = {
session_id: sessionId,
requirement: requirement,
timestamp: getUtc8ISOString(),
uncertainty_factors: uncertaintyFactors,
uncertainty_level: uncertaintyLevel,
recommended_mode: recommendedMode,
selected_mode: selectedMode,
goal: extractedGoal,
constraints: extractedConstraints,
stakeholders: extractedStakeholders,
domain_keywords: extractedKeywords
}
Write(`${sessionFolder}/strategy-assessment.json`, JSON.stringify(strategyAssessment, null, 2))
// 5. 初始化 roadmap.md 骨架
const roadmapMdSkeleton = `# 需求路线图
**会话**:${sessionId}
**需求**:${requirement}
**策略**:${selectedMode}
**状态**:规划中
**创建时间**:${getUtc8ISOString()}
## 策略评估
- 不确定性级别:${uncertaintyLevel}
- 分解模式:${selectedMode}
## 路线图
> 阶段 3 分解后填充
## 收敛标准详情
> 阶段 3 分解后填充
## 风险项
> 阶段 3 分解后填充
## 下一步
> 阶段 4 验证后填充
`
Write(`${sessionFolder}/roadmap.md`, roadmapMdSkeleton)
成功标准:
- 需求目标、约束、利益方已识别
- 不确定性级别已评估
- 策略已选择(渐进式或直接式)
- strategy-assessment.json 已生成
- roadmap.md 骨架已初始化
阶段 2:上下文收集(可选,子代理)
目标:如果存在代码库,收集相关上下文以增强分解质量。
// 1. 检测代码库
const hasCodebase = bash(`
test -f package.json && echo "nodejs" ||
test -f go.mod && echo "golang" ||
test -f Cargo.toml && echo "rust" ||
test -f pyproject.toml && echo "python" ||
test -f pom.xml && echo "java" ||
test -d src && echo "generic" ||
echo "none"
`).trim()
// 2. 代码库探索(仅当 hasCodebase !== 'none')
let exploreAgent = null
if (hasCodebase !== 'none') {
try {
exploreAgent = spawn_agent({
message: `
## 任务分配
### 强制第一步(代理执行)
1. **读取角色定义**:~/.codex/agents/cli-explore-agent.md(必须先读)
2. 读取:${projectRoot}/.workflow/project-tech.json(如果存在)
3. 读取:${projectRoot}/.workflow/project-guidelines.json(如果存在)
---
## 任务目标
探索代码库以获取需求分解上下文。
## 探索上下文
需求:${requirement}
策略:${selectedMode}
项目类型:${hasCodebase}
会话:${sessionFolder}
## 强制第一步
1. 运行:ccw tool exec get_modules_by_depth '{}'
2. 基于需求关键词执行相关搜索
## 探索重点
- 识别与需求相关的模块/组件
- 找到应遵循的现有模式
- 定位新功能的集成点
- 评估当前架构约束
## 输出
将发现写入:${sessionFolder}/exploration-codebase.json
模式:{
project_type: "${hasCodebase}",
relevant_modules: [{name, path, relevance}],
existing_patterns: [{pattern, files, description}],
integration_points: [{location, description, risk}],
architecture_constraints: [string],
tech_stack: {languages, frameworks, tools},
_metadata: {timestamp, exploration_scope}
}
`
})
// 等待并处理超时
let result = wait({ ids: [exploreAgent], timeout_ms: 600000 })
if (result.timed_out) {
send_input({ id: exploreAgent, message: '立即完成并写入 exploration-codebase.json。' })
result = wait({ ids: [exploreAgent], timeout_ms: 300000 })
if (result.timed_out) throw new Error('代理超时')
}
} finally {
if (exploreAgent) close_agent({ id: exploreAgent })
}
}
// 无代码库 → 跳过,直接进入阶段 3
阶段 3:分解与问题创建(内联代理)
目标:执行需求分解,创建问题,生成 execution-plan.json + issues.jsonl + roadmap.md。
关键:创建问题后,必须执行 分解质量检查(步骤 3.4),使用 CLI 分析,然后才能进入阶段 4。
准备上下文
const strategy = JSON.parse(Read(`${sessionFolder}/strategy-assessment.json`))
let explorationContext = null
if (fileExists(`${sessionFolder}/exploration-codebase.json`)) {
explorationContext = JSON.parse(Read(`${sessionFolder}/exploration-codebase.json`))
}
内部记录模式(CLI 解析)
这些模式内部用于解析 CLI 分解输出。在步骤 3.3 中转换为问题。
渐进式模式 - 层记录:
{
id: "L{n}", // L0, L1, L2, L3
name: string, // 层名称:MVP / 可用 / 完善 / 优化
goal: string, // 层目标(一句话)
scope: [string], // 包含的功能
excludes: [string], // 明确排除的功能
convergence: {
criteria: [string], // 可测试条件
verification: string, // 如何验证
definition_of_done: string // 业务语言完成定义
},
risks: [{description, probability, impact, mitigation}],
effort: "small" | "medium" | "large",
depends_on: ["L{n}"]
}
直接式模式 - 任务记录:
{
id: "T{n}", // T1, T2, T3, ...
title: string,
type: "infrastructure" | "feature" | "enhancement" | "testing",
scope: string,
inputs: [string],
outputs: [string],
convergence: { criteria, verification, definition_of_done },
depends_on: ["T{n}"],
parallel_group: number // 相同组 = 可并行化
}
收敛质量要求
| 字段 | 要求 | 坏示例 | 好示例 |
|---|---|---|---|
criteria[] |
可测试 | "系统工作正常" |
"API 返回 200 且响应体包含 user_id 字段" |
verification |
可执行 | "检查一下" |
"jest --testPathPattern=auth && curl -s localhost:3000/health" |
definition_of_done |
业务语言 | "代码通过编译" |
"新用户可完成注册→登录→执行核心操作的完整流程" |
步骤 3.1:CLI 辅助分解
渐进式模式 CLI 模板
ccw cli -p "
目的:将需求分解为渐进式层(MVP→迭代),带收敛标准
成功:2-4 个自包含层,每层有可测试收敛,无范围重叠
需求:
${requirement}
策略上下文:
- 不确定性:${strategy.uncertainty_level}
- 目标:${strategy.goal}
- 约束:${strategy.constraints.join(', ')}
- 利益方:${strategy.stakeholders.join(', ')}
${explorationContext ? `代码库上下文:
- 相关模块:${explorationContext.relevant_modules.map(m => m.name).join(', ')}
- 现有模式:${explorationContext.existing_patterns.map(p => p.pattern).join(', ')}
- 架构约束:${explorationContext.architecture_constraints.join(', ')}
- 技术栈:${JSON.stringify(explorationContext.tech_stack)}` : '无代码库(纯需求分解)'}
任务:
• 定义 2-4 个从 MVP 到完整实现的渐进式层
• L0 (MVP):最小可行闭环 - 核心路径端到端工作
• L1 (可用):关键用户路径,基本错误处理
• L2 (完整):边界情况、性能、安全强化
• L3 (优化):高级功能、可观测性、运营支持
• 每层:明确范围(包含)和排除(不包含)
• 每层:收敛带可测试标准、可执行验证、业务语言 DoD
• 每层风险项
模式:analysis
上下文:@**/*
预期:
每层输出:
## L{n}: {名称}
**目标**:{一句话}
**范围**:{逗号分隔功能}
**排除**:{逗号分隔排除功能}
**收敛**:
- 标准:{可测试条件列表}
- 验证:{可执行命令或步骤}
- 完成定义:{业务语言句子}
**风险项**:{列表}
**工作量**:{small|medium|large}
**依赖**:{层 ID 或无}
约束:
- 每个功能仅属于一层(无重叠)
- 标准必须可测试(可编写断言)
- 验证必须可执行(命令或明确步骤)
- 完成定义必须非技术利益方可理解
- L0 必须是完整闭环(端到端路径工作)
" --tool gemini --mode analysis
直接式模式 CLI 模板
ccw cli -p "
目的:将需求分解为拓扑排序任务序列,带收敛标准
成功:自包含任务,清晰输入/输出,可测试收敛,正确依赖顺序
需求:
${requirement}
策略上下文:
- 目标:${strategy.goal}
- 约束:${strategy.constraints.join(', ')}
${explorationContext ? `代码库上下文:
- 相关模块:${explorationContext.relevant_modules.map(m => m.name).join(', ')}
- 现有模式:${explorationContext.existing_patterns.map(p => p.pattern).join(', ')}
- 技术栈:${JSON.stringify(explorationContext.tech_stack)}` : '无代码库(纯需求分解)'}
任务:
• 分解为垂直切片,边界清晰
• 每任务:类型(基础设施|功能|增强|测试)
• 每任务:明确输入(需要什么)和输出(产生什么)
• 每任务:收敛带可测试标准、可执行验证、业务语言 DoD
• 拓扑排序:尊重依赖顺序
• 分配 parallel_group 数字(相同组 = 可并行运行)
模式:analysis
上下文:@**/*
预期:
每任务输出:
## T{n}: {标题}
**类型**:{infrastructure|feature|enhancement|testing}
**范围**:{描述}
**输入**:{逗号分隔文件/模块或 'none'}
**输出**:{逗号分隔文件/模块}
**收敛**:
- 标准:{可测试条件列表}
- 验证:{可执行命令或步骤}
- 完成定义:{业务语言句子}
**依赖**:{任务 ID 或无}
**并行组**:{数字}
约束:
- 输入必须来自前置任务输出或现有资源
- 无循环依赖
- 标准必须可测试
- 验证必须可执行
- 相同 parallel_group 的任务必须真正独立
" --tool gemini --mode analysis
CLI 备用链
// 备用链:Gemini → Qwen → 手动分解
try {
cliOutput = executeCLI('gemini', prompt)
} catch (error) {
try {
cliOutput = executeCLI('qwen', prompt)
} catch {
// 手动备用(见备用分解)
records = selectedMode === 'progressive'
? manualProgressiveDecomposition(requirement, explorationContext)
: manualDirectDecomposition(requirement, explorationContext)
}
}
CLI 输出解析
// 解析渐进式层
function parseProgressiveLayers(cliOutput) {
const layers = []
const layerBlocks = cliOutput.split(/## L(\d+):/).slice(1)
for (let i = 0; i < layerBlocks.length; i += 2) {
const layerId = `L${layerBlocks[i].trim()}`
const text = layerBlocks[i + 1]
const nameMatch = /^(.+?)(?=
)/.exec(text)
const goalMatch = /\*\*Goal\*\*:\s*(.+?)(?=
)/.exec(text)
const scopeMatch = /\*\*Scope\*\*:\s*(.+?)(?=
)/.exec(text)
const excludesMatch = /\*\*Excludes\*\*:\s*(.+?)(?=
)/.exec(text)
const effortMatch = /\*\*Effort\*\*:\s*(.+?)(?=
)/.exec(text)
const dependsMatch = /\*\*Depends On\*\*:\s*(.+?)(?=
|$)/.exec(text)
const riskMatch = /\*\*Risk Items\*\*:
((?:- .+?
)*)/.exec(text)
const convergence = parseConvergence(text)
layers.push({
id: layerId,
name: nameMatch?.[1].trim() || `层 ${layerId}`,
goal: goalMatch?.[1].trim() || "",
scope: scopeMatch?.[1].split(/[,,]/).map(s => s.trim()).filter(Boolean) || [],
excludes: excludesMatch?.[1].split(/[,,]/).map(s => s.trim()).filter(Boolean) || [],
convergence,
risks: riskMatch
? riskMatch[1].split('
').map(s => s.replace(/^- /, '').trim()).filter(Boolean)
.map(desc => ({description: desc, probability: "中", impact: "中", mitigation: "N/A"}))
: [],
effort: normalizeEffort(effortMatch?.[1].trim()),
depends_on: parseDependsOn(dependsMatch?.[1], 'L')
})
}
return layers
}
// 解析直接式任务
function parseDirectTasks(cliOutput) {
const tasks = []
const taskBlocks = cliOutput.split(/## T(\d+):/).slice(1)
for (let i = 0; i < taskBlocks.length; i += 2) {
const taskId = `T${taskBlocks[i].trim()}`
const text = taskBlocks[i + 1]
const titleMatch = /^(.+?)(?=
)/.exec(text)
const typeMatch = /\*\*Type\*\*:\s*(.+?)(?=
)/.exec(text)
const scopeMatch = /\*\*Scope\*\*:\s*(.+?)(?=
)/.exec(text)
const inputsMatch = /\*\*Inputs\*\*:\s*(.+?)(?=
)/.exec(text)
const outputsMatch = /\*\*Outputs\*\*:\s*(.+?)(?=
)/.exec(text)
const dependsMatch = /\*\*Depends On\*\*:\s*(.+?)(?=
|$)/.exec(text)
const groupMatch = /\*\*Parallel Group\*\*:\s*(\d+)/.exec(text)
const convergence = parseConvergence(text)
tasks.push({
id: taskId,
title: titleMatch?.[1].trim() || `任务 ${taskId}`,
type: normalizeType(typeMatch?.[1].trim()),
scope: scopeMatch?.[1].trim() || "",
inputs: parseList(inputsMatch?.[1]),
outputs: parseList(outputsMatch?.[1]),
convergence,
depends_on: parseDependsOn(dependsMatch?.[1], 'T'),
parallel_group: parseInt(groupMatch?.[1]) || 1
})
}
return tasks
}
// 解析收敛部分
function parseConvergence(text) {
const criteriaMatch = /- Criteria:\s*((?:.+
?)+?)(?=- Verification:)/.exec(text)
const verificationMatch = /- Verification:\s*(.+?)(?=
- Definition)/.exec(text)
const dodMatch = /- Definition of Done:\s*(.+?)(?=
\*\*|$)/.exec(text)
const criteria = criteriaMatch
? criteriaMatch[1].split('
')
.map(s => s.replace(/^\s*[-•]\s*/, '').trim())
.filter(s => s && !s.startsWith('Verification') && !s.startsWith('Definition'))
: []
return {
criteria: criteria.length > 0 ? criteria : ["任务成功完成"],
verification: verificationMatch?.[1].trim() || "手动验证",
definition_of_done: dodMatch?.[1].trim() || "功能按预期工作"
}
}
// 辅助函数
function normalizeEffort(effort) {
if (!effort) return "中"
const lower = effort.toLowerCase()
if (lower.includes('small') || lower.includes('low')) return "小"
if (lower.includes('large') || lower.includes('high')) return "大"
return "中"
}
function normalizeType(type) {
if (!type) return "功能"
const lower = type.toLowerCase()
if (lower.includes('infra')) return "基础设施"
if (lower.includes('enhance')) return "增强"
if (lower.includes('test')) return "测试"
return "功能"
}
function parseList(text) {
if (!text || text.toLowerCase() === 'none') return []
return text.split(/[,,]/).map(s => s.trim()).filter(Boolean)
}
function parseDependsOn(text, prefix) {
if (!text || text.toLowerCase() === 'none' || text === '[]') return []
const pattern = new RegExp(`${prefix}\\d+`, 'g')
return (text.match(pattern) || [])
}
备用分解
// CLI 失败时手动分解
function manualProgressiveDecomposition(requirement, context) {
return [
{
id: "L0", name: "MVP", goal: "最小可用闭环",
scope: ["核心功能"], excludes: ["高级功能", "优化"],
convergence: {
criteria: ["核心路径端到端可跑通"],
verification: "手动测试核心流程",
definition_of_done: "用户可完成一次核心操作的完整流程"
},
risks: [{description: "技术选型待验证", probability: "中", impact: "中", mitigation: "待评估"}],
effort: "中", depends_on: []
},
{
id: "L1", name: "可用", goal: "关键用户路径完善",
scope: ["错误处理", "输入校验"], excludes: ["性能优化", "监控"],
convergence: {
criteria: ["所有用户输入有校验", "错误场景有提示"],
verification: "单元测试 + 手动测试错误场景",
definition_of_done: "用户遇到问题时有清晰的引导和恢复路径"
},
risks: [], effort: "中", depends_on: ["L0"]
}
]
}
function manualDirectDecomposition(requirement, context) {
return [
{
id: "T1", title: "基础设施搭建", type: "基础设施",
scope: "项目骨架和基础配置",
inputs: [], outputs: ["project-structure"],
convergence: {
criteria: ["项目可构建无报错", "基础配置完成"],
verification: "npm run build(或对应构建命令)",
definition_of_done: "项目基础框架就绪,可开始功能开发"
},
depends_on: [], parallel_group: 1
},
{
id: "T2", title: "核心功能实现", type: "功能",
scope: "核心业务逻辑",
inputs: ["project-structure"], outputs: ["core-module"],
convergence: {
criteria: ["核心 API/功能可调用", "返回预期结果"],
verification: "运行核心功能测试",
definition_of_done: "核心业务功能可正常使用"
},
depends_on: ["T1"], parallel_group: 2
}
]
}
步骤 3.2:记录增强与验证
// 验证渐进式层
function validateProgressiveLayers(layers) {
const errors = []
// 检查范围重叠
const allScopes = new Map()
layers.forEach(layer => {
layer.scope.forEach(feature => {
if (allScopes.has(feature)) {
errors.push(`范围重叠:"${feature}" 同时存在于 ${allScopes.get(feature)} 和 ${layer.id}`)
}
allScopes.set(feature, layer.id)
})
})
// 检查循环依赖
const cycleErrors = detectCycles(layers, 'L')
errors.push(...cycleErrors)
// 检查收敛质量
layers.forEach(layer => {
errors.push(...validateConvergence(layer.id, layer.convergence))
})
// 检查 L0 自包含(无依赖)
const l0 = layers.find(l => l.id === 'L0')
if (l0 && l0.depends_on.length > 0) {
errors.push("L0 (MVP) 不应有依赖")
}
return errors
}
// 验证直接式任务
function validateDirectTasks(tasks) {
const errors = []
// 检查输入/输出链
const availableOutputs = new Set()
const sortedTasks = topologicalSort(tasks)
sortedTasks.forEach(task => {
task.inputs.forEach(input => {
if (!availableOutputs.has(input)) {
// 现有文件是有效输入 - 仅警告
}
})
task.outputs.forEach(output => availableOutputs.add(output))
})
// 检查循环依赖
errors.push(...detectCycles(tasks, 'T'))
// 检查收敛质量
tasks.forEach(task => {
errors.push(...validateConvergence(task.id, task.convergence))
})
// 检查并行组一致性
const groups = new Map()
tasks.forEach(task => {
if (!groups.has(task.parallel_group)) groups.set(task.parallel_group, [])
groups.get(task.parallel_group).push(task)
})
groups.forEach((groupTasks, groupId) => {
if (groupTasks.length > 1) {
const ids = new Set(groupTasks.map(t => t.id))
groupTasks.forEach(task => {
task.depends_on.forEach(dep => {
if (ids.has(dep)) {
errors.push(`并行组 ${groupId}:${task.id} 依赖 ${dep},但两者在同一组`)
}
})
})
}
})
return errors
}
// 验证收敛质量
function validateConvergence(recordId, convergence) {
const errors = []
const vaguePatterns = /正常|正确|好|可以|没问题|works|fine|good|correct/i
convergence.criteria.forEach((criterion, i) => {
if (vaguePatterns.test(criterion) && criterion.length < 15) {
errors.push(`${recordId} criteria[${i}]:太模糊 - "${criterion}"`)
}
})
if (convergence.verification.length < 10) {
errors.push(`${recordId} verification:太短,需要可执行步骤`)
}
const technicalPatterns = /compile|build|lint|npm|npx|jest|tsc|eslint/i
if (technicalPatterns.test(convergence.definition_of_done)) {
errors.push(`${recordId} definition_of_done:应为业务语言,非技术命令`)
}
return errors
}
// 检测循环依赖
function detectCycles(records, prefix) {
const errors = []
const graph = new Map(records.map(r => [r.id, r.depends_on]))
const visited = new Set()
const inStack = new Set()
function dfs(node, path) {
if (inStack.has(node)) {
errors.push(`检测到循环依赖:${[...path, node].join(' → ')}`)
return
}
if (visited.has(node)) return
visited.add(node)
inStack.add(node)
;(graph.get(node) || []).forEach(dep => dfs(dep, [...path, node]))
inStack.delete(node)
}
records.forEach(r => {
if (!visited.has(r.id)) dfs(r.id, [])
})
return errors
}
// 拓扑排序
function topologicalSort(tasks) {
const result = []
const visited = new Set()
const taskMap = new Map(tasks.map(t => [t.id, t]))
function visit(taskId) {
if (visited.has(taskId)) return
visited.add(taskId)
const task = taskMap.get(taskId)
if (task) {
task.depends_on.forEach(dep => visit(dep))
result.push(task)
}
}
tasks.forEach(t => visit(t.id))
return result
}
步骤 3.3:问题创建与输出生成
3.3a:内部记录 → 问题数据映射
// 渐进式模式:层 → 问题数据(issues-jsonl-schema)
function layerToIssue(layer, sessionId, timestamp) {
const context = `## 目标
${layer.goal}
` +
`## 范围
${layer.scope.map(s => `- ${s}`).join('
')}
` +
`## 排除
${layer.excludes.map(s => `- ${s}`).join('
') || '无'}
` +
`## 收敛标准
${layer.convergence.criteria.map(c => `- ${c}`).join('
')}
` +
`## 验证
${layer.convergence.verification}
` +
`## 完成定义
${layer.convergence.definition_of_done}
` +
(layer.risks.length ? `## 风险
${layer.risks.map(r => `- ${r.description} (概率:${r.probability} 影响:${r.impact})`).join('
')}` : '')
const effortToPriority = { small: 4, medium: 3, large: 2 }
return {
title: `[${layer.name}] ${layer.goal}`,
context: context,
priority: effortToPriority[layer.effort] || 3,
source: "text",
tags: ["req-plan", "progressive", layer.name.toLowerCase(), `wave-${getWaveNum(layer)}`],
affected_components: [],
extended_context: {
notes: JSON.stringify({
session: sessionId,
strategy: "progressive",
layer: layer.id,
wave: getWaveNum(layer),
effort: layer.effort,
depends_on_issues: [], // 所有问题创建后回填
original_id: layer.id
})
},
lifecycle_requirements: {
test_strategy: "integration",
regression_scope: "affected",
acceptance_type: "automated",
commit_strategy: "per-task"
}
}
}
function getWaveNum(layer) {
const match = layer.id.match(/L(\d+)/)
return match ? parseInt(match[1]) + 1 : 1
}
// 直接式模式:任务 → 问题数据(issues-jsonl-schema)
function taskToIssue(task, sessionId, timestamp) {
const context = `## 范围
${task.scope}
` +
`## 输入
${task.inputs.length ? task.inputs.map(i => `- ${i}`).join('
') : '无(起始任务)'}
` +
`## 输出
${task.outputs.map(o => `- ${o}`).join('
')}
` +
`## 收敛标准
${task.convergence.criteria.map(c => `- ${c}`).join('
')}
` +
`## 验证
${task.convergence.verification}
` +
`## 完成定义
${task.convergence.definition_of_done}`
return {
title: `[${task.type}] ${task.title}`,
context: context,
priority: 3,
source: "text",
tags: ["req-plan", "direct", task.type, `wave-${task.parallel_group}`],
affected_components: task.outputs,
extended_context: {
notes: JSON.stringify({
session: sessionId,
strategy: "direct",
task_id: task.id,
wave: task.parallel_group,
parallel_group: task.parallel_group,
depends_on_issues: [], // 所有问题创建后回填
original_id: task.id
})
},
lifecycle_requirements: {
test_strategy: task.type === 'testing' ? 'unit' : 'integration',
regression_scope: "affected",
acceptance_type: "automated",
commit_strategy: "per-task"
}
}
}
3.3b:通过 ccw issue create 创建问题
// 顺序创建问题(获取正式 ISS-xxx ID)
const issueIdMap = {} // originalId → ISS-xxx
for (const record of records) {
const issueData = selectedMode === 'progressive'
? layerToIssue(record, sessionId, getUtc8ISOString())
: taskToIssue(record, sessionId, getUtc8ISOString())
// 通过 ccw issue create 创建问题
try {
const createResult = bash(`ccw issue create --data '${JSON.stringify(issueData)}' --json`)
const created = JSON.parse(createResult.trim())
issueIdMap[record.id] = created.id
} catch (error) {
// 重试一次
try {
const retryResult = bash(`ccw issue create --data '${JSON.stringify(issueData)}' --json`)
const created = JSON.parse(retryResult.trim())
issueIdMap[record.id] = created.id
} catch {
// 记录错误,跳过此记录,继续其余
console.error(`无法为 ${record.id} 创建问题`)
}
}
}
// 回填 depends_on_issues 到 extended_context.notes
for (const record of records) {
const issueId = issueIdMap[record.id]
if (!issueId) continue
const deps = record.depends_on.map(d => issueIdMap[d]).filter(Boolean)
if (deps.length > 0) {
const currentNotes = JSON.parse(issueData.extended_context.notes)
currentNotes.depends_on_issues = deps
bash(`ccw issue update ${issueId} --notes '${JSON.stringify(currentNotes)}'`)
}
}
3.3c:生成 execution-plan.json
function generateExecutionPlan(records, issueIdMap, sessionId, requirement, selectedMode) {
const issueIds = records.map(r => issueIdMap[r.id]).filter(Boolean)
let waves
if (selectedMode === 'progressive') {
waves = records.filter(r => issueIdMap[r.id]).map((r, i) => ({
wave: i + 1,
label: r.name,
issue_ids: [issueIdMap[r.id]],
depends_on_waves: r.depends_on.length > 0
? [...new Set(r.depends_on.map(d => records.findIndex(x => x.id === d) + 1))]
: []
}))
} else {
const groups = new Map()
records.filter(r => issueIdMap[r.id]).forEach(r => {
const g = r.parallel_group
if (!groups.has(g)) groups.set(g, [])
groups.get(g).push(r)
})
waves = [...groups.entries()]
.sort(([a], [b]) => a - b)
.map(([groupNum, groupRecords]) => ({
wave: groupNum,
label: `组 ${groupNum}`,
issue_ids: groupRecords.map(r => issueIdMap[r.id]),
depends_on_waves: groupNum > 1 ? [groupNum - 1] : []
}))
}
const issueDependencies = {}
records.forEach(r => {
if (!issueIdMap[r.id]) return
const deps = r.depends_on.map(d => issueIdMap[d]).filter(Boolean)
if (deps.length > 0) {
issueDependencies[issueIdMap[r.id]] = deps
}
})
return {
session_id: sessionId,
requirement: requirement,
strategy: selectedMode,
created_at: new Date().toISOString(),
issue_ids: issueIds,
waves: waves,
issue_dependencies: issueDependencies
}
}
const executionPlan = generateExecutionPlan(records, issueIdMap, sessionId, requirement, selectedMode)
Write(`${sessionFolder}/execution-plan.json`, JSON.stringify(executionPlan, null, 2))
3.3d:生成 issues.jsonl 会话副本
const sessionIssues = []
for (const originalId of Object.keys(issueIdMap)) {
const issueId = issueIdMap[originalId]
if (!issueId) continue
const issueJson = bash(`ccw issue status ${issueId} --json`).trim()
sessionIssues.push(issueJson)
}
Write(`${sessionFolder}/issues.jsonl`, sessionIssues.join('
') + '
')
3.3e:生成 roadmap.md(带问题 ID 引用)
// 渐进式模式路线图
function generateProgressiveRoadmapMd(layers, issueIdMap, input) {
return `# 需求路线图
**会话**:${input.sessionId}
**需求**:${input.requirement}
**策略**:渐进式
**不确定性**:${input.strategy.uncertainty_level}
**生成时间**:${new Date().toISOString()}
## 策略评估
- 目标:${input.strategy.goal}
- 约束:${input.strategy.constraints.join(', ') || '无'}
- 利益方:${input.strategy.stakeholders.join(', ') || '无'}
## 路线图概览
| 层级 | 名称 | 目标 | 工作量 | 依赖 | 问题 ID |
|------|------|------|--------|------|----------|
${layers.map(l => `| ${l.id} | ${l.name} | ${l.goal} | ${l.effort} | ${l.depends_on.length ? l.depends_on.join(', ') : '-'} | ${issueIdMap[l.id]} |`).join('
')}
## 问题映射
| 波次 | 问题 ID | 标题 | 优先级 |
|------|----------|-------|----------|
${layers.map(l => `| ${getWaveNum(l)} | ${issueIdMap[l.id]} | [${l.name}] ${l.goal} | ${({small: 4, medium: 3, large: 2})[l.effort] || 3} |`).join('
')}
## 各层详情
${layers.map(l => `### ${l.id}: ${l.name} (${issueIdMap[l.id]})
**目标**:${l.goal}
**范围**:${l.scope.join('、')}
**排除**:${l.excludes.join('、') || '无'}
**收敛标准**:
${l.convergence.criteria.map(c => `- ${c}`).join('
')}
- **验证方法**:${l.convergence.verification}
- **完成定义**:${l.convergence.definition_of_done}
**风险项**:${l.risks.length ? l.risks.map(r => `
- ${r.description}(概率:${r.probability},影响:${r.impact},缓解:${r.mitigation})`).join('') : '无'}
**工作量**:${l.effort}
`).join('
---
')}
## 风险汇总
${layers.flatMap(l => l.risks.map(r => `- **${l.id}**(${issueIdMap[l.id]}):${r.description}(概率:${r.probability},影响:${r.impact})`)).join('
') || '无已识别风险'}
## 下一步
### 使用 team-planex 执行全部波次
\`\`\`
$team-planex --plan ${input.sessionFolder}/execution-plan.json
\`\`\`
### 按波次逐步执行
\`\`\`
${layers.map(l => `# 波次 ${getWaveNum(l)}:${l.name}
$team-planex ${issueIdMap[l.id]}`).join('
')}
\`\`\`
路线图文件:\`${input.sessionFolder}/\`
- issues.jsonl(标准问题格式)
- execution-plan.json(波次编排)
`
}
// 直接式模式路线图
function generateDirectRoadmapMd(tasks, issueIdMap, input) {
const groups = new Map()
tasks.forEach(t => {
const g = t.parallel_group
if (!groups.has(g)) groups.set(g, [])
groups.get(g).push(t)
})
return `# 需求路线图
**会话**:${input.sessionId}
**需求**:${input.requirement}
**策略**:直接式
**生成时间**:${new Date().toISOString()}
## 策略评估
- 目标:${input.strategy.goal}
- 约束:${input.strategy.constraints.join(', ') || '无'}
## 任务序列
| 组 | ID | 标题 | 类型 | 依赖 | 问题 ID |
|----|-----|------|------|------|----------|
${tasks.map(t => `| ${t.parallel_group} | ${t.id} | ${t.title} | ${t.type} | ${t.depends_on.length ? t.depends_on.join(', ') : '-'} | ${issueIdMap[t.id]} |`).join('
')}
## 问题映射
| 波次 | 问题 ID | 标题 | 优先级 |
|------|----------|-------|----------|
${tasks.map(t => `| ${t.parallel_group} | ${issueIdMap[t.id]} | [${t.type}] ${t.title} | 3 |`).join('
')}
## 各任务详情
${tasks.map(t => `### ${t.id}: ${t.title} (${issueIdMap[t.id]})
**类型**:${t.type} | **并行组**:${t.parallel_group}
**范围**:${t.scope}
**输入**:${t.inputs.length ? t.inputs.join(', ') : '无(起始任务)'}
**输出**:${t.outputs.join(', ')}
**收敛标准**:
${t.convergence.criteria.map(c => `- ${c}`).join('
')}
- **验证方法**:${t.convergence.verification}
- **完成定义**:${t.convergence.definition_of_done}
`).join('
---
')}
## 下一步
### 使用 team-planex 执行全部波次
\`\`\`
$team-planex --plan ${input.sessionFolder}/execution-plan.json
\`\`\`
### 按波次逐步执行
\`\`\`
${[...groups.entries()].sort(([a], [b]) => a - b).map(([g, ts]) =>
`# 波次 ${g}:组 ${g}
$team-planex ${ts.map(t => issueIdMap[t.id]).join(' ')}`
).join('
')}
\`\`\`
路线图文件:\`${input.sessionFolder}/\`
- issues.jsonl(标准问题格式)
- execution-plan.json(波次编排)
`
}
// 写入 roadmap.md
const roadmapInput = {
sessionId, requirement, sessionFolder,
strategy: { ...strategy }
}
const roadmapMd = selectedMode === 'progressive'
? generateProgressiveRoadmapMd(records, issueIdMap, roadmapInput)
: generateDirectRoadmapMd(records, issueIdMap, roadmapInput)
Write(`${sessionFolder}/roadmap.md`, roadmapMd)
步骤 3.4:分解质量检查(强制)
创建问题并生成输出文件后,必须在继续之前执行 CLI 质量检查。
质量维度
| 维度 | 检查标准 | 关键? |
|---|---|---|
| 需求覆盖率 | 所有原始需求方面都在问题中处理 | 是 |
| 收敛质量 | 标准可测试、验证可执行、DoD 业务可读 | 是 |
| 范围完整性 | 渐进式:无重叠/间隙;直接式:输入/输出链有效 | 是 |
| 依赖正确性 | 无循环依赖、顺序正确、问题依赖匹配 | 是 |
| 工作量平衡 | 无单个问题过大 | 否 |
CLI 质量检查
ccw cli -p "
目的:验证路线图分解质量
成功:所有质量维度通过
原始需求:
${requirement}
已创建问题(${selectedMode} 模式):
${issuesJsonlContent}
执行计划:
${JSON.stringify(executionPlan, null, 2)}
任务:
• 需求覆盖率:分解是否处理需求的所有方面?
• 收敛质量:标准可测试吗?验证可执行吗?DoD 业务可读吗?
• 范围完整性:${selectedMode === 'progressive' ? '层间无范围重叠,无功能间隙' : '输入/输出链有效,并行组正确'}
• 依赖正确性:无循环依赖,波次顺序正确
• 工作量平衡:无过大项
模式:analysis
预期:
## 质量检查结果
### 需求覆盖率:通过|失败
[详情]
### 收敛质量:通过|失败
[详情及每记录具体问题]
### 范围完整性:通过|失败
[详情]
### 依赖正确性:通过|失败
[详情]
### 工作量平衡:通过|失败
[详情]
## 推荐:通过|自动修复|需要审查
## 修复(如果自动修复):
[具体修复作为 JSON 补丁]
约束:只读验证,不修改文件
" --tool gemini --mode analysis
自动修复策略
| 问题类型 | 自动修复操作 |
|---|---|
| 模糊标准 | 替换为具体、可测试条件 |
| 技术 DoD | 重写为业务语言 |
| 缺失范围项 | 添加到适当问题上下文 |
| 工作量不平衡 | 建议拆分(报告给用户) |
修复后,通过 ccw issue update 更新问题并重新生成 issues.jsonl + roadmap.md。
阶段 4:验证与 team-planex 交接
目标:显示分解结果,收集用户反馈,提供 team-planex 执行选项。
// 1. 显示分解结果
const executionPlan = JSON.parse(Read(`${sessionFolder}/execution-plan.json`))
const issueIds = executionPlan.issue_ids
const waves = executionPlan.waves
渐进式模式显示:
## 路线图概览
| 波次 | 问题 ID | 名称 | 目标 | 优先级 |
|------|----------|------|------|----------|
| 1 | ISS-xxx | MVP | ... | 2 |
| 2 | ISS-yyy | 可用 | ... | 3 |
### 收敛标准
**波次 1 - MVP (ISS-xxx)**:
- 标准:[标准列表]
- 验证:[验证]
- 完成定义:[完成定义]
直接式模式显示:
## 任务序列
| 波次 | 问题 ID | 标题 | 类型 | 依赖 |
|------|----------|-------|------|--------------|
| 1 | ISS-xxx | ... | 基础设施 | - |
| 2 | ISS-yyy | ... | 功能 | ISS-xxx |
用户反馈循环(最多 5 轮,AUTO_YES 时跳过)
if (!AUTO_YES) {
let round = 0
let continueLoop = true
while (continueLoop && round < 5) {
round++
const feedback = ASK_USER([
{
id: "feedback", type: "select",
prompt: `路线图验证(第 ${round} 轮):
对当前分解有任何反馈吗?`,
options: [
{ label: "批准", description: "分解合理,进入下一步" },
{ label: "调整范围", description: "某些问题范围需要调整" },
{ label: "修改收敛", description: "收敛标准不够具体或可测试" },
{ label: "重新分解", description: "整体策略或分层方法需要更改" }
]
}
]) // 阻塞(等待用户响应)
if (feedback.feedback === '批准') {
continueLoop = false
} else {
// 基于反馈类型处理调整
// 调整后,重新显示并返回循环顶部
}
}
}
完成选项
if (AUTO_YES) {
// 自动模式:显示摘要并结束
console.log(`路线图已生成,${issueIds.length} 个问题已创建。`)
console.log(`会话:${sessionFolder}`)
} else {
const nextStep = ASK_USER([
{
id: "next", type: "select",
prompt: `路线图已生成,${issueIds.length} 个问题已创建。下一步:`,
options: [
{ label: "使用 team-planex 执行",
description: `启动 team-planex 执行全部 ${issueIds.length} 个问题(${waves.length} 个波次)` },
{ label: "执行第一波",
description: `仅执行波次 1:${waves[0].label}` },
{ label: "查看问题",
description: "查看已创建的问题详情" },
{ label: "完成",
description: "保存路线图,稍后执行" }
]
}
]) // 阻塞(等待用户响应)
}
| 选择 | 操作 |
|---|---|
| 使用 team-planex 执行 | $team-planex --plan ${sessionFolder}/execution-plan.json |
| 执行第一波 | $team-planex ${waves[0].issue_ids.join(' ')} |
| 查看问题 | 从 issues.jsonl 显示问题摘要表 |
| 完成 | 显示文件路径,结束 |
实现草图:编排器内部使用
Skill(skill="team-planex", args="--plan ...")接口调用, 此为伪代码示意,非命令行语法。
JSONL 模式设计
问题格式(issues.jsonl)
每行遵循标准 issues-jsonl-schema.json(见 .ccw/workflows/cli-templates/schemas/issues-jsonl-schema.json)。
| 字段 | 来源 | 描述 |
|---|---|---|
id |
ccw issue create |
正式 ISS-YYYYMMDD-NNN ID |
title |
层/任务映射 | [层名称] 目标 或 [任务类型] 标题 |
context |
收敛字段 | Markdown 带目标、范围、收敛标准、验证、DoD |
priority |
工作量映射 | 小→4,中→3,大→2 |
source |
固定 | "text" |
tags |
自动生成 | ["req-plan", 模式, 名称/类型, "wave-N"] |
extended_context.notes |
元数据 JSON | 会话、策略、original_id、波次、depends_on_issues |
lifecycle_requirements |
固定 | test_strategy、regression_scope、acceptance_type、commit_strategy |
执行计划格式(execution-plan.json)
{
"session_id": "RPLAN-{slug}-{date}",
"requirement": "原始需求描述",
"strategy": "progressive|direct",
"created_at": "ISO 8601",
"issue_ids": ["ISS-xxx", "ISS-yyy"],
"waves": [
{
"wave": 1,
"label": "MVP",
"issue_ids": ["ISS-xxx"],
"depends_on_waves": []
},
{
"wave": 2,
"label": "Usable",
"issue_ids": ["ISS-yyy"],
"depends_on_waves": [1]
}
],
"issue_dependencies": {
"ISS-yyy": ["ISS-xxx"]
}
}
波次映射:
- 渐进式模式:每层 → 一波(L0→波次 1,L1→波次 2,…)
- 直接式模式:每并行组 → 一波(组 1→波次 1,组 2→波次 2,…)
会话配置
| 标志 | 默认 | 描述 |
|---|---|---|
-y, --yes |
false | 自动确认所有决策 |
-c, --continue |
false | 继续现有会话 |
-m, --mode |
auto | 分解策略:渐进式 / 直接式 / 自动式 |
会话 ID 格式:RPLAN-{slug}-{YYYY-MM-DD}
- slug:小写,字母数字 + CJK 字符,最多 40 字符
- 日期:YYYY-MM-DD (UTC+8)
错误处理
| 错误 | 解决 |
|---|---|
| cli-explore-agent 超时 | 重试一次,发送输入提示,然后跳过探索 |
| cli-explore-agent 失败 | 跳过代码探索,继续纯需求分解 |
| 无代码库 | 正常流,跳过阶段 2 |
| CLI 分解失败(Gemini) | 备用到 Qwen,然后手动分解 |
| 问题创建失败 | 重试一次,然后跳过并继续其余 |
| 检测到循环依赖 | 提示用户调整依赖,重新分解 |
| 用户反馈超时 | 保存当前状态,显示 --continue 恢复命令 |
| 最大反馈轮数达到 | 使用当前版本生成最终工件 |
| 会话文件夹冲突 | 追加时间戳后缀 |
| 质量检查 NEEDS_REVIEW | 报告关键问题给用户手动解决 |
核心规则
- 显式生命周期:wait 完成后始终 close_agent 释放资源
- 不要停止:连续多阶段工作流。完成每阶段后,立即进入下一阶段
- 从不输出模糊收敛:标准必须可测试,验证可执行,DoD 用业务语言
- 从不跳过质量检查:步骤 3.4 强制,然后才能进入阶段 4
- 始终写入所有三个输出文件:issues.jsonl、execution-plan.json、roadmap.md
最佳实践
- 清晰需求描述:详细描述 → 更准确的不确定性评估和分解
- 先验证 MVP:渐进式模式中,L0 应是最小可验证闭环
- 可测试收敛:标准必须可编写断言或手动步骤;definition_of_done 应非技术利益方可判断
- 增量验证:使用
--continue迭代现有路线图 - team-planex 集成:创建的问题遵循标准 issues-jsonl-schema,可直接通过 execution-plan.json 由
$team-planex消费
使用建议
使用 $workflow-req-plan 时:
- 需要将大型需求分解为可渐进执行的路线图
- 不确定从何开始,需要 MVP 策略
- 需要生成可跟踪任务序列
- 需求涉及多个阶段或迭代
- 希望自动问题创建 + team-planex 执行管道
使用 $workflow-lite-plan 时:
- 有明确的单个任务要执行
- 需求已经是路线图中的层/任务
- 不需要分层规划
直接使用 $team-planex 时:
- 问题已存在(手动或其他工作流创建)
- 有来自先前 req-plan 会话的 execution-plan.json
现在为执行 req-plan 工作流: $ARGUMENTS