CtrlK
BlogDocsLog inGet started
Tessl Logo
SkillPublic

tapd-iteration-runner

TAPD 迭代调度器——批量开发一个迭代中的全部需求。自动完成环境初始化、 需求依赖分析、逐需求调度 pipeline 实现、迭代汇总报告四段编排。 Use this skill whenever the user mentions 迭代执行, 开发迭代, 批量需求实现, TDD 迭代, dry run, batch requirement implementation, TAPD iteration development, speckit-based iteration, 迭代开发, or any workflow involving batch TAPD story processing with iteration-level coordination — even if the user only says "帮我开发这个迭代" or "跑一下迭代".

Quality

87%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide
SecuritybySnyk

Low

Low-risk findings worth noting

SKILL.md
Quality
Evals
Security

TAPD 迭代调度器

1. 定位

本 skill 负责迭代级编排:建分支、拉需求、依赖排序、依次调度每个需求的 pipeline、迭代收尾。

runner 不知道的事:

  • 需求内部的子 skill 步骤是什么
  • speckit 命令长什么样
  • context.md / req.md / spec.md 的格式
  • subagent prompt 怎么渲染
  • 单需求层面的重入怎么做

这些全部由 tapd-story-pipeline 承担。runner 在自己的主上下文中内联加载并执行 tapd-story-pipeline/SKILL.md,仅根据 meta.yaml 与 questions.md 做决策。

2. 基础配置

项目根目录下的 project.json 提供默认配置:

{
  "workspace_id": "对应的 TAPD 工作空间 ID",
  "owner": "开发者 ID"
}

取值优先级(适用于 workspace_id 和 owner):

  1. 用户在消息中显式指定 → 最高优先
  2. project.json 中的配置 → 次优先
  3. 通过 TAPD MCP 自动获取(仅 owner)→ 再次
  4. 交互式询问用户 → 最低优先(兜底)

iteration_id 无默认值,必须由用户提供或通过交互获取。

3. runner → pipeline 参数传递

用户在发起迭代时可指定 agent 工具名称(如 agent / claude / cursor),存入 iteration-state.json.agent_tool。未指定时默认为 agent。

runner 内联执行 pipeline 时把 agent_tool 作为入参传入;pipeline 在自己的 meta.yaml 中 也写一份,作为后续单次调起的入参回退。(agent_tool 决定 pipeline 子 skill 用哪种 subagent 工具。)

workspace_id 同理:runner 在 loop 内联执行时把 iteration-state.json.workspace_id 作为入参传给 pipeline;pipeline 首次执行时把它落到 meta.yaml.workspace_id, 后续 pipeline 子 skill(如 commit 调 stories_update、req.md 兜底注入调 stories_get) 统一从 meta.yaml 取,避免依赖运行时入参或 project.json 兜底。

4. 子 Skill 编排

顺序子 skill职责停断点
1tapd-iteration-init环境检查、分支创建、状态初始化、恢复检测否
2tapd-iteration-analysis需求依赖分析、DAG 构建、拓扑排序否
3(内联)loop对 sequence 中每个需求内联执行 tapd-story-pipeline是
4tapd-iteration-report迭代汇总:changelog + 效能报告 + 推送否

5. iteration-state.json

迭代级状态文件,保存在 specs/${VERSION}/iteration-state.json。

完整字段定义见 references/iteration-state-schema.md。

决策常用字段速查:

你需要…读取字段
判断迭代所处阶段status
遍历待实现需求sequence
判断某需求是否完成stories.*.phase(派生自 meta.yaml)
传递参数给 pipelineiter_branch, agent_tool, workspace_id
汇总效能数据stories.*.stats(派生自 meta.yaml)

写入权限:

  • runner 完全拥有 iteration-state.json,因为迭代级状态只有一个写者,避免 runner 与 pipeline 并发修改导致数据冲突
  • stories.*.phase 和 stats 是 meta.yaml 的派生缓存——runner 在 loop 中从各需求的 meta.yaml 同步过来,用于在 iteration-state.json 单点呈现迭代级全局视图
  • runner 不直接修改 pipeline 的 meta.yaml——pipeline 对自己的 meta.yaml 有完整的校验逻辑(state-mutation-guide.md §4),外部修改必须遵循 §7 速查表规则,确保 phase 与产物的对应关系始终合法

6. 状态流转

