start-workflow
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesestart-workflow
start-workflow
IRON LAW: Run all phases without stopping. Never ask for confirmation between phases. Only pause at the security gate (TG /approve) if the feature is flagged as security-sensitive.
铁律:全程无中断运行所有阶段。阶段之间绝不请求确认。仅当功能被标记为安全敏感时,在安全门禁环节暂停(需Telegram发送 /approve 审批)。
Invocation
调用方式
/start-workflow
/start-workflow {url | text description}
/start-workflow --resume
/start-workflow --resume <run_id>/start-workflow
/start-workflow {url | text description}
/start-workflow --resume
/start-workflow --resume <run_id>Parameters
参数
| Param | Description |
|---|---|
| (none) | Prompt the user to enter their requirement |
| Feature requirement — URL to a spec/issue, or plain text description |
| Auto-find recent runs and let user pick one to resume |
| Resume a specific previous run from its last completed phase |
| 参数 | 描述 |
|---|---|
| (无) | 提示用户输入需求 |
| 功能需求 —— 指向规范/issue的URL,或纯文本描述 |
| 自动查找最近运行记录,让用户选择要恢复的任务 |
| 从上次完成的阶段恢复指定的历史运行任务 |
Resume Flow
恢复流程
If the user invokes (no run_id), auto-discover recent runs:
/start-workflow --resumebash
ls -dt /tmp/workflow-*/state.json 2>/dev/null | head -10For each state.json found, read and extract: , , , , .
run_idfeature_namephasestatusstarted_atPresent a numbered list to the user:
找到以下未完成的 workflow:
— health-check — 中断于 coding(2026-04-12 14:32)ab12cd34 — user-auth — 中断于 code-review(2026-04-11 09:15)ef56gh78请回复编号选择要恢复的 run,或回复 n 取消:
- If the user replies with a number, use that run's .
run_id - If the user replies "n" or any cancellation, stop.
- If no state files are found, tell the user:
没有找到可恢复的 workflow run。请直接用开始新的任务。/start-workflow {需求}
Only show runs where is not — skip completed runs.
statusDONE如果用户调用 (未指定run_id),自动发现最近的运行记录:
/start-workflow --resumebash
ls -dt /tmp/workflow-*/state.json 2>/dev/null | head -10针对每个找到的state.json,读取并提取以下字段:、、、、。
run_idfeature_namephasestatusstarted_at向用户展示编号列表:
找到以下未完成的 workflow:
— health-check — 中断于 coding(2026-04-12 14:32)ab12cd34 — user-auth — 中断于 code-review(2026-04-11 09:15)ef56gh78请回复编号选择要恢复的 run,或回复 n 取消:
- 如果用户回复数字,使用对应run的
run_id - 如果用户回复"n"或任意取消指令,终止流程
- 如果未找到状态文件,告知用户:
没有找到可恢复的 workflow run。请直接用开始新的任务。/start-workflow {需求}
仅展示不为的运行记录 —— 跳过已完成的任务。
statusDONEInput Collection
输入收集
If the user invokes with no arguments, ask:
/start-workflow请描述你想要实现的功能,或者粘贴一个需求链接(GitHub Issue、文档 URL 等):
Wait for the user's reply. Use that as .
input_rawThen automatically derive a feature name from the input:
- From URL: use the last path segment or issue title (e.g. → read title →
issues/42)user-auth-revamp - From text: extract the core noun phrase (e.g. "给项目加一个 /health 接口" → )
health-check - Format: kebab-case, 2–4 words, no spaces, lowercase, ASCII only
Show the derived name to the user:
功能名称:(如需修改请直接回复新名称,确认则回复 ok)health-check
If the user replies with a new name, use that. If they reply "ok" or any affirmation (好/确认/yes/continue/👍), proceed with the derived name.
如果用户调用时未带参数,询问:
/start-workflow请描述你想要实现的功能,或者粘贴一个需求链接(GitHub Issue、文档 URL 等):
等待用户回复,将内容作为。
input_raw随后自动从输入中生成功能名称:
- 从URL生成:取路径最后一段或issue标题(例如→ 读取标题 →
issues/42)user-auth-revamp - 从文本生成:提取核心名词短语(例如"给项目加一个 /health 接口" → )
health-check - 格式:kebab-case,2-4个单词,无空格,全小写,仅用ASCII字符
向用户展示生成的名称:
功能名称:(如需修改请直接回复新名称,确认则回复 ok)health-check
如果用户回复新名称则使用该名称,若用户回复"ok"或任意确认指令(好/确认/yes/continue/👍),则使用生成的名称继续流程。
Resolve Skill Directory (run first, every time)
解析Skill目录(每次都优先执行)
Skills can be installed globally () or per-project (). Always resolve the actual path before running any script:
~/.claude/skills/.claude/skills/bash
SKILL_DIR=$(find \
.claude/skills ~/.claude/skills \
.cursor/skills ~/.cursor/skills \
.windsurf/skills ~/.windsurf/skills \
.cline/skills ~/.cline/skills \
.agents/skills ~/.agents/skills \
-maxdepth 1 -name start-workflow -type d 2>/dev/null | head -1)
SKILLS_BASE="$SKILL_DIR/skills"All script references below use (for own scripts) and (for sub-skills).
$SKILL_DIR$SKILLS_BASESkill可以全局安装()或项目级安装()。运行任何脚本前必须先解析实际路径:
~/.claude/skills/.claude/skills/bash
SKILL_DIR=$(find \
.claude/skills ~/.claude/skills \
.cursor/skills ~/.cursor/skills \
.windsurf/skills ~/.windsurf/skills \
.cline/skills ~/.cline/skills \
.agents/skills ~/.agents/skills \
-maxdepth 1 -name start-workflow -type d 2>/dev/null | head -1)
SKILLS_BASE="$SKILL_DIR/skills"下文所有脚本引用均使用(指向自身脚本)和(指向子Skill)。
$SKILL_DIR$SKILLS_BASEPrerequisites Check
前置依赖检查
bash
bash "$SKILL_DIR/setup.sh"If any dependency is missing, stop and tell the user what to install.
Read to get (optional — skip TG steps if absent).
~/.claude/.envTG_CHAT_IDbash
bash "$SKILL_DIR/setup.sh"如果缺失任何依赖,终止流程并告知用户需要安装的内容。
读取获取(可选 —— 不存在则跳过Telegram相关步骤)。
~/.claude/.envTG_CHAT_IDGit Init Check
Git初始化检查
Check if the current directory is a git repository:
bash
git rev-parse --git-dir 2>/dev/nullIf it is NOT a git repo, tell the user:
当前目录不是 git 仓库,openspec 需要 git 环境。是否现在初始化?(会执行和一个空 commit)git init
If the user agrees, run:
bash
git initThen create a with common defaults before the first commit:
.gitignoreundefined检查当前目录是否为git仓库:
bash
git rev-parse --git-dir 2>/dev/null如果不是git仓库,告知用户:
当前目录不是 git 仓库,openspec 需要 git 环境。是否现在初始化?(会执行和一个空 commit)git init
如果用户同意,运行:
bash
git init随后在首次提交前创建包含通用默认规则的:
.gitignoreundefinedDependencies
Dependencies
node_modules/
.venv/
pycache/
*.pyc
node_modules/
.venv/
pycache/
*.pyc
Lock files (tracked but excluded from review diffs)
Lock files (tracked but excluded from review diffs)
package-lock.json and yarn.lock are intentionally committed
package-lock.json and yarn.lock are intentionally committed
Build output
Build output
dist/
build/
.next/
out/
dist/
build/
.next/
out/
Environment
Environment
.env
.env.local
.env.*.local
.env
.env.local
.env.*.local
Editor & OS
Editor & OS
.DS_Store
.idea/
.vscode/
*.swp
```bash
git add .gitignore
git commit -m "chore: init with .gitignore"If the user declines, stop and explain that a git repo is required.
.DS_Store
.idea/
.vscode/
*.swp
```bash
git add .gitignore
git commit -m "chore: init with .gitignore"如果用户拒绝,终止流程并说明需要git仓库。
Execution Flow
执行流程
Phase 0 — Bootstrap
阶段0 — 启动引导
bash
RUN_DIR=$(python3 "$SKILL_DIR/scripts/bootstrap.py" \
"{feature_name}" "{input_raw}" "{tg_chat_id}")
python3 "$SKILL_DIR/scripts/detect-input.py" "$RUN_DIR/state.json"For (run_id already known): set , read existing state.json, skip phases with .
--resume <run_id>RUN_DIR=/tmp/workflow-<run_id>status: doneFor (no run_id): follow the Resume Flow above to resolve the run_id first, then proceed as above.
--resumebash
RUN_DIR=$(python3 "$SKILL_DIR/scripts/bootstrap.py" \
"{feature_name}" "{input_raw}" "{tg_chat_id}")
python3 "$SKILL_DIR/scripts/detect-input.py" "$RUN_DIR/state.json"对于(已明确run_id)的情况:设置,读取现有state.json,跳过的阶段。
--resume <run_id>RUN_DIR=/tmp/workflow-<run_id>status: done对于(未指定run_id)的情况:先遵循上述恢复流程解析得到run_id,再按上述逻辑执行。
--resumePhase 1 — spec-writer
阶段1 — spec-writer
Load and follow with:
$SKILLS_BASE/spec-writer/SKILL.md- = current run directory
RUN_DIR - = current working directory
PROJECT_DIR - Content = from state.json
state.fetched_content
After spec-writer completes, update state atomically:
python
state['phases']['spec-writer']['status'] = 'done'
state['phase'] = 'coding'加载并遵循执行,传入参数:
$SKILLS_BASE/spec-writer/SKILL.md- = 当前运行目录
RUN_DIR - = 当前工作目录
PROJECT_DIR - Content = state.json中的
state.fetched_content
spec-writer执行完成后,原子化更新状态:
python
state['phases']['spec-writer']['status'] = 'done'
state['phase'] = 'coding'Phase 2 — Coding
阶段2 — 编码
Read . For each task, complete the full cycle before moving to the next:
{specs_dir}/tasks.md- Read the task description
- Implement only that task — do not implement multiple tasks at once
- immediately after implementation
git add -A && git commit -m "feat: {task_name}" - Update atomically
state.phases.coding.last_task - Only then read and start the next task
Do NOT write all code first and commit later. Each task = one commit, in order.
On completion:
python
state['phases']['coding']['status'] = 'done'
state['phase'] = 'code-review'读取。针对每个任务,完成完整周期后再进入下一个任务:
{specs_dir}/tasks.md- 读取任务描述
- 仅实现该任务 —— 不要同时实现多个任务
- 实现完成后立即执行
git add -A && git commit -m "feat: {task_name}" - 原子化更新
state.phases.coding.last_task - 仅在上述步骤完成后读取并开始下一个任务
禁止先编写所有代码再统一提交。每个任务对应一次提交,按顺序执行。
完成后更新状态:
python
state['phases']['coding']['status'] = 'done'
state['phase'] = 'code-review'Phase 3 — code-reviewer
阶段3 — code-reviewer
Load and follow with:
$SKILLS_BASE/code-reviewer/SKILL.md- = current run directory
RUN_DIR - = current working directory
PROJECT_DIR - Max rounds = 2
After code-reviewer completes, update state and advance phase.
加载并遵循执行,传入参数:
$SKILLS_BASE/code-reviewer/SKILL.md- = 当前运行目录
RUN_DIR - = 当前工作目录
PROJECT_DIR - 最大轮次 = 2
code-reviewer执行完成后,更新状态并进入下一阶段。
Phase 4 — Security Gate
阶段4 — 安全门禁
Read and for keywords:
, , , , , , , , , , ,
{specs_dir}/specs{specs_dir}/designauthauthenticationauthorizationpaymentbillingPIIpersonal dataencryptionadminprivilegesudorootIf NOT sensitive: set , continue.
state.phases.security-gate.status = skippedIf sensitive:
bash
MSG_ID=$(python3 "$SKILL_DIR/scripts/tg-send.py" \
"$TG_CHAT_ID" \
"⚠️ *需要安全审批*\n\n功能:{feature_name}({run_id})\n\n未解决问题:\n{findings_list}\n\n回复 /approve 继续,或 /deny 终止。")
python3 "$SKILL_DIR/scripts/tg-poll-approval.py" \
"$TG_CHAT_ID" "$MSG_ID" --timeout 3600
APPROVAL_EXIT=$?读取和检查关键词:
、、、、、、、、、、、
{specs_dir}/specs{specs_dir}/designauthauthenticationauthorizationpaymentbillingPIIpersonal dataencryptionadminprivilegesudoroot如果无敏感内容:设置,继续流程。
state.phases.security-gate.status = skipped如果存在敏感内容:
bash
MSG_ID=$(python3 "$SKILL_DIR/scripts/tg-send.py" \
"$TG_CHAT_ID" \
"⚠️ *需要安全审批*\n\n功能:{feature_name}({run_id})\n\n未解决问题:\n{findings_list}\n\n回复 /approve 继续,或 /deny 终止。")
python3 "$SKILL_DIR/scripts/tg-poll-approval.py" \
"$TG_CHAT_ID" "$MSG_ID" --timeout 3600
APPROVAL_EXIT=$?0=approved, 1=denied, 2=timeout→treat as denied
0=已批准, 1=已拒绝, 2=超时→视为拒绝
Update state accordingly, stop pipeline if denied.
对应更新状态,若被拒绝则终止流水线。Phase 5 — test-runner
阶段5 — test-runner
Load and follow with and .
$SKILLS_BASE/test-runner/SKILL.mdRUN_DIRPROJECT_DIR加载并遵循执行,传入和。
$SKILLS_BASE/test-runner/SKILL.mdRUN_DIRPROJECT_DIRPhase 6 — openspec archive
阶段6 — openspec归档
Only if test-runner status = done (tests passed):
bash
cd "$PROJECT_DIR"
openspec archive "{feature_name}" --yes 2>&1
ARCHIVE_EXIT=$?openspec archive.openspec/changes/{feature_name}/bash
git add -A
git commit -m "chore: archive openspec change {feature_name}"Update accordingly. Failure does NOT stop the pipeline — record warning for TG notification.
state.phases.openspec-archive.status仅当test-runner状态为done(测试通过)时执行:
bash
cd "$PROJECT_DIR"
openspec archive "{feature_name}" --yes 2>&1
ARCHIVE_EXIT=$?openspec archive.openspec/changes/{feature_name}/bash
git add -A
git commit -m "chore: archive openspec change {feature_name}"对应更新。归档失败不会终止流水线 —— 记录警告用于Telegram通知。
state.phases.openspec-archive.statusPhase 7 — doc-syncer
阶段7 — doc-syncer
Load and follow with and .
$SKILLS_BASE/doc-syncer/SKILL.mdRUN_DIRPROJECT_DIR加载并遵循执行,传入和。
$SKILLS_BASE/doc-syncer/SKILL.mdRUN_DIRPROJECT_DIRPhase 8 — Done
阶段8 — 完成
Update state:
python
state['status'] = 'DONE'
state['phase'] = 'done'
state['completed_at'] = datetime.now(timezone.utc).isoformat()Send TG notification if is set.
TG_CHAT_IDBefore sending, compose the message by reading the actual content from artifacts:
- 功能描述:读取 ,提取"问题陈述"和"成功标准",用 1-2 句话概括
{specs_dir}/proposal - 实现内容:读取 ,列出已完成的任务名称(每条一行,最多 5 条)
{specs_dir}/tasks - 审查发现与修复:读取 ,提取实际被修复的 P0/P1 问题描述(非数量,是具体内容);若全部通过则写"无重大问题"
$RUN_DIR/review-round-*.txt - 测试问题:若有失败,从 test-runner 输出中提取失败的测试名称和错误原因(1 句话);若全部通过则写"全部通过"
bash
python3 "$SKILL_DIR/scripts/tg-send.py" \
"$TG_CHAT_ID" \
"✅ *工作流完成*\n\n📦 *{feature_name}*({run_id})\n⏱ 耗时:{duration}\n\n🎯 *功能概述*\n{proposal_summary}\n\n✅ *已实现*\n{tasks_summary}\n\n🔍 *代码审查*({review_rounds} 轮)\n{review_findings_summary}\n\n🧪 *测试*:{test_result_summary}\n\n📁 归档:{archive_status} | 📝 文档:{doc_sync_status}"Print final summary to terminal.
更新状态:
python
state['status'] = 'DONE'
state['phase'] = 'done'
state['completed_at'] = datetime.now(timezone.utc).isoformat()如果设置了则发送Telegram通知。
TG_CHAT_ID发送前从产物中读取实际内容组装消息:
- 功能描述:读取,提取"问题陈述"和"成功标准",用1-2句话概括
{specs_dir}/proposal - 实现内容:读取,列出已完成的任务名称(每条一行,最多5条)
{specs_dir}/tasks - 审查发现与修复:读取,提取实际被修复的P0/P1问题描述(不是数量,是具体内容);若全部通过则写"无重大问题"
$RUN_DIR/review-round-*.txt - 测试问题:若有失败,从test-runner输出中提取失败的测试名称和错误原因(1句话);若全部通过则写"全部通过"
bash
python3 "$SKILL_DIR/scripts/tg-send.py" \
"$TG_CHAT_ID" \
"✅ *工作流完成*\n\n📦 *{feature_name}*({run_id})\n⏱ 耗时:{duration}\n\n🎯 *功能概述*\n{proposal_summary}\n\n✅ *已实现*\n{tasks_summary}\n\n🔍 *代码审查*({review_rounds} 轮)\n{review_findings_summary}\n\n🧪 *测试*:{test_result_summary}\n\n📁 归档:{archive_status} | 📝 文档:{doc_sync_status}"向终端打印最终汇总信息。
State Write Pattern (Atomic)
状态写入模式(原子性)
Always use this pattern — never write state directly:
bash
python3 - "$RUN_DIR/state.json" << 'PYEOF'
import json, os, sys
state_file = sys.argv[1]
state = json.load(open(state_file, encoding='utf-8'))始终使用此模式 —— 永远不要直接写入状态:
bash
python3 - "$RUN_DIR/state.json" << 'PYEOF'
import json, os, sys
state_file = sys.argv[1]
state = json.load(open(state_file, encoding='utf-8'))modify state...
modify state...
tmp = state_file + '.tmp.' + str(os.getpid())
with open(tmp, 'w', encoding='utf-8') as f:
json.dump(state, f, ensure_ascii=False, indent=2)
os.replace(tmp, state_file)
PYEOF
undefinedtmp = state_file + '.tmp.' + str(os.getpid())
with open(tmp, 'w', encoding='utf-8') as f:
json.dump(state, f, ensure_ascii=False, indent=2)
os.replace(tmp, state_file)
PYEOF
undefinedError Handling
错误处理
On any phase error:
- Set ,
state.status = ERRORstate.error = <message> - Send TG notification if TG_CHAT_ID is set
- Print error and run_id to terminal (user can after fixing)
--resume - Stop immediately
任何阶段发生错误时:
- 设置,
state.status = ERRORstate.error = <错误信息> - 如果设置了TG_CHAT_ID则发送Telegram通知
- 向终端打印错误和run_id(用户修复问题后可通过恢复)
--resume - 立即终止流程