skill-planner
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePlanner Skill
Planner 技能
Thin wrapper that delegates plan creation to subagent.
planner-agentIMPORTANT: 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: - Metadata file schema
.claude/context/core/formats/return-metadata-file.md - Path: - Marker file protocol
.claude/context/core/patterns/postflight-control.md - Path: - File I/O helpers
.claude/context/core/patterns/file-metadata-exchange.md - Path: - jq escaping patterns (Issue #1132)
.claude/context/core/patterns/jq-escaping-workarounds.md
Note: This skill is a thin wrapper with internal postflight. Context is loaded by the delegated agent.
引用(请勿提前加载):
- 路径:- 元数据文件 schema
.claude/context/core/formats/return-metadata-file.md - 路径:- 标记文件协议
.claude/context/core/patterns/postflight-control.md - 路径:- 文件I/O辅助工具
.claude/context/core/patterns/file-metadata-exchange.md - 路径:- jq转义模式(问题#1132)
.claude/context/core/patterns/jq-escaping-workarounds.md
注意:此技能是带有内部飞行后处理的轻量封装层,上下文由被委托的代理加载。
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:
- - Must be provided and exist in state.json
task_number - Task status must allow planning
bash
undefined验证必填输入:
- - 必须提供且存在于state.json中
task_number - 任务状态必须允许规划
bash
undefinedLookup task
Lookup task
task_data=$(jq -r --argjson num "$task_number"
'.active_projects[] | select(.project_number == $num)'
specs/state.json)
'.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)
'.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.jsonUpdate TODO.md: Use Edit tool to change status marker from or to .
[RESEARCHED][NOT STARTED][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
undefinedEnsure 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 - this will FAIL.
Skill(planner-agent)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"
fiStage 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.jsonUpdate TODO.md: Use Edit tool to change status marker from to .
[PLANNING][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.mdbash
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
fiUpdate TODO.md: Add plan artifact link:
markdown
- **Plan**: [implementation-{NNN}.md]({artifact_path})将工件添加到state.json并附带摘要。
重要提示:使用两步jq模式以避免问题#1132中的转义错误。请参阅。
jq-escaping-workarounds.mdbash
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:
- Keep status as "planning"
- Do not cleanup postflight marker
- Report error to user
如果子代理未写入元数据文件:
- 保持状态为“planning”
- 不清理飞行后标记文件
- 向用户报告错误
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):
- 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- Retry with two-step pattern (already implemented in Stage 8)
如果jq命令因INVALID_CHARACTER或语法错误失败(问题#1132):
- 记录到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- 使用两步模式重试(已在阶段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_abc123Example 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以完成