initialized → analyzed → implementing → completed → reported
                        └→ bugfix ──────┘
状态说明
initialized环境初始化已完成
analyzed需求依赖分析完成
implementing需求实现中(loop 进行中)
bugfix已发布版本出现 bug,回到迭代修复
completed所有需求 phase=committed
reported迭代汇总已完成(终态)

7. loop 调度逻辑

runner 主 SKILL 的核心。对 sequence 中每个 ID,用语义指令调度 pipeline。 runner 不修改 meta.yaml——所有状态变更由 pipeline 执行。

以下为逻辑伪代码(非可执行脚本),描述 runner 的语义调度循环:

for ID in sequence:
    iteration_state.selected_story = ID
    workdir = f"specs/{VERSION}/{ID}"

    # 记录壁钟开始时间(仅首次;持久化以便恢复后仍可计算耗时)
    if not iteration_state.stories[ID].started_at:
        iteration_state.stories[ID].started_at = now_iso8601()
        save_iteration_state()

    # 注入 req.md(首次)
    if not exists(f"{workdir}/req.md"):
        ensure_dir(workdir)
        if exists(f"specs/{VERSION}/.tmp/{ID}.md"):
            copy(f"specs/{VERSION}/.tmp/{ID}.md", f"{workdir}/req.md")
        else:
            desc = tapd_mcp.stories_get(workspace_id, id=ID).description
            write_file(f"{workdir}/req.md", desc)

    action = "execute"  # 首次用 execute

    while True:
        # 内联执行 pipeline(runner 不修改 meta.yaml):
        # 按 action 与入参加载并执行 skills/tapd-story-pipeline/SKILL.md,
        # pipeline 在当前上下文中推进到下一个卡点后退出
        # (其子 skill specify/plan/... 各自拉 speckit subagent)。
        run_inline(skill="skills/tapd-story-pipeline/SKILL.md",
                   action=action, story_id=ID, workdir=workdir,
                   workspace_id=iteration_state.workspace_id,
                   agent_tool=iteration_state.agent_tool,
                   iter_branch=iteration_state.iter_branch)

        # pipeline 退出后读 meta.yaml(只读)判断结果
        meta = read_yaml(f"{workdir}/meta.yaml")

        if meta.phase == "committed":
            # 记录壁钟耗时 = committed 时刻 − started_at
            iteration_state.stories[ID].stats.duration_sec = \
                now_epoch() - parse_iso8601(iteration_state.stories[ID].started_at)
            sync_to_iteration_state(ID, phase="committed", stats=meta.stats)
            save_iteration_state()
            break

        # 根据卡点确定下一个 action(参见 state-mutation-guide.md §8)
        if meta.last_failure:
            if meta.last_failure.type == "system" and meta.attempts < 2:
                action = "retry"  # 自动重试,无需与用户对话
            else:
                user_input = chat_with_user(meta.last_failure)
                if user_input == "重试":
                    # 用户可能已修改 req.md / spec.md 等内容文件,并写好 attempt-md
                    action = "retry"
                else:
                    action = "abort"

        elif meta.pending_review:
            user_input = chat_with_user(meta.pending_review)
            if user_input == "通过":
                action = "approve"
            elif user_input == "回退":
                # 用户已写好 iteration-patches/attempt-${N}.md
                action = "reject"
            else:
                action = "abort"

        elif has_open_questions(f"{workdir}/questions.md"):
            user_answers = chat_with_user(read_open_questions(workdir))
            write_answers_to_questions_md(workdir, user_answers)
            action = "answer"

        else:
            # pipeline 退出异常
            notify_user(f"pipeline 退出异常,请检查 {workdir}/process.log")
            if chat_with_user("重试?") == "重试":
                action = "execute"
            else:
                break

关键原则:runner 只做三件事——

  1. 读 meta.yaml(只读)判断卡点
  2. 与用户对话
  3. 写用户输入文件(questions.md 答复、attempt-md)并确定下一个 action

8. 与 pipeline 的通信契约

8.1 内联调用约定

runner 在 loop 中内联执行 pipeline,传入以下入参:

入参来源
ACTIONloop 决策结果(execute / approve / reject / answer / retry / abort)
WORKDIRspecs/${VERSION}/${ID}
WORKSPACE_IDiteration-state.json.workspace_id
AGENT_TOOLiteration-state.json.agent_tool
ITER_BRANCHiteration-state.json.iter_branch

