Skip to main content

skill-orchestrate

Autonomous state machine that drives a task through its full lifecycle (research -> plan -> implement -> complete) without user confirmation between phases. Invoke for /orchestrate command.

Jump to install

Source facts

Repository
benbrastmckie/nvim
Last source activity
August 18, 2026 at 00:48
Detected SKILL.md language
English
Stars
444
Forks
459

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
skill-orchestrate
description
Autonomous state machine that drives a task through its full lifecycle (research -> plan -> implement -> complete) without user confirmation between phases. Invoke for /orchestrate command.
allowed-tools
Agent, Bash, Read, Edit
# Orchestrate Skill Fire-and-forget autonomous loop implementing the 10-state task lifecycle state machine. Drives research, planning, implementation, and blocker escalation without user interaction. ## Context References Architecture documentation (load as needed): - `.claude/docs/architecture/orchestrate-state-machine.md` - Complete state table and transition diagram - `.claude/docs/architecture/handoff-schema.md` - Orchestrator handoff JSON schema Infrastructure (source as needed): - `.claude/scripts/skill-base.sh` - Shared skill lifecycle functions --- ## Execution Flow ### Stage 0: Multi-Task Mode Detection Parse `multi_task_mode` from the delegation context. If true, branch to multi-task stages (MT-1 through MT-5) in the **Multi-Task Mode** section below. If false or absent, fall through to Stage 1 (single-task mode). Read from delegation context: - `multi_task_mode` (default: false) - `session_id` - `focus_prompt` (default: "") - `lit_flag` (default: "false") If `multi_task_mode` is true: skip Stages 1-8 entirely and proceed to Stage MT-1. --- ### Stage 1: Input Validation Read from delegation context: - `task_number` (from `task_context.task_number`) - `session_id`, `focus_prompt`, `lit_flag` - `continue_budget` (default: `false`) → `continue_budget_flag`. Defect B: explicit, operator-typed budget-continuation override for an exhausted work-cycle budget, threaded from the command's `--continue-budget` flag. Never inferred from `session_id`, mtime, or any automatic signal. See Stage 2 below for the override mechanism. Resolve from `specs/state.json`: ```bash PADDED_NUM=$(printf "%03d" "$task_number") TASK_DATA=$(jq -r --argjson num "$task_number" \ '.active_projects[] | select(.project_number == $num)' \ specs/state.json) ``` If `TASK_DATA` is empty: exit with error "Task $task_number not found in state.json". Extract: `PROJECT_NAME`, `TASK_TYPE` (default: "general"), `DESCRIPTION`, `TASK_DIR="specs/${PADDED_NUM}_${PROJECT_NAME}"`. Then resolve the absolute anchor that every dispatched agent will be handed. `TASK_DIR` stays relative (many consumers below depend on that); `TASK_DIR_ABS` is the anchor that goes into delegation contexts, because a dispatched agent has no reliable way to know what the ambient working directory will be when its Write tool runs. ```bash # SKILL_REPO_ROOT is exported by skill-base.sh, which resolves it from BASH_SOURCE rather than # from the ambient cwd. $(pwd) is a last-resort fallback for direct invocation. TASK_DIR_ABS="${TASK_DIR_ABS:-${SKILL_REPO_ROOT:-$(pwd)}/${TASK_DIR}}" HANDOFF_PATH_ABS="${TASK_DIR_ABS}/.orchestrator-handoff.json" ``` ### Stage 1b: Resolve Task-Type Routing Map task_type to the correct research, plan, and implementation agents via the single canonical agent resolver, `command-route-agent.sh` — sourced from the shared manifest-routing-lib.sh ladder (the same one `command-route-skill.sh` uses), against each manifest's `routing_agents` declarations. No case table, no directory probe, no sed derivation: agent names are declared data, not derived strings (see `context/guides/manifest-routing-schema.md`). ```bash source .claude/scripts/command-route-agent.sh "research" "$TASK_TYPE" "general-research-agent" "" RESEARCH_AGENT="$AGENT_NAME" source .claude/scripts/command-route-agent.sh "plan" "$TASK_TYPE" "planner-agent" "" PLANNER_AGENT="$AGENT_NAME" source .claude/scripts/command-route-agent.sh "implement" "$TASK_TYPE" "general-implementation-agent" "" IMPLEMENT_AGENT="$AGENT_NAME" echo "[orchestrate] Task type: $TASK_TYPE → research=$RESEARCH_AGENT, plan=$PLANNER_AGENT, implement=$IMPLEMENT_AGENT" ``` ### Stage 2: Loop Guard Initialization Create or read the loop guard file. This tracks cycle count across conversational turns. **Ephemeral, never committed.** `.orchestrator-loop-guard` is per-cycle runtime state with no freshness check on read (see the resume branch below: any syntactically valid guard file at this path is trusted, with no `session_id` or mtime comparison against the current dispatch). A git-restored copy of a stale guard would silently resume a wrong `cycle_count`/`infra_failures` pair — exactly the hazard this file's gitignore coverage exists to prevent. See `context/standards/orchestrator-runtime-files.md` for the full two-class policy and rationale. ```bash MAX_CYCLES=5 # Single shared implementation, orchestrate-loop-guard-init.sh — see that script's header for # the full contract (MAX_INFRA_FAILURES constant, loop_guard_file/handoff_file assignment, # mkdir -p "$TASK_DIR", and the blocker-escalation counter pair applied further below in this # same fence). This is the same call skill-orchestrate-hard/SKILL.md's Stage 2 makes for its own # genuinely-common portion — everything else in this stage (MAX_CYCLES's own value, the # hard-only loop-guard-staleness detector, churn-state init) stays per-engine, either because it # differs or because it sits inside the locked budget-continuation-override region below, which # this script and its call site never touch. loop_guard_init_json=$(bash .claude/scripts/orchestrate-loop-guard-init.sh "$TASK_DIR" "${HANDOFF_PATH_ABS}") loop_guard_file=$(echo "$loop_guard_init_json" | jq -r '.loop_guard_file') handoff_file=$(echo "$loop_guard_init_json" | jq -r '.handoff_file') MAX_INFRA_FAILURES=$(echo "$loop_guard_init_json" | jq -r '.max_infra_failures') # --- budget-continuation-override:begin --- # Defect B: cycle_count is a per-task, CUMULATIVE budget that survives re-invocation BY DESIGN -- # it is deliberately NOT reset on a new session_id, because that would let an operator silently # bypass MAX_CYCLES by simply re-invoking /orchestrate. test-session-runtime-files.sh Case 3 is # the regression protecting this decision; this override must never disturb it. The override # below is the sanctioned, explicit, loudly-logged escape hatch for a genuinely exhausted budget # -- never automatic, never session_id-gated, never inferred from mtime. Verbatim-twin mechanism # to skill-orchestrate-hard/SKILL.md's Stage 2 (base mode has no loop-guard-staleness detector to # sit after, so this runs immediately before the pre-existing resume-read block below). if [ -f "$loop_guard_file" ] && jq empty "$loop_guard_file" 2>/dev/null; then peek_cycle_count=$(jq -r '.cycle_count // 0' "$loop_guard_file") if [ "$peek_cycle_count" -ge "$MAX_CYCLES" ]; then if [ "$continue_budget_flag" = "true" ]; then exhaust_ts=$(date -u +%s) exhausted_guard_dest="${TASK_DIR}/.exhausted-loop-guard-${exhaust_ts}.json" echo "[orchestrate] BUDGET EXHAUSTED (cycle_count=${peek_cycle_count}/${MAX_CYCLES}) — --continue-budget authorized a fresh budget. Archiving exhausted guard to ${exhausted_guard_dest} for auditability, reinitializing at cycle_count=0 with cross-invocation history fields (dispatch_seq_counter, detected_defects) preserved." >&2 if cp "$loop_guard_file" "$exhausted_guard_dest" 2>/dev/null; then # Reinit IN PLACE from the just-archived copy: reset only cycle_count, never wipe # dispatch_seq_counter (must never repeat a value within this task) or detected_defects. jq --arg updated "$(date -u +%Y-%m-%dT%H:%M:%SZ)" '.cycle_count = 0 | .last_updated = $updated' \ "$exhausted_guard_dest" > "${loop_guard_file}.tmp" && mv "${loop_guard_file}.tmp" "$loop_guard_file" else echo "[orchestrate] WARNING: could not archive exhausted guard to ${exhausted_guard_dest}; proceeding without archiving (cycle_count reset in place)." >&2 jq --arg updated "$(date -u +%Y-%m-%dT%H:%M:%SZ)" '.cycle_count = 0 | .last_updated = $updated' \ "$loop_guard_file" > "${loop_guard_file}.tmp" && mv "${loop_guard_file}.tmp" "$loop_guard_file" fi else echo "[orchestrate] ERROR: work-cycle budget exhausted (cycle_count=${peek_cycle_count}/${MAX_CYCLES}). This is a budget limit, not an error condition -- the task's plan may still have incomplete phases." >&2 echo "[orchestrate] To continue this task's work, explicitly authorize a fresh budget: /orchestrate ${task_number} --continue-budget" >&2 exit 1 fi fi fi # --- budget-continuation-override:end --- if [ -f "$loop_guard_file" ] && jq empty "$loop_guard_file" 2>/dev/null; then # Resume: read existing guard. No session_id or mtime check — see the ephemerality note above; # this is precisely why a git-restorable guard would corrupt the cycle budget. cycle_count=$(jq -r '.cycle_count // 0' "$loop_guard_file") infra_failures=$(jq -r '.infra_failures // 0' "$loop_guard_file") # System-defect observation log for this run (contract: Stage MT-1's `detected_defects` # declaration). `// []` is the forward-compatible read for a guard file written before this # field existed, matching the `// 0` idiom above. detected_defects=$(jq -c '.detected_defects // []' "$loop_guard_file") # dispatch_seq_counter: orchestrator-minted per-dispatch identity (Defect A), verbatim-twin # field to skill-orchestrate-hard/SKILL.md's Stage 2. `// 0` forward-compatible read, matching # cycle_count's own idiom — a guard written before this field existed resumes at 0, never # repeating a value already minted this task since the counter only ever increments (see # mint_dispatch_seq() below). dispatch_seq_counter=$(jq -r '.dispatch_seq_counter // 0' "$loop_guard_file") # Observational-only session_id tracking (NEVER a gate — see Ephemeral note above and # context/standards/status-markers.md's rationale: SESSION_ID is regenerated per /orchestrate # invocation, while this guard is explicitly designed to survive across conversational turns. # The real same-task concurrency guard is task-lock.sh's acquire/heartbeat/release mutex, not # session_id equality). A mismatch is logged, never branched on. guard_session_id=$(jq -r '.session_id // ""' "$loop_guard_file") if [ -n "$guard_session_id" ] && [ "$guard_session_id" != "$session_id" ]; then echo "[orchestrate] INFO: loop guard was last written by a different session_id ('${guard_session_id}' vs current '${session_id}') — expected on conversational resume, not gated." fi echo "[orchestrate] Resuming — cycle $cycle_count of $MAX_CYCLES (infra failures: $infra_failures of $MAX_INFRA_FAILURES)" else # Fresh start: create guard atomically via init-marker. A plain # `>` redirect has no O_EXCL semantics, so two racing writers could both take # this branch and stomp each other's counters; init-marker's mkdir-gate + # tmp-mv payload guarantees exactly one winner. On a lost race (exit 1), # degrade to the same resume-read the `if`-branch above performs. if jq -n \ --arg session_id "$session_id" \ --argjson max_cycles "$MAX_CYCLES" \ --argjson max_infra_failures "$MAX_INFRA_FAILURES" \ --arg started "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ '{ "session_id": $session_id, "cycle_count": 0, "max_cycles": $max_cycles, "infra_failures": 0, "max_infra_failures": $max_infra_failures, "current_state": "reading", "detected_defects": [], "started": $started, "last_updated": $started, "dispatch_seq_counter": 0 }' | bash .claude/scripts/task-lock.sh init-marker "$loop_guard_file"; then cycle_count=0 infra_failures=0 detected_defects='[]' dispatch_seq_counter=0 echo "[orchestrate] Starting fresh — MAX_CYCLES=$MAX_CYCLES, MAX_INFRA_FAILURES=$MAX_INFRA_FAILURES" else # Lost the creation race: another writer won. Resume from their guard, reading BOTH # counters — not just cycle_count — and the system-defect observation log alongside them. cycle_count=$(jq -r '.cycle_count // 0' "$loop_guard_file") infra_failures=$(jq -r '.infra_failures // 0' "$loop_guard_file") detected_defects=$(jq -c '.detected_defects // []' "$loop_guard_file") dispatch_seq_counter=$(jq -r '.dispatch_seq_counter // 0' "$loop_guard_file") echo "[orchestrate] Resuming (lost init race) — cycle $cycle_count of $MAX_CYCLES (infra failures: $infra_failures of $MAX_INFRA_FAILURES)" fi fi # mint_dispatch_seq(): named-shim to the single shared implementation, # skill_orchestrate_mint_dispatch_seq (scripts/skill-base.sh) — see that function's header for the # full contract. Kept as a locally-named function (not called directly by name) because Stage 4/5 # call sites below still say `mint_dispatch_seq`, and this file pair is where a one-sided rename # is a known recurring defect class. Source is defensive/idempotent: this Stage 2 fence has no # earlier explicit source line of its own to depend on. source .claude/scripts/skill-base.sh mint_dispatch_seq() { skill_orchestrate_mint_dispatch_seq "$loop_guard_file" } # Blocker escalation counter (reset each /orchestrate invocation) — from the same shared # orchestrate-loop-guard-init.sh call above. blocker_escalation_count=$(echo "$loop_guard_init_json" | jq -r '.blocker_escalation_count') MAX_BLOCKER_ESCALATIONS=$(echo "$loop_guard_init_json" | jq -r '.max_blocker_escalations') # Drift detection constants (reset each /orchestrate invocation) — base-mode-only; hard mode has # no Stage 5a Drift Inspection equivalent (its own H5 divergence-audit mechanism plays that role # instead), so these stay out of the shared script. drift_inspection_count=0 MAX_DRIFT_INSPECTIONS=1 DRIFT_COMPLETION_THRESHOLD=0.70
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub