| name | skill-planner-hard |
| description | Create hard-mode implementation plans with phase sizing, postmortem constraints, and preserved-assets accounting. Invoke for --hard planning tasks. |
| allowed-tools | Agent, AskUserQuestion, Bash, Edit, Read, Write |
Planner Hard Skill
Hard-mode wrapper that delegates plan creation to planner-hard-agent subagent.
Extends skill-planner with H8 plan requirements passed in delegation context.
Relationship to base skill: Structurally identical to skill-planner except it
dispatches to planner-hard-agent and passes H8 plan requirements.
Maintenance note: changes to skill-planner postflight should be mirrored here.
Context References
Reference (do not load eagerly):
- Path:
.claude/context/formats/return-metadata-file.md - Metadata file schema
- Path:
.claude/context/contracts/reference-grounding.md - H3 contract (loaded by agent)
- Path:
.claude/context/patterns/postflight-control.md - Marker file protocol
- Path:
.claude/context/patterns/jq-escaping-workarounds.md - jq escaping patterns
Trigger Conditions
This skill activates when:
/plan N --hard is invoked and no extension hard variant exists
- Routed here by
command-route-skill.sh with effort_flag="hard"
Execution Flow
Stage 1: Input Validation
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 $task_number not found"
fi
task_type=$(echo "$task_data" | jq -r '.task_type // "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" ] || [ "$status" = "abandoned" ] || [ "$status" = "expanded" ]; then
return error "Task is in terminal state [$status]"
fi
Stage 1.5: Hard-Mode Cost Note
session_flag_file="/tmp/.hard-mode-notified-${SESSION_ID:-$$}"
if [ ! -f "$session_flag_file" ]; then
echo "[hard-mode] Hard mode active. Cost: ~3-5x standard. Use --hard for deflection-prone or formally complex tasks." >&2
touch "$session_flag_file"
fi
Stage 2 + Stage 3: Preflight Status Update and Postflight Marker
Source skill-base.sh once, then follow @.claude/context/patterns/skill-preflight-flow.md in
full for Stage 2 (preflight status update) and Stage 3 (marker creation):
source .claude/scripts/skill-base.sh
padded_num=$(printf "%03d" "$task_number")
skill_name="skill-planner-hard"
operation="plan"
Marker unification note: this skill's marker previously dropped created and
stop_hook_active (Shape C) — a drift, not a hard-mode design decision. Routing through
skill_create_postflight_marker restores both fields as part of this conversion, matching every
other importer's Shape A schema.
Stage 3a: Read Artifact Number
artifact_number=$(jq -r --argjson num "$task_number" \
'.active_projects[] | select(.project_number == $num) | .next_artifact_number // 1' \
specs/state.json)
if [ "$artifact_number" = "null" ] || [ -z "$artifact_number" ]; then
artifact_number=1
fi
plan_artifact_number=$(( artifact_number - 1 ))
[ "$plan_artifact_number" -lt 1 ] && plan_artifact_number=1
plan_padded=$(printf "%02d" "$plan_artifact_number")
Stage 3b: Find Research Report and Prior Plan
padded_num=$(printf "%03d" "$task_number")
task_dir="specs/${padded_num}_${project_name}"
research_path=$(ls "${task_dir}/reports/"*.md 2>/dev/null | sort | tail -1)
prior_plan_path=$(ls "${task_dir}/plans/"*.md 2>/dev/null | sort | tail -1)
Stage 4a: Memory Retrieval (Auto)
if [ "$clean_flag" != "true" ]; then
memory_context=$(bash .claude/scripts/memory-retrieve.sh "$description" "$task_type" "" 2>/dev/null) || memory_context=""
fi
Literature Detection and Injection (Stage 4a, shared block)
Follow @.claude/context/patterns/lit-stage4a-flow.md in full to resolve --lit and set
lit_context: call literature-lit-flag-resolve.sh, branch on all six directives
(LIT_DISABLED, SUBINDEX_PRESENT, GLOBAL_MISSING, PROMPT_NEEDED, AUTONOMOUS_GLOBAL,
SPARSE_PROMPT_NEEDED), issue the real four-option AskUserQuestion for the two interactive
directives (including the "Search online to ingest" option wired to the STABLE-CONTRACT
literature-ingest-online.sh bridge), apply the two-checkpoint sparse re-prompt after "Use
global corpus now", and take the deterministic [lit:auto] autonomous fallback when
orchestrator_mode == "true" (never calling AskUserQuestion in that case). This skill
supplies the shared block's preconditions: lit_flag, description, and orchestrator_mode
(read from the delegation context; default "false" when unset).
Note: lit_flag is independent of clean_flag. Using --clean --lit suppresses memory retrieval but still injects literature briefing. Literature briefing is gated solely on lit_flag == "true".
Stage 4: Prepare Delegation Context
Pass H8 plan requirements explicitly in the delegation context:
{
"session_id": "{session_id}",
"delegation_depth": 1,
"delegation_path": ["orchestrator", "plan", "skill-planner-hard"],
"timeout": 3600,
"task_context": {
"task_number": N,
"task_name": "{project_name}",
"description": "{description}",
"task_type": "{task_type}"
},
"artifact_number": "{plan_artifact_number}",
"research_path": "{research_path or null}",
"prior_plan_path": "{prior_plan_path or null}",
"effort_flag": "hard",
"model_flag": "{model_flag from command, null if not set}",
"roadmap_path": "specs/ROADMAP.md",
"roadmap_flag": "{roadmap_flag from command}",
"metadata_file_path": "specs/{NNN}_{SLUG}/.return-meta.json",
"hard_mode_requirements": {
"phase_sizing_constraint": "Each phase must be completable in one agent run (~100-500 lines output)",
"postmortem_constraints_required": true,
"preserved_assets_accounting": "Required when prior plan exists",
"source_to_implementation_mapping": "Required for Tier 1/2 reference tasks",
"wave_map_required": true
}
}
Stage 4b: Read Format Specification
format_content=$(cat .claude/context/formats/plan-format.md)
Stage 5: Invoke Subagent
Tool: Agent
Parameters:
- subagent_type: "planner-hard-agent"
- prompt: [task_context, delegation_context, format specification, memory_context, lit_context]
- description: "Create hard-mode implementation plan for task {N}"
If lit_context is non-empty, inject it as a <literature-briefing> block after the memory context and before the task-specific instructions.
Stage 5b: Self-Execution Fallback
Follow @.claude/context/patterns/skill-self-execution-fallback.md in full. This skill's success
status value for that block's write obligation is "planned".
Postflight (ALWAYS EXECUTE)
Stage 6: Parse Subagent Return
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")
memory_candidates=$(jq -c '.memory_candidates // []' "$metadata_file")
postmortem_rules_count=$(jq -r '.postmortem_rules_count // 0' "$metadata_file")
echo "[hard-mode] Postmortem rules added to plan: $postmortem_rules_count" >&2
else
status="failed"
fi
Stage 6a: Validate Artifact Content (non-blocking)
if [ "$status" = "planned" ] && [ -n "$artifact_path" ] && [ -f "$artifact_path" ]; then
bash .claude/scripts/validate-artifact.sh "$artifact_path" plan --fix || true
fi
Stage 6b: Skeleton Task Allocation (H8 escape valve)
Duplicate-with-modification of skill-spawn/SKILL.md Stages 7-11 (do NOT extract a shared
helper — this is a deliberate lower-risk, smaller-diff first cut; revisit only if a second
consumer appears). Structurally identical, EXCEPT the dependency direction is REVERSED (see
below) and the artifact consumed is .skeleton-return.json rather than .spawn-return.json.
Runs only when planner-hard-agent (Stage 4a of planner-hard-agent.md) declared a skeleton
plan. No-ops cleanly otherwise.
skeleton_file="specs/${padded_num}_${project_name}/.skeleton-return.json"
if [ -f "$skeleton_file" ] && jq empty "$skeleton_file" 2>/dev/null; then
new_tasks=$(jq -r '.new_tasks' "$skeleton_file")
task_count=$(jq '.new_tasks | length' "$skeleton_file")
if [ "$task_count" -gt 0 ]; then
dependency_order=$(jq -r '.dependency_order' "$skeleton_file")
next_num=$(jq -r '.next_project_number' specs/state.json)
declare -A task_num_map
order_idx=0
for idx in $(echo "$dependency_order" | jq -r '.[]'); do
task_num_map[$idx]=$((next_num + order_idx))
order_idx=$((order_idx + 1))
done
for idx in $(echo "$dependency_order" | jq -r '.[]'); do
new_task_num=${task_num_map[$idx]}
new_padded=$(printf "%03d" "$new_task_num")
task_title=$(jq -r --argjson i "$idx" '.new_tasks[$i].title' "$skeleton_file")
task_slug=$(echo "$task_title" | tr '[:upper:]' '[:lower:]' | tr ' ' '_' | sed 's/[^a-z0-9_]//g')
mkdir -p "specs/${new_padded}_${task_slug}/reports"
done