Skip to main content

skill-spawn

Research blockers and spawn new tasks to overcome them, updating parent task dependencies

跳到安装

来源信息

仓库
benbrastmckie/nvim
最近来源活动
2026年8月18日 02:27
检测到的 SKILL.md 语言
英语
星标
444
分支
459

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
skill-spawn
description
Research blockers and spawn new tasks to overcome them, updating parent task dependencies
allowed-tools
Agent, Bash, Edit, Read, Write
# Spawn Skill Thin wrapper that delegates blocker analysis to `spawn-agent` subagent, then handles all state management in postflight: creates new task entries, establishes parent-child relationships, and updates dependencies. **IMPORTANT**: This skill implements the skill-internal postflight pattern. After the subagent returns, this skill handles all postflight operations (task creation, dependency linking, git commit) before returning. This eliminates the "continue" prompt issue between skill return and orchestrator. ## Context References Reference (do not load eagerly): - Path: `.claude/context/formats/return-metadata-file.md` - Metadata file schema - Path: `.claude/context/patterns/postflight-control.md` - Marker file protocol - Path: `.claude/context/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. ## Trigger Conditions This skill activates when: - Task status is not terminal (completed, abandoned, expanded) - /spawn command is invoked with a valid task number --- ## Execution Flow ### Stage 1: Parse Delegation Context Parse inputs from the /spawn command: ```bash # Extract from delegation context task_number=$1 session_id="$2" blocker_prompt="$3" # May be empty # Lookup task data task_data=$(jq -r --argjson num "$task_number" \ '.active_projects[] | select(.project_number == $num)' \ specs/state.json) # Validate exists if [ -z "$task_data" ]; then echo "Error: Task $task_number not found" exit 1 fi # Extract fields project_name=$(echo "$task_data" | jq -r '.project_name') task_type=$(echo "$task_data" | jq -r '.task_type // "general"') status=$(echo "$task_data" | jq -r '.status') description=$(echo "$task_data" | jq -r '.description // ""') parent_topic=$(echo "$task_data" | jq -r '.topic // ""') # Inherited by spawned tasks ``` **Mode A Universal Fallback**: If `parent_topic` is empty, the parent task has no topic. Invoke Mode A per @.claude/context/patterns/topic-assignment-pattern.md (Mode A: Interactive) to let the user assign one now (which will also be inherited by spawned tasks). There is no Skip option; topic assignment is mandatory. ```bash if [[ -z "$parent_topic" ]]; then # Get existing active topics from state.json mapfile -t existing_topics < <(bash .claude/scripts/manage-topics.sh list) # Follow @.claude/context/patterns/topic-assignment-pattern.md (Mode A: Interactive) to # show the picker and capture the result in $parent_topic. fi ``` AskUserQuestion: ```json { "question": "Assign a topic to this task (will be inherited by spawned tasks)?", "header": "Topic", "multiSelect": false, "options": ["<existing-topic-1>", "<existing-topic-2>", "New topic..."] } ``` - If user selects an existing topic → `parent_topic="$selected"` - If user selects "New topic..." → show free-text follow-up and capture as `parent_topic` --- ### Stage 2: Preflight Status Update Determine spawn type and preserve original status before updating. **Spawn type detection**: - If `status` is `blocked`, `implementing`, or `partial` -> Blocker-driven spawn - If `status` is any other non-terminal state -> Holistic decomposition **Note**: `[BLOCKED]` means "has unmet dependencies", not "encountered an error". The parent task transitions to `blocked` because it now depends on spawned subtasks. **Update state.json** (preserve `previous_status`): ```bash padded_num=$(printf "%03d" "$task_number") previous_status=$(echo "$task_data" | jq -r '.status') bash .claude/scripts/state-write.sh \ '(.active_projects[] | select(.project_number == '$task_number')) |= . + { status: $status, previous_status: $prev, last_updated: $ts, session_id: $sid }' \ --session-id "$session_id" \ --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ --arg status "blocked" \ --arg prev "$previous_status" \ --arg sid "$session_id" ``` --- ### Stage 3: (Removed — state.json is authoritative for status) The state.json update in Stage 2 already sets status to "blocked". TODO.md will be regenerated via generate-todo.sh in Stage 14b after all task writes complete. --- ### Stage 4: Create Postflight Marker Source `skill-base.sh` once, then follow `@.claude/context/patterns/skill-preflight-flow.md`'s Stage 3 (marker creation) — Stage 2 above is intentionally left untouched (it writes `status: "blocked"` directly via `state-write.sh`, a genuinely custom transition outside the `research`/`plan`/`implement` vocabulary `skill_preflight_update` requires), only the marker write itself moves onto the shared function. `operation` stays `"spawn"` here, an opaque string with no vocabulary requirement for the marker (see `skill_create_postflight_marker`'s signature in `skill-base.sh`): ```bash source .claude/scripts/skill-base.sh skill_name="skill-spawn" operation="spawn" skill_create_postflight_marker "$padded_num" "$project_name" "$session_id" "$skill_name" "$operation" ``` --- ### Stage 5: Prepare Delegation Context Find the latest plan path (if exists): ```bash plan_path="" if [ -d "specs/${padded_num}_${project_name}/plans" ]; then plan_path=$(ls -t "specs/${padded_num}_${project_name}/plans/"*.md 2>/dev/null | head -1) fi ``` Determine analysis mode for the agent: ```bash analysis_mode="holistic" if [ "$status" = "blocked" ] || [ "$status" = "implementing" ] || [ "$status" = "partial" ] || [ -n "$blocker_prompt" ]; then analysis_mode="blocker" fi ``` Prepare delegation context for the subagent: ```json { "session_id": "sess_{timestamp}_{random}", "delegation_depth": 2, "delegation_path": ["orchestrator", "spawn", "skill-spawn"], "timeout": 1800, "task_number": N, "task_data": { "project_number": N, "project_name": "{slug}", "status": "blocked", "task_type": "{task_type}", "description": "{description}", "effort": "{effort}" }, "blocker_prompt": "{optional user description}", "plan_path": "{path to latest plan or null}", "analysis_mode": "blocker" | "holistic", "metadata_file_path": "specs/{NNN}_{SLUG}/.return-meta.json" } ``` --- ### Stage 6: Invoke Subagent **CRITICAL**: You MUST use the **Agent** tool to spawn the subagent. **Required Tool Invocation**: ``` Tool: Agent (NOT Skill, NOT Plan) Parameters: - subagent_type: "spawn-agent" - prompt: [Include task_number, task_data, blocker_prompt, plan_path, metadata_file_path, session_id] - description: "Analyze blocker for task {N} and propose new tasks" ``` **DO NOT** use `Skill(spawn-agent)` - this will FAIL. The subagent will: - Load task context and plan - Analyze the blocker and identify root cause - Propose minimal new tasks with dependencies - Write blocker analysis report - Write `.spawn-return.json` with task definitions - Return a brief text summary (NOT JSON) --- ### Stage 6b: Self-Execution Fallback **CRITICAL**: If you performed the work above WITHOUT using the Agent tool (i.e., you read files, wrote artifacts, or updated metadata directly instead of spawning a subagent), you MUST write a `.return-meta.json` file now before proceeding to postflight. Use the schema from `return-metadata-file.md` with the appropriate status value for this operation. If you DID use the Agent tool, skip this stage -- the subagent already wrote the metadata. --- ## Postflight (ALWAYS EXECUTE) The following stages MUST execute after work is complete, whether the work was done by a subagent or inline (Stage 6b). Do NOT skip these stages for any reason. ### Stage 7: Read Return Metadata Read the spawn return file: ```bash spawn_file="specs/${padded_num}_${project_name}/.spawn-return.json" if [ -f "$spawn_file" ] && jq empty "$spawn_file" 2>/dev/null; then new_tasks=$(jq -r '.new_tasks' "$spawn_file") task_count=$(jq '.new_tasks | length' "$spawn_file") if [ "$task_count" -eq 0 ]; then echo "Spawn cancelled: no tasks selected." # Cleanup and restore parent status if needed rm -f "specs/${padded_num}_${project_name}/.postflight-pending" rm -f "specs/${padded_num}_${project_name}/.spawn-return.json" exit 0 fi dependency_order=$(jq -r '.dependency_order' "$spawn_file") analysis_summary=$(jq -r '.analysis_summary' "$spawn_file") report_path=$(jq -r '.report_path' "$spawn_file") else echo "Error: Invalid or missing spawn return file" exit 1 fi ``` --- ### Stage 8: Get Next Task Numbers Get the next available task numbers from state.json: ```bash next_num=$(jq -r '.next_project_number' specs/state.json) # Calculate task numbers for each new task based on dependency_order # First task gets next_num, second gets next_num+1, etc. ``` --- ### Stage 9: Apply Topological Sort (Kahn's Algorithm) The agent provides `dependency_order` which is already topologically sorted (foundational tasks first). Map internal indices to actual task numbers: ```bash # Example: dependency_order = [0, 1] means task at index 0 is foundational # If next_num = 242: # - Index 0 -> Task {N} (foundational) # - Index 1 -> Task {M} (depends on {N}) # Build index->task_number mapping 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 ``` --- ### Stage 9.5: File Footprint Overlap Check (Component 4a) Before finalizing any `dependencies` merges (Stage 11), run the shared overlap check across `new_tasks[]`'s `file_scope` entries so two spawned tasks that touch the same files are never left without a serializing edge: ```bash # Pairwise check across all new_tasks using file-footprint-overlap.md's directory-prefix rule # (.claude/context/patterns/file-footprint-overlap.md, referenced by path — not restated here). # For each unordered pair (i, j) of new_tasks indices with no existing dependency edge between # them (checking .new_tasks[i].dependencies and .new_tasks[j].dependencies), if their # file_scope arrays overlap, auto-add an edge from the later index to the earlier one: # .new_tasks[later_idx].dependencies += [earlier_idx] # This mutates the in-memory dependency data used by Stage 9's task_num_map and Stage 11's # internal_deps resolution, so the auto-added edge flows through Kahn's ordering and into # state.json like any agent-declared dependency. ``` **Never silent**: any edge added by this check must be included in the Stage 17 return summary annotated "(auto: file overlap)", distinguishing it from dependencies the `spawn-agent` already declared with explicit reasoning. --- ### Stage 10: Create New Task Directories For each new task, create directory structure: ```bash for idx in $(echo "$dependency_order" | jq -r '.[]'); do new_task_num=${task_num_map[$idx]} new_padded=$(printf "%03d" "$new_task_num") # Get task data from spawn return task_title=$(jq -r --argjson i "$idx" '.new_tasks[$i].title' "$spawn_file") task_slug=$(echo "$task_title" | tr '[:upper:]' '[:lower:]' | tr ' ' '_' | sed 's/[^a-z0-9_]//g') # Create directory with research artifact stub mkdir -p "specs/${new_padded}_${task_slug}/reports" # Copy spawn analysis as initial research for first task # (or create stub pointing to parent's spawn analysis) done ``` ---
在 GitHub 查看
这个 SKILL.md 很大,SkillsMP 这里只预览前一段内容。 在 GitHub 查看