adopt
Bootstrap an existing repo for ForgeDock — triage open issues, apply labels, suggest a starter milestone, and identify first…
Scan for pipeline-orphaned issues stuck in intermediate workflow states and recover them — diagnose each orphan's actual GitHub state, apply recovery actions, clean up worktrees
> /plugin marketplace add RapierCraftStudios/ForgeDock > /plugin install forgedock@forgedock
How it fires
How this command gets triggered: by you, by Claude, or both.
/recover-orphansContext preview
What this command does when you run it.
Scan for pipeline-orphaned issues stuck in intermediate workflow states and recover them — diagnose each orphan's actual GitHub state, apply recovery actions, clean up worktrees
description: Scan for pipeline-orphaned issues stuck in intermediate workflow states and recover them — diagnose each orphan's actual GitHub state, apply recovery actions, clean up worktrees argument-hint: "[--dry-run | --since <hours> | --issue <number>]"
<!-- SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios --> <!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
> **Skill names**: `{FORGE_SKILL_PREFIX}` is `forgedock:` (plugin install) or empty (`install.sh`), resolved once per run by `commands/work-on.md` § Skill Name Resolution. If the skill is not found under either name, STOP and report "skill not found" — never run the phase inline.
**Input**: $ARGUMENTS
Scan ALL open issues with intermediate workflow labels for orphaned state — issues where the agent died mid-pipeline (context expired, rate-limited, crashed) and no active agent is continuing. Diagnose each orphan's actual GitHub state and apply the appropriate recovery action.
**Agent model policy**: `model: "{DEFAULT_MODEL}"` — resolved from forge.yaml `agents.default_model`, else "sonnet". Fallback: `model: "opus"` if rate-limited. **NEVER use plan mode (EnterPlanMode).** **NEVER use the Agent tool** — recover-orphans re-enters the pipeline via `Skill(skill="{FORGE_SKILL_PREFIX}work-on", ...)` and `Skill(skill="{FORGE_SKILL_PREFIX}review-pr", ...)` only.
<!-- FORGE:SPEC_LOADED — recover-orphans.md loaded and active. Agent is bound by this spec. -->
---
Read `forge.yaml` at the project root before running any commands:
CONFIG_FILE="${FORGE_CONFIG:-forge.yaml}"
GH_REPO=$(yq '.project.owner + "/" + .project.repo' "$CONFIG_FILE")
GH_FLAG="-R $GH_REPO"
REPO_PATH=$(yq '.paths.root' "$CONFIG_FILE")
WORKTREE_BASE=$(yq '.paths.worktree_base' "$CONFIG_FILE")
STAGING_BRANCH=$(yq '.branches.staging' "$CONFIG_FILE")If `forge.yaml` is missing: stop and tell the user to run `npx forgedock init` to generate it.
---
DRY_RUN=false
SINCE_HOURS=""
TARGET_ISSUE=""
# Parse flags
for arg in $ARGUMENTS; do
case "$arg" in
--dry-run) DRY_RUN=true ;;
--since) : ;; # value follows
--issue) : ;; # value follows
esac
done
# Parse --since <hours> and --issue <number> (value follows flag)
PREV=""
for arg in $ARGUMENTS; do
if [ "$PREV" = "--since" ]; then
SINCE_HOURS="$arg"
elif [ "$PREV" = "--issue" ]; then
TARGET_ISSUE="$arg"
fi
PREV="$arg"
done
echo "=== /recover-orphans: $(date -u +%Y-%m-%dT%H:%M:%SZ) ==="
echo "DRY_RUN=$DRY_RUN | SINCE_HOURS=${SINCE_HOURS:-all} | TARGET_ISSUE=${TARGET_ISSUE:-all}"| Flag | Effect | |------|--------| | (none) | Scan all intermediate-state open issues | | `--dry-run` | Report-only — print what would be done, no mutations | | `--since <hours>` | Only scan issues not updated in the last N hours (default: all) | | `--issue <number>` | Recover a single specific issue |
---
**Note**: `gh issue list --label` uses AND semantics when multiple labels are given. To find issues with ANY intermediate workflow label, query each label separately and merge results.
# Compute stale cutoff if --since was provided
CUTOFF=""
if [ -n "$SINCE_HOURS" ]; then
CUTOFF=$(python3 -c "
from datetime import datetime, timedelta, timezone
h = int('$SINCE_HOURS')
print((datetime.now(timezone.utc) - timedelta(hours=h)).strftime('%Y-%m-%dT%H:%M:%SZ'))
" 2>/dev/null || echo "")
fi
if [ -n "$TARGET_ISSUE" ]; then
# Single-issue mode
ORPHAN_LIST="$TARGET_ISSUE"
echo "Single-issue mode: targeting #$TARGET_ISSUE"
else
# Fleet scan: query each workflow label separately, merge, deduplicate
ORPHAN_JSON=$(
for LABEL in "workflow:investigating" "workflow:ready-to-build" "workflow:building" "workflow:in-review" "workflow:remediating"; do
gh issue list ${GH_FLAG} \
--state open \
--label "$LABEL" \
--limit 100 \
--json number,title,labels,updatedAt
done | jq -s '
flatten |
unique_by(.number) |
sort_by(.updatedAt) | reverse |
.[]
')
# Apply --since filter if specified
if [ -n "$CUTOFF" ]; then
ORPHAN_JSON=$(echo "$ORPHAN_JSON" | jq -s --arg cutoff "$CUTOFF" '
[.[] | select(.updatedAt < $cutoff)] | .[]
')
fi
ORPHAN_LIST=$(echo "$ORPHAN_JSON" | jq -r '.number' | sort -un)
fi
ORPHAN_COUNT=$(echo "$ORPHAN_LIST" | grep -c '[0-9]' 2>/dev/null || echo 0)
echo "Orphan candidates found: $ORPHAN_COUNT"If `ORPHAN_COUNT` is 0: print `No orphaned issues found — pipeline is clean.` and STOP.
---
For each issue number in `ORPHAN_LIST`, run the full diagnostic and determine the recovery action.
# Diagnosis result arrays (accumulated for Phase 3 and Phase 5 report)
declare -A DIAG_ACTION # issue_num -> action name
declare -A DIAG_REASON # issue_num -> human-readable reason
declare -A DIAG_PR_NUM # issue_num -> associated PR number (if any)
declare -A DIAG_BRANCH # issue_num -> associated branch (if any)
for NUM in $ORPHAN_LIST; do
echo ""
echo "--- Diagnosing #$NUM ---"
# Read current issue state
ISSUE=$(gh issue view "$NUM" ${GH_FLAG} \
--json number,title,labels,state,updatedAt,body 2>/dev/null)
if [ -z "$ISSUE" ]; then
echo "#$NUM: Could not fetch — skipping"
continue
fi
ISSUE_STATE=$(echo "$ISSUE" | jq -r '.state')
ISSUE_TITLE=$(echo "$ISSUE" | jq -r '.title')
ISSUE_LABELS=$(echo "$ISSUE" | jq -r '[.labels[].name] | join(", ")')
WORKFLOW_LABEL=$(echo "$ISSUE" | jq -r '[.labels[].name | select(startswith("workflow:"))] | first // "none"')
echo "#$NUM: $ISSUE_TITLE"
echo " State: $ISSUE_STATE | Labels: $ISSUE_LABELS"
# Skip if already in terminal state (race condition: label changed since query)
if [ "$ISSUE_STATE" = "CLOSED" ]; then
DIAG_ACTION[$NUM]="skip"
DIAG_REASON[$NUM]="Issue already closed"
continue
fi
if echoForgeDock — autonomous AI dev pipeline for Claude Code. GitHub as agent memory: issue in, PR out.
Bootstrap an existing repo for ForgeDock — triage open issues, apply labels, suggest a starter milestone, and identify first…
Pull production analytics from GSC, Bing Webmaster, Clarity, Umami, Cloudflare, Stripe, and GA4 — generate insights and create…
Audit agent outputs from an orchestration run — timeline analysis, stall detection, active vs idle time breakdown
Trace a production issue or pipeline failure end-to-end through GitHub artifacts, then file a detailed improvement issue to the…
Autonomous deploy loop — runs until zero open issues remain. Detects pipeline state and resumes from any position. Fully…
Guided idea-to-backlog setup for a brand-new project — interview, defaults, doubts, spike doc, validated orchestrate-ready backlog