技能规划器Skill skill-planner

技能规划器是一个用于从研究结果创建分阶段实现计划的自动化工具。它作为薄包装器,委托给planner-agent子代理来生成计划,并处理后置操作如状态更新、工件链接和git提交。适用于任务管理、项目规划和AI代理工作流。关键词:实现计划、任务分解、自动化规划、AI智能体、项目管理、软件开发流程。

AI智能体 0 次安装 0 次浏览 更新于 3/22/2026

name: skill-planner description: 从研究发现创建分阶段实现计划。在任务需要实现计划时调用。 allowed-tools: Task, Bash, Edit, Read, Write, Read(/tmp/.json), Bash(rm:)

原始上下文(现由子代理加载):

- .opencode/context/core/formats/plan-format.md

- .opencode/context/core/workflows/task-breakdown.md

原始工具(现由子代理使用):

- Read, Write, Edit, Glob, Grep


规划器技能

薄包装器,将计划创建委托给 planner-agent 子代理。

重要:此技能实现技能内部后置飞行模式。在子代理返回后,此技能处理所有后置操作(状态更新、工件链接、git提交)然后返回。这消除了技能返回和编排器之间的“继续”提示问题。

上下文引用

引用(不要急切加载):

  • 路径:.opencode/context/core/formats/return-metadata-file.md - 元数据文件架构
  • 路径:.opencode/context/core/patterns/postflight-control.md - 标记文件协议
  • 路径:.opencode/context/core/patterns/file-metadata-exchange.md - 文件 I/O 助手
  • 路径:.opencode/context/core/patterns/jq-escaping-workarounds.md - jq 转义模式(问题 #1132)

注意:此技能是一个带有内部后置飞行的薄包装器。上下文由委托代理加载。

触发条件

此技能在以下情况激活:

  • 任务状态允许规划(未开始、已研究)
  • 调用 /plan 命令
  • 需要正式化实现方法

执行流程

阶段 1:输入验证

验证必需输入:

  • task_number - 必须提供并存在于 state.json 中
  • 任务状态必须允许规划
# 查找任务
task_data=$(jq -r --argjson num "$task_number" \
  '.active_projects[] | select(.project_number == $num)' \
  specs/state.json)

# 验证存在
if [ -z "$task_data" ]; then
  return error "任务 $task_number 未找到"
fi

# 提取字段
language=$(echo "$task_data" | jq -r '.language // "general"')
status=$(echo "$task_data" | jq -r '.status')
project_name=$(echo "$task_data" | jq -r '.project_name')
description=$(echo "$task_data" | jq -r '.description // ""')

# 验证状态
if [ "$status" = "completed" ]; then
  return error "任务已完成"
fi

阶段 2:预飞行状态更新

在调用子代理前更新任务状态为“planning”。

更新 state.json

jq --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
   --arg status "planning" \
   --arg sid "$session_id" \
  '(.active_projects[] | select(.project_number == '$task_number')) |= . + {
    status: $status,
    last_updated: $ts,
    session_id: $sid
  }' specs/state.json > /tmp/state.json && mv /tmp/state.json specs/state.json

更新 TODO.md:使用 Edit 工具将状态标记从 [RESEARCHED][NOT STARTED] 改为 [PLANNING]


阶段 3:创建后置飞行标记

创建标记文件以防止过早终止:

# 确保任务目录存在
padded_num=$(printf "%03d" "$task_number")
mkdir -p "specs/${padded_num}_${project_name}"

cat > "specs/${padded_num}_${project_name}/.postflight-pending" << EOF
{
  "session_id": "${session_id}",
  "skill": "skill-planner",
  "task_number": ${task_number},
  "operation": "plan",
  "reason": "后置飞行待处理:状态更新、工件链接、git 提交",
  "created": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
  "stop_hook_active": false
}
EOF

阶段 4:准备委托上下文

为子代理准备委托上下文:

{
  "session_id": "sess_{timestamp}_{random}",
  "delegation_depth": 1,
  "delegation_path": ["orchestrator", "plan", "skill-planner"],
  "timeout": 1800,
  "task_context": {
    "task_number": N,
    "task_name": "{project_name}",
    "description": "{description}",
    "language": "{language}"
  },
  "research_path": "{如果存在,研究报告的路径}",
  "metadata_file_path": "specs/{NNN}_{SLUG}/.return-meta.json"
}

阶段 5:调用子代理

关键:必须使用 Task 工具来生成子代理。

必需工具调用

工具:Task(非 Skill)
参数:
  - subagent_type: "planner-agent"
  - prompt: [包括 task_context, delegation_context, research_path, metadata_file_path]
  - description: "为任务 {N} 执行规划"

不要使用 Skill(planner-agent) - 这会失败。

子代理将:

  • 加载规划上下文文件
  • 分析任务需求和研究
  • 分解为逻辑阶段
  • 识别风险和缓解措施
  • specs/{NNN}_{SLUG}/plans/ 中创建计划
  • 将元数据写入 specs/{NNN}_{SLUG}/.return-meta.json
  • 返回简要文本摘要(非 JSON)

阶段 6:解析子代理返回(读取元数据文件)

子代理返回后,读取元数据文件:

metadata_file="specs/${padded_num}_${project_name}/.return-meta.json"

if [ -f "$metadata_file" ] && jq empty "$metadata_file" 2>/dev/null; then
    status=$(jq -r '.status' "$metadata_file")
    artifact_path=$(jq -r '.artifacts[0].path // ""' "$metadata_file")
    artifact_type=$(jq -r '.artifacts[0].type // ""' "$metadata_file")
    artifact_summary=$(jq -r '.artifacts[0].summary // ""' "$metadata_file")
else
    echo "错误:无效或缺失元数据文件"
    status="failed"
fi

阶段 7:更新任务状态(后置飞行)

如果状态是“planned”,更新 state.json 和 TODO.md

更新 state.json

jq --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
   --arg status "planned" \
  '(.active_projects[] | select(.project_number == '$task_number')) |= . + {
    status: $status,
    last_updated: $ts,
    planned: $ts
  }' specs/state.json > /tmp/state.json && mv /tmp/state.json specs/state.json

更新 TODO.md:使用 Edit 工具将状态标记从 [PLANNING] 改为 [PLANNED]

部分/失败时:保持状态为“planning”以便恢复。


阶段 8:链接工件

添加工件到 state.json 并附带摘要。

重要:使用两步 jq 模式以避免问题 #1132 转义错误。参考 jq-escaping-workarounds.md

if [ -n "$artifact_path" ]; then
    # 步骤 1:过滤掉现有计划工件(使用“| not”模式以避免 != 转义 - 问题 #1132)
    jq '(.active_projects[] | select(.project_number == '$task_number')).artifacts =
        [(.active_projects[] | select(.project_number == '$task_number')).artifacts // [] | .[] | select(.type == "plan" | not)]' \
      specs/state.json > /tmp/state.json && mv /tmp/state.json specs/state.json

    # 步骤 2:添加新计划工件
    jq --arg path "$artifact_path" \
       --arg type "$artifact_type" \
       --arg summary "$artifact_summary" \
      '(.active_projects[] | select(.project_number == '$task_number')).artifacts += [{"path": $path, "type": $type, "summary": $summary}]' \
      specs/state.json > /tmp/state.json && mv /tmp/state.json specs/state.json
fi

更新 TODO.md:添加工件链接。

TODO.md 剥离 specs/ 前缀TODO.md 在 specs/ 内): todo_link_path="${artifact_path#specs/}"

- **计划**:[implementation-{NNN}.md]({todo_link_path})

阶段 9:Git 提交

提交更改并附带会话 ID:

git add -A
git commit -m "任务 ${task_number}:创建实现计划

会话:${session_id}

共同作者:Claude Opus 4.5 <noreply@anthropic.com>"

阶段 10:清理

移除标记和元数据文件:

rm -f "specs/${padded_num}_${project_name}/.postflight-pending"
rm -f "specs/${padded_num}_${project_name}/.postflight-loop-guard"
rm -f "specs/${padded_num}_${project_name}/.return-meta.json"

阶段 11:返回简要摘要

返回简要文本摘要(非 JSON)。示例:

为任务 {N} 创建计划:
- 定义了 {phase_count} 个阶段,估计 {estimated_hours} 小时
- 关键阶段:{阶段名称}
- 计划创建于 specs/{NNN}_{SLUG}/plans/implementation-{NNN}.md
- 状态更新为 [PLANNED]
- 更改已提交

错误处理

输入验证错误

如果任务未找到或状态无效,立即返回错误消息。

元数据文件缺失

如果子代理未写入元数据文件:

  1. 保持状态为“planning”
  2. 不清理后置飞行标记
  3. 向用户报告错误

Git 提交失败

非阻塞:记录失败但继续成功响应。

jq 解析失败

如果 jq 命令失败并出现 INVALID_CHARACTER 或语法错误(问题 #1132):

  1. 记录到 errors.json:
jq --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
   --arg sid "$session_id" \
   --arg msg "后置飞行工件链接中的 jq 解析错误" \
   --argjson task "$task_number" \
  '.errors += [{
    "id": ("err_" + ($ts | gsub("[^0-9]"; ""))),
    "timestamp": $ts,
    "type": "jq_parse_failure",
    "severity": "medium",
    "message": $msg,
    "context": {"session_id": $sid, "command": "/plan", "task": $task, "checkpoint": "GATE_OUT"},
    "recovery": {"suggested_action": "使用来自 jq-escaping-workarounds.md 的两步 jq 模式", "auto_recoverable": true},
    "fix_status": "unfixed"
  }]' specs/errors.json > /tmp/errors.json && mv /tmp/errors.json specs/errors.json
  1. 使用两步模式重试(已在阶段 8 中实现)

子代理超时

如果子代理超时(默认 1800 秒),返回部分状态。 保持状态为“planning”以便恢复。


返回格式

此技能返回简要文本摘要(非 JSON)。JSON 元数据被写入文件并在内部处理。

成功返回示例:

为任务 414 创建计划:
- 定义了 5 个阶段,估计 2.5 小时
- 覆盖:代理结构、执行流程、错误处理、示例、验证
- 计划创建于 specs/414_create_planner_agent/plans/implementation-001.md
- 状态更新为 [PLANNED]
- 更改已提交,会话 sess_1736700000_abc123

部分返回示例:

为任务 414 部分创建计划:
- 在超时前定义了 3 个阶段,共 5 个
- 部分计划保存于 specs/414_create_planner_agent/plans/implementation-001.md
- 状态保持 [PLANNING] - 运行 /plan 414 以完成