skill-planner

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Planner Skill

Planner 技能

Thin wrapper that delegates plan creation to
planner-agent
subagent.
IMPORTANT: This skill implements the skill-internal postflight pattern. After the subagent returns, this skill handles all postflight operations (status update, artifact linking, git commit) before returning. This eliminates the "continue" prompt issue between skill return and orchestrator.
这是一个轻量封装层,将计划创建任务委托给
planner-agent
子代理。
重要提示:此技能实现了技能内部的飞行后(postflight)模式。子代理返回结果后,此技能会在返回前处理所有飞行后操作(状态更新、工件关联、Git提交)。这消除了技能返回与编排器之间的“继续”提示问题。

Context References

上下文引用

Reference (do not load eagerly):
  • Path:
    .claude/context/core/formats/return-metadata-file.md
    - Metadata file schema
  • Path:
    .claude/context/core/patterns/postflight-control.md
    - Marker file protocol
  • Path:
    .claude/context/core/patterns/file-metadata-exchange.md
    - File I/O helpers
  • Path:
    .claude/context/core/patterns/jq-escaping-workarounds.md
    - jq escaping patterns (Issue #1132)
Note: This skill is a thin wrapper with internal postflight. Context is loaded by the delegated agent.
引用(请勿提前加载):
  • 路径:
    .claude/context/core/formats/return-metadata-file.md
    - 元数据文件 schema
  • 路径:
    .claude/context/core/patterns/postflight-control.md
    - 标记文件协议
  • 路径:
    .claude/context/core/patterns/file-metadata-exchange.md
    - 文件I/O辅助工具
  • 路径:
    .claude/context/core/patterns/jq-escaping-workarounds.md
    - jq转义模式(问题#1132)
注意:此技能是带有内部飞行后处理的轻量封装层,上下文由被委托的代理加载。

Trigger Conditions

触发条件

This skill activates when:
  • Task status allows planning (not_started, researched)
  • /plan command is invoked
  • Implementation approach needs to be formalized

当满足以下条件时,此技能激活:
  • 任务状态允许规划(not_started、researched)
  • 调用了/plan命令
  • 需要将实施方法正式化

Execution Flow

执行流程

Stage 1: Input Validation

阶段1:输入验证

Validate required inputs:
  • task_number
    - Must be provided and exist in state.json
  • Task status must allow planning
bash
undefined
验证必填输入:
  • task_number
    - 必须提供且存在于state.json中
  • 任务状态必须允许规划
bash
undefined

Lookup task

Lookup task

task_data=$(jq -r --argjson num "$task_number"
'.active_projects[] | select(.project_number == $num)'
specs/state.json)
task_data=$(jq -r --argjson num "$task_number"
'.active_projects[] | select(.project_number == $num)'
specs/state.json)

Validate exists

Validate exists

if [ -z "$task_data" ]; then return error "Task $task_number not found" fi
if [ -z "$task_data" ]; then return error "Task $task_number not found" fi

Extract fields

Extract fields

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 // ""')
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 // ""')

Validate status

Validate status

if [ "$status" = "completed" ]; then return error "Task already completed" fi

---
if [ "$status" = "completed" ]; then return error "Task already completed" fi

---

Stage 2: Preflight Status Update

阶段2:飞行前状态更新

Update task status to "planning" BEFORE invoking subagent.
Update state.json:
bash
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
Update TODO.md: Use Edit tool to change status marker from
[RESEARCHED]
or
[NOT STARTED]
to
[PLANNING]
.

在调用子代理之前,将任务状态更新为“planning”。
更新state.json
bash
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:使用编辑工具将状态标记从
[RESEARCHED]
[NOT STARTED]
更改为
[PLANNING]

Stage 3: Create Postflight Marker

阶段3:创建飞行后标记文件

Create the marker file to prevent premature termination:
bash
undefined
创建标记文件以防止提前终止:
bash
undefined

Ensure task directory exists

Ensure task directory exists

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": "Postflight pending: status update, artifact linking, git commit", "created": "$(date -u +%Y-%m-%dT%H:%M:%SZ)", "stop_hook_active": false } EOF

---
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": "Postflight pending: status update, artifact linking, git commit", "created": "$(date -u +%Y-%m-%dT%H:%M:%SZ)", "stop_hook_active": false } EOF

---

Stage 4: Prepare Delegation Context

阶段4:准备委托上下文

Prepare delegation context for the subagent:
json
{
  "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": "{path to research report if exists}",
  "metadata_file_path": "specs/{NNN}_{SLUG}/.return-meta.json"
}

为子代理准备委托上下文:
json
{
  "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": "{path to research report if exists}",
  "metadata_file_path": "specs/{NNN}_{SLUG}/.return-meta.json"
}

Stage 5: Invoke Subagent

阶段5:调用子代理

CRITICAL: You MUST use the Task tool to spawn the subagent.
Required Tool Invocation:
Tool: Task (NOT Skill)
Parameters:
  - subagent_type: "planner-agent"
  - prompt: [Include task_context, delegation_context, research_path, metadata_file_path]
  - description: "Execute planning for task {N}"
DO NOT use
Skill(planner-agent)
- this will FAIL.
The subagent will:
  • Load planning context files
  • Analyze task requirements and research
  • Decompose into logical phases
  • Identify risks and mitigations
  • Create plan in
    specs/{NNN}_{SLUG}/plans/
  • Write metadata to
    specs/{NNN}_{SLUG}/.return-meta.json
  • Return a brief text summary (NOT JSON)

关键注意事项:必须使用Task工具来生成子代理。
必需的工具调用
Tool: Task (NOT Skill)
Parameters:
  - 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格式)

Stage 6: Parse Subagent Return (Read Metadata File)

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

After subagent returns, read the metadata file:
bash
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 "Error: Invalid or missing metadata file"
    status="failed"
fi

子代理返回后,读取元数据文件:
bash
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 "Error: Invalid or missing metadata file"
    status="failed"
fi

Stage 7: Update Task Status (Postflight)

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

If status is "planned", update state.json and TODO.md:
Update state.json:
bash
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
Update TODO.md: Use Edit tool to change status marker from
[PLANNING]
to
[PLANNED]
.
On partial/failed: Keep status as "planning" for resume.

如果状态为“planned”,更新state.json和TODO.md:
更新state.json
bash
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:使用编辑工具将状态标记从
[PLANNING]
更改为
[PLANNED]
部分完成/失败时:保持状态为“planning”以便恢复。

Stage 8: Link Artifacts

阶段8:关联工件

Add artifact to state.json with summary.
IMPORTANT: Use two-step jq pattern to avoid Issue #1132 escaping bug. See
jq-escaping-workarounds.md
.
bash
if [ -n "$artifact_path" ]; then
    # Step 1: Filter out existing plan artifacts (use "| not" pattern to avoid != escaping - Issue #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

    # Step 2: Add new plan artifact
    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
Update TODO.md: Add plan artifact link:
markdown
- **Plan**: [implementation-{NNN}.md]({artifact_path})

将工件添加到state.json并附带摘要。
重要提示:使用两步jq模式以避免问题#1132中的转义错误。请参阅
jq-escaping-workarounds.md
bash
if [ -n "$artifact_path" ]; then
    # Step 1: Filter out existing plan artifacts (use "| not" pattern to avoid != escaping - Issue #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

    # Step 2: Add new plan artifact
    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:添加计划工件链接:
markdown
- **Plan**: [implementation-{NNN}.md]({artifact_path})

Stage 9: Git Commit

阶段9:Git提交

Commit changes with session ID:
bash
git add -A
git commit -m "task ${task_number}: create implementation plan

Session: ${session_id}

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>"

使用会话ID提交更改:
bash
git add -A
git commit -m "task ${task_number}: create implementation plan

Session: ${session_id}

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>"

Stage 10: Cleanup

阶段10:清理

Remove marker and metadata files:
bash
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"

删除标记文件和元数据文件:
bash
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"

Stage 11: Return Brief Summary

阶段11:返回简短摘要

Return a brief text summary (NOT JSON). Example:
Plan created for task {N}:
- {phase_count} phases defined, {estimated_hours} hours estimated
- Key phases: {phase names}
- Created plan at specs/{NNN}_{SLUG}/plans/implementation-{NNN}.md
- Status updated to [PLANNED]
- Changes committed

返回简短的文本摘要(非JSON格式)。示例:
已为任务{N}创建计划:
- 定义了{phase_count}个阶段,预估{estimated_hours}小时
- 核心阶段:{phase names}
- 计划已创建于specs/{NNN}_{SLUG}/plans/implementation-{NNN}.md
- 状态已更新为[PLANNED]
- 更改已提交

Error Handling

错误处理

Input Validation Errors

输入验证错误

Return immediately with error message if task not found or status invalid.
如果任务未找到或状态无效,立即返回错误消息。

Metadata File Missing

元数据文件缺失

If subagent didn't write metadata file:
  1. Keep status as "planning"
  2. Do not cleanup postflight marker
  3. Report error to user
如果子代理未写入元数据文件:
  1. 保持状态为“planning”
  2. 不清理飞行后标记文件
  3. 向用户报告错误

Git Commit Failure

Git提交失败

Non-blocking: Log failure but continue with success response.
非阻塞:记录失败但继续返回成功响应。

jq Parse Failure

jq解析失败

If jq commands fail with INVALID_CHARACTER or syntax error (Issue #1132):
  1. Log to errors.json:
bash
jq --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
   --arg sid "$session_id" \
   --arg msg "jq parse error in postflight artifact linking" \
   --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": "Use two-step jq pattern from jq-escaping-workarounds.md", "auto_recoverable": true},
    "fix_status": "unfixed"
  }]' specs/errors.json > /tmp/errors.json && mv /tmp/errors.json specs/errors.json
  1. Retry with two-step pattern (already implemented in Stage 8)
如果jq命令因INVALID_CHARACTER或语法错误失败(问题#1132):
  1. 记录到errors.json:
bash
jq --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
   --arg sid "$session_id" \
   --arg msg "jq parse error in postflight artifact linking" \
   --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": "Use two-step jq pattern from jq-escaping-workarounds.md", "auto_recoverable": true},
    "fix_status": "unfixed"
  }]' specs/errors.json > /tmp/errors.json && mv /tmp/errors.json specs/errors.json
  1. 使用两步模式重试(已在阶段8中实现)

Subagent Timeout

子代理超时

Return partial status if subagent times out (default 1800s). Keep status as "planning" for resume.

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

Return Format

返回格式

This skill returns a brief text summary (NOT JSON). The JSON metadata is written to the file and processed internally.
Example successful return:
Plan created for task 414:
- 5 phases defined, 2.5 hours estimated
- Covers: agent structure, execution flow, error handling, examples, verification
- Created plan at specs/414_create_planner_agent/plans/implementation-001.md
- Status updated to [PLANNED]
- Changes committed with session sess_1736700000_abc123
Example partial return:
Plan partially created for task 414:
- 3 of 5 phases defined before timeout
- Partial plan saved at specs/414_create_planner_agent/plans/implementation-001.md
- Status remains [PLANNING] - run /plan 414 to complete
此技能返回简短的文本摘要(非JSON格式)。JSON元数据会写入文件并在内部处理。
成功返回示例:
已为任务414创建计划:
- 定义了5个阶段,预估2.5小时
- 涵盖:代理结构、执行流程、错误处理、示例、验证
- 计划已创建于specs/414_create_planner_agent/plans/implementation-001.md
- 状态已更新为[PLANNED]
- 已使用会话sess_1736700000_abc123提交更改
部分完成返回示例:
已为任务414部分创建计划:
- 超时前已定义5个阶段中的3个
- 部分计划已保存于specs/414_create_planner_agent/plans/implementation-001.md
- 状态保持为[PLANNING] - 运行/plan 414以完成