runner 按上述入参与 ACTION 加载并执行 skills/tapd-story-pipeline/SKILL.md。 pipeline 推进到下一个卡点后退出(输出其 §8.1 退出报告),控制权回到 loop。

ACTION 取值:execute / approve / reject / answer / retry / abort 各指令语义见 ../tapd-story-pipeline/references/state-mutation-guide.md §2。

8.2 退出后读取的文件

runner 只读以下文件(不写 meta.yaml):

  • ${WORKDIR}/meta.yaml — 只读,判断卡点类型
  • ${WORKDIR}/questions.md — 只读判断 + 写答复(外部可写的内容文件)
  • ${WORKDIR}/commit.md — 仅在 tapd-iteration-report 阶段批量读取

8.3 退出报告用途

pipeline 退出时输出的文字报告面向用户,runner 的决策不依赖退出报告——所有决策数据从 meta.yaml(只读)和 questions.md 读取。

8.4 契约版本

本契约基于 tapd-story-pipeline v1.1.0 语义指令模式 + runner v2.0.0 内联执行模式。runner 的 loop 逻辑与 state-mutation-guide.md §8 runner 速查表保持同步。

9. 恢复机制

当 tapd-iteration-init 检测到已有未完成的 iteration-state.json 时,按 references/recovery.md 流程恢复。恢复时:

  1. 读 iteration-state.json
  2. 对 sequence 中所有非 committed 需求,加载其 meta.yaml
  3. 同步 meta.yaml.phase / meta.yaml.stats 到 iteration-state.json.stories.*.phase / stats (派生缓存的一次性回填)
  4. 遗留的卡点(last_failure / pending_review / questions.md [open])由 loop 在下一轮调度时自然处理

10. 迭代汇总触发

每次 pipeline 退出且推进了 phase 后,runner 检查所有需求 phase 是否全部为 committed:

  • 是 → iteration-state.json.status = completed,加载 tapd-iteration-report/SKILL.md 执行汇总;汇总完成后 status = reported(终态)
  • 否 → 继续 loop

11. 平台约定

OSShell备注
Linux / macOSBash默认
WindowsPowerShell首次运行设置 [Console]::OutputEncoding = [System.Text.Encoding]::UTF8

${AGENT_TOOL} 从 iteration-state.json.agent_tool 字段读取。

12. 参考文件

文件用途加载时机
references/iteration-state-schema.mditeration-state.json 完整字段定义与写入权限需要查看字段结构时
references/recovery.md迭代级断点恢复映射表init 阶段检测到已有状态时
references/error-handling.md迭代层错误处理规则遇到 TAPD MCP / git / pipeline 异常时
references/dependency-types.md技术依赖与业务依赖判定条件analysis 阶段识别需求依赖时
references/report-scripts.mdchangelog 和 summary 生成脚本report 阶段需要实现细节时
../tapd-story-pipeline/references/state-mutation-guide.md必读:runner 决策依据(§7 速查表)loop 决策时

13. Example: 3 需求迭代 Happy Path

用户输入:"帮我开发 TAPD 迭代 #1001234 的需求,workspace_id 是 20000001"

阶段 1 — init:

  • 读取 project.json 获取 workspace_id=20000001
  • 调 TAPD MCP iterations_get → 迭代名称 iteration-v0.9.x
  • 创建分支 v0.9.x,创建 specs/v0.9.x/,写入 iteration-state.json(status=initialized)

阶段 2 — analysis:

  • 调 TAPD MCP stories_get → 3 个子需求 A、B、C
  • A 无依赖,B 依赖 A(共享模块),C 依赖 B(接口依赖)
  • sequence = [A, B, C],status → analyzed

阶段 3 — loop:

需求 A:内联执行 pipeline → phase 推进到 committed → sync → 下一个
需求 B:内联执行 pipeline → phase=tasks-generated(confirm 卡点)
  → runner 展示 artifacts → 用户"通过" → phase=confirmed → 再次内联执行 → committed
需求 C:内联执行 pipeline → committed
全部 committed → status=completed

阶段 4 — report:

  • 生成 changelog.md(v0.9.0)
  • 生成 summary.md(效能统计)
  • patch 自增 → 1
  • git commit + push → status=reported(终态)
Repository

TencentBlueKing/bk-bcs

Path

.agents/skills/tapd-iteration-runner/SKILL.md

Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.