start-workflow

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

start-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

参数

ParamDescription
(none)Prompt the user to enter their requirement
{url|text}
Feature requirement — URL to a spec/issue, or plain text description
--resume
Auto-find recent runs and let user pick one to resume
--resume <run_id>
Resume a specific previous run from its last completed phase
参数描述
(无)提示用户输入需求
{url|text}
功能需求 —— 指向规范/issue的URL,或纯文本描述
--resume
自动查找最近运行记录,让用户选择要恢复的任务
--resume <run_id>
从上次完成的阶段恢复指定的历史运行任务

Resume Flow

恢复流程

If the user invokes
/start-workflow --resume
(no run_id), auto-discover recent runs:
bash
ls -dt /tmp/workflow-*/state.json 2>/dev/null | head -10
For each state.json found, read and extract:
run_id
,
feature_name
,
phase
,
status
,
started_at
.
Present a numbered list to the user:
找到以下未完成的 workflow:
  1. ab12cd34
    — health-check — 中断于 coding(2026-04-12 14:32)
  2. ef56gh78
    — user-auth — 中断于 code-review(2026-04-11 09:15)
请回复编号选择要恢复的 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
status
is not
DONE
— skip completed runs.
如果用户调用
/start-workflow --resume
(未指定run_id),自动发现最近的运行记录:
bash
ls -dt /tmp/workflow-*/state.json 2>/dev/null | head -10
针对每个找到的state.json,读取并提取以下字段:
run_id
feature_name
phase
status
started_at
向用户展示编号列表:
找到以下未完成的 workflow:
  1. ab12cd34
    — health-check — 中断于 coding(2026-04-12 14:32)
  2. ef56gh78
    — user-auth — 中断于 code-review(2026-04-11 09:15)
请回复编号选择要恢复的 run,或回复 n 取消:
  • 如果用户回复数字,使用对应run的
    run_id
  • 如果用户回复"n"或任意取消指令,终止流程
  • 如果未找到状态文件,告知用户:
没有找到可恢复的 workflow run。请直接用
/start-workflow {需求}
开始新的任务。
仅展示
status
不为
DONE
的运行记录 —— 跳过已完成的任务。

Input Collection

输入收集

If the user invokes
/start-workflow
with no arguments, ask:
请描述你想要实现的功能,或者粘贴一个需求链接(GitHub Issue、文档 URL 等):
Wait for the user's reply. Use that as
input_raw
.
Then automatically derive a feature name from the input:
  • From URL: use the last path segment or issue title (e.g.
    issues/42
    → read title →
    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:
功能名称:
health-check
(如需修改请直接回复新名称,确认则回复 ok)
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字符
向用户展示生成的名称:
功能名称:
health-check
(如需修改请直接回复新名称,确认则回复 ok)
如果用户回复新名称则使用该名称,若用户回复"ok"或任意确认指令(好/确认/yes/continue/👍),则使用生成的名称继续流程。

Resolve Skill Directory (run first, every time)

解析Skill目录(每次都优先执行)

Skills can be installed globally (
~/.claude/skills/
) or per-project (
.claude/skills/
). Always resolve the actual path before running any script:
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
$SKILL_DIR
(for own scripts) and
$SKILLS_BASE
(for sub-skills).
Skill可以全局安装(
~/.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_DIR
(指向自身脚本)和
$SKILLS_BASE
(指向子Skill)。

Prerequisites Check

前置依赖检查

bash
bash "$SKILL_DIR/setup.sh"
If any dependency is missing, stop and tell the user what to install.
Read
~/.claude/.env
to get
TG_CHAT_ID
(optional — skip TG steps if absent).
bash
bash "$SKILL_DIR/setup.sh"
如果缺失任何依赖,终止流程并告知用户需要安装的内容。
读取
~/.claude/.env
获取
TG_CHAT_ID
(可选 —— 不存在则跳过Telegram相关步骤)。

Git Init Check

Git初始化检查

Check if the current directory is a git repository:
bash
git rev-parse --git-dir 2>/dev/null
If it is NOT a git repo, tell the user:
当前目录不是 git 仓库,openspec 需要 git 环境。是否现在初始化?(会执行
git init
和一个空 commit)
If the user agrees, run:
bash
git init
Then create a
.gitignore
with common defaults before the first commit:
undefined
检查当前目录是否为git仓库:
bash
git rev-parse --git-dir 2>/dev/null
如果不是git仓库,告知用户:
当前目录不是 git 仓库,openspec 需要 git 环境。是否现在初始化?(会执行
git init
和一个空 commit)
如果用户同意,运行:
bash
git init
随后在首次提交前创建包含通用默认规则的
.gitignore
undefined

Dependencies

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
--resume <run_id>
(run_id already known): set
RUN_DIR=/tmp/workflow-<run_id>
, read existing state.json, skip phases with
status: done
.
For
--resume
(no run_id): follow the Resume Flow above to resolve the run_id first, then proceed as above.
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"
对于
--resume <run_id>
(已明确run_id)的情况:设置
RUN_DIR=/tmp/workflow-<run_id>
,读取现有state.json,跳过
status: done
的阶段。
对于
--resume
(未指定run_id)的情况:先遵循上述恢复流程解析得到run_id,再按上述逻辑执行。

Phase 1 — spec-writer

阶段1 — spec-writer

Load and follow
$SKILLS_BASE/spec-writer/SKILL.md
with:
  • RUN_DIR
    = current run directory
  • PROJECT_DIR
    = current working directory
  • Content =
    state.fetched_content
    from state.json
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
{specs_dir}/tasks.md
. For each task, complete the full cycle before moving to the next:
  1. Read the task description
  2. Implement only that task — do not implement multiple tasks at once
  3. git add -A && git commit -m "feat: {task_name}"
    immediately after implementation
  4. Update
    state.phases.coding.last_task
    atomically
  5. 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
。针对每个任务,完成完整周期后再进入下一个任务:
  1. 读取任务描述
  2. 仅实现该任务 —— 不要同时实现多个任务
  3. 实现完成后立即执行
    git add -A && git commit -m "feat: {task_name}"
  4. 原子化更新
    state.phases.coding.last_task
  5. 仅在上述步骤完成后读取并开始下一个任务
禁止先编写所有代码再统一提交。每个任务对应一次提交,按顺序执行。
完成后更新状态:
python
state['phases']['coding']['status'] = 'done'
state['phase'] = 'code-review'

Phase 3 — code-reviewer

阶段3 — code-reviewer

Load and follow
$SKILLS_BASE/code-reviewer/SKILL.md
with:
  • RUN_DIR
    = current run directory
  • PROJECT_DIR
    = current working directory
  • 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
{specs_dir}/specs
and
{specs_dir}/design
for keywords:
auth
,
authentication
,
authorization
,
payment
,
billing
,
PII
,
personal data
,
encryption
,
admin
,
privilege
,
sudo
,
root
If NOT sensitive: set
state.phases.security-gate.status = skipped
, continue.
If 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}/design
检查关键词:
auth
authentication
authorization
payment
billing
PII
personal data
encryption
admin
privilege
sudo
root
如果无敏感内容:设置
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
$SKILLS_BASE/test-runner/SKILL.md
with
RUN_DIR
and
PROJECT_DIR
.
加载并遵循
$SKILLS_BASE/test-runner/SKILL.md
执行,传入
RUN_DIR
PROJECT_DIR

Phase 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
moves
.openspec/changes/{feature_name}/
into an archive directory, leaving uncommitted changes in the working tree. After a successful archive, commit these changes:
bash
git add -A
git commit -m "chore: archive openspec change {feature_name}"
Update
state.phases.openspec-archive.status
accordingly. Failure does NOT stop the pipeline — record warning for TG notification.
仅当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}"
对应更新
state.phases.openspec-archive.status
。归档失败不会终止流水线 —— 记录警告用于Telegram通知。

Phase 7 — doc-syncer

阶段7 — doc-syncer

Load and follow
$SKILLS_BASE/doc-syncer/SKILL.md
with
RUN_DIR
and
PROJECT_DIR
.
加载并遵循
$SKILLS_BASE/doc-syncer/SKILL.md
执行,传入
RUN_DIR
PROJECT_DIR

Phase 8 — Done

阶段8 — 完成

Update state:
python
state['status'] = 'DONE'
state['phase']  = 'done'
state['completed_at'] = datetime.now(timezone.utc).isoformat()
Send TG notification if
TG_CHAT_ID
is set.
Before sending, compose the message by reading the actual content from artifacts:
  • 功能描述:读取
    {specs_dir}/proposal
    ,提取"问题陈述"和"成功标准",用 1-2 句话概括
  • 实现内容:读取
    {specs_dir}/tasks
    ,列出已完成的任务名称(每条一行,最多 5 条)
  • 审查发现与修复:读取
    $RUN_DIR/review-round-*.txt
    ,提取实际被修复的 P0/P1 问题描述(非数量,是具体内容);若全部通过则写"无重大问题"
  • 测试问题:若有失败,从 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()
如果设置了
TG_CHAT_ID
则发送Telegram通知。
发送前从产物中读取实际内容组装消息:
  • 功能描述:读取
    {specs_dir}/proposal
    ,提取"问题陈述"和"成功标准",用1-2句话概括
  • 实现内容:读取
    {specs_dir}/tasks
    ,列出已完成的任务名称(每条一行,最多5条)
  • 审查发现与修复:读取
    $RUN_DIR/review-round-*.txt
    ,提取实际被修复的P0/P1问题描述(不是数量,是具体内容);若全部通过则写"无重大问题"
  • 测试问题:若有失败,从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
undefined
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
undefined

Error Handling

错误处理

On any phase error:
  1. Set
    state.status = ERROR
    ,
    state.error = <message>
  2. Send TG notification if TG_CHAT_ID is set
  3. Print error and run_id to terminal (user can
    --resume
    after fixing)
  4. Stop immediately
任何阶段发生错误时:
  1. 设置
    state.status = ERROR
    state.error = <错误信息>
  2. 如果设置了TG_CHAT_ID则发送Telegram通知
  3. 向终端打印错误和run_id(用户修复问题后可通过
    --resume
    恢复)
  4. 立即终止流程