blamechris

/autonomous-dev-flow

"Orchestrate long-running autonomous dev sessions — work through GitHub issues sequentially with TDD, create PRs, run /full-review, then merge or flag..."

blamechris 7 1 Updated 4w ago
GitHub

Install

npx skillscat add blamechris/chroxy/claude-skills-autonomous-dev-flow

Install via the SkillsCat registry.

SKILL.md

/autonomous-dev-flow

Orchestrate long-running autonomous dev sessions — work through GitHub issues sequentially with TDD, create PRs, run /full-review, then merge or flag according to this repo's self-merge posture, and continue to the next issue. PRs that don't merge accumulate for asynchronous user review while work continues.

Arguments

  • $ARGUMENTS - Issue source and options. Examples:
    • label:ready-to-build (all open issues with this label)
    • milestone:"v1.2" (all open issues in milestone)
    • #12 #15 #18 or 12 15 18 (specific issues by number)
    • label:ready-to-build max:5 sort:created-asc (with options)
    • If empty, auto-detect: scan open issues sorted by complexity (low first, then medium, skip high)
    • Options: max:N (default 10, hard cap 15), sort:created-asc (default) or sort:created-desc

Instructions

Phase 0: Queue Setup

# Branch prefix for autonomous session branches
BRANCH_PREFIX="feat/"

Parse $ARGUMENTS to determine the issue source:

  • Explicit list: Strip # prefixes, run gh issue view ${NUM} --json number,title,state,labels,body,assignees for each
  • Label: gh issue list --label "${LABEL}" --state open --json number,title,labels,assignees --limit ${MAX}
  • Milestone: gh issue list --milestone "${MILESTONE}" --state open --json number,title,labels,assignees --limit ${MAX}
  • Auto-detect (empty args): gh issue list --state open --json number,title,labels,assignees --limit 30 then sort by complexity label (low first, then medium, skip high)

Apply sort order and cap to max (hard cap 15 — sessions beyond this rarely maintain quality). Recommended: 3-5 issues for first use; sessions of 10+ work best with well-specified, low-complexity issues.

Filter out assigned issues — exclude issues with assignees from the working queue. Show them in the queue table as informational but don't process them.

Validate the queue before starting:

  • At least 1 issue must be open and unassigned
  • If all matching issues are assigned, report "All N matching issues are assigned — nothing to process" and stop
  • If 0 issues match, report and stop — don't start an empty session
  • Show the user the queue and get confirmation before entering the loop
## Work Queue ({N} issues, {M} skipped as assigned)

| # | Issue | Labels | Action |
|---|-------|--------|--------|
| 1 | #12 — Add retry logic to API client | enhancement | Implement |
| 2 | #15 — Add leaderboard system | complexity:high | Decompose → sub-issues |
| — | #16 — Refactor auth module | enhancement | Assigned to @user (skipped) |
| 3 | #18 — Add integration tests for auth flow | testing | Implement |

Start autonomous dev session?

Wait for user confirmation. This is the ONLY confirmation point — everything after runs autonomously.

After confirmation, create task list tracking:

For each issue in work queue:
  TaskCreate: "Issue #N — <title>" with status pending

Phase 0.5: Auto-Decompose High-Complexity Issues

When the queue contains issues that are too large to implement directly (e.g., issues spanning multiple systems or touching 3+ files), decompose them into smaller, independently implementable sub-issues BEFORE entering the core loop.

For each high-complexity issue:

  1. Check for prior decomposition — scan the issue's comments for an existing "Decomposed into #A, #B, #C" comment. If found, use those existing sub-issues instead of creating new ones.
  2. Read the full issue body: gh issue view ${ISSUE_NUM} --json body,comments -q .
  3. Understand the full scope — files involved, systems affected, testing needs
  4. Break into 2-5 sub-issues, each low or medium complexity
  5. Create sub-issues via gh issue create:
SUB_URL=$(gh issue create \
  --title "type(scope): Sub-task description" \
  --label "enhancement" \
  --body "$(cat <<'EOF'
## Summary

Specific sub-task description.

Part of #${ISSUE_NUM}

## Implementation Plan

- Files to modify: `src/path/to/file`
- Test strategy: Add tests for X behavior
- Approach: [specific implementation details]

## Acceptance Criteria

- [ ] Criterion 1
- [ ] Criterion 2
EOF
)")

SUB_NUM=$(basename "$SUB_URL")
  1. Insert sub-issues at FRONT of queue (context is fresh from reading the parent)
  2. Comment on parent issue: gh issue comment ${ISSUE_NUM} --body "Decomposed into #A, #B, #C — each independently implementable with TDD."
  3. Parent stays open until all sub-issues merge — do NOT close it
  4. After decomposition, if the total queue exceeds 15, truncate to 15 with a message: "Queue expanded to N issues after decomposition. Processing first 15."

Skip criteria — auto-skip these issues (log reason in progress table):

  • Empty issue body or no identifiable acceptance criteria — needs requirements before implementation
  • No code path (manual testing, design docs, decisions needed)
  • Requires user input not present in the description
  • Deployment/release tasks
  • Issues labeled blocked or wontfix
  • Issues requiring design decisions with multiple valid approaches not specified

If skipping, comment on the issue:

gh issue comment ${ISSUE_NUM} --body "Skipped during autonomous dev session — [reason]. Needs manual attention."

Phase 1: Sync Check (before EACH issue)

git checkout main
git pull origin main

Check for any PRs merged by the user since last check:

gh pr list --state merged --json number,headRefName,mergedAt --limit 20 \
  | jq --arg prefix "${BRANCH_PREFIX}" '[.[] | select(.headRefName | startswith($prefix))]'

Note any merged PRs in the progress table. If on a stale branch, switch back to main.

Check for existing branches/PRs from a previous session for the current issue:

# Check if issue already has a PR (search by title reference)
gh pr list --json number,title,headRefName,state --limit 50 \
  | jq --arg num "${ISSUE_NUM}" '[.[] | select(.title | contains("#" + $num))]'

# Also check by branch prefix
gh pr list --json number,title,headRefName,state --limit 50 \
  | jq --arg prefix "${BRANCH_PREFIX}" '[.[] | select(.headRefName | startswith($prefix))]'
  • Already merged → mark as done, skip
  • Open PR exists → skip (user can re-queue if needed)
  • Stale branch, no PR → delete branch, re-process

Phase 2: Issue Understanding

gh issue view ${ISSUE_NUM} --json title,body,labels,comments

Read the full issue. Identify:

  • Files to modify — use Glob/Grep to find relevant code
  • Test strategy — what behavior to test, where tests go
  • Implementation approach — minimal path to satisfy acceptance criteria

Explore the codebase to understand the relevant code before writing anything:

# Read CLAUDE.md for project conventions
cat CLAUDE.md 2>/dev/null

# Explore relevant files based on issue description

If the issue body is empty or has no actionable requirements, apply skip criteria from Phase 0.5.

Phase 3: Implementation (TDD)

Create branch following project conventions:

# Generate slug from issue title: lowercase, hyphens, no special chars, max 40 chars
ISSUE_TITLE=$(gh issue view "${ISSUE_NUM}" --json title -q '.title')
SLUG=$(printf '%s' "${ISSUE_TITLE}" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/-/g; s/^-+|-+$//g' | cut -c1-40)

# Create branch from issue number + slug
BRANCH="${BRANCH_PREFIX}${ISSUE_NUM}-${SLUG}"
git checkout -b "${BRANCH}"

CRITICAL: Always branch from main. Never stack branches — each PR must be independently mergeable in any order.

RED — Write Failing Tests First

Based on the issue's acceptance criteria, write tests that describe the desired behavior. Tests MUST fail before any implementation.

# Server: cd packages/server && npm test
# App: cd packages/app && npx jest
# Dashboard: cd packages/server && npm run dashboard:test

# Run tests to confirm they fail
${TEST_COMMAND}

If tests pass immediately, the behavior already exists — investigate before proceeding. Either the issue is already resolved or the tests don't capture the right behavior.

GREEN — Make Tests Pass

Write the minimum implementation to make all new tests pass. Don't over-engineer — just satisfy the tests.

# Run tests to confirm they pass
${TEST_COMMAND}

If tests still fail, iterate on the implementation until they pass. Do NOT move to REFACTOR until all tests are green.

REFACTOR — Clean Up

With green tests as a safety net:

  • Remove duplication
  • Improve naming
  • Simplify logic
  • Ensure the code follows project conventions (per CLAUDE.md)
# Run tests again to confirm refactoring didn't break anything
${TEST_COMMAND}

# App: cd packages/app && npx tsc --noEmit
# Dashboard: cd packages/server && npm run dashboard:typecheck
${LINT_COMMAND}

Phase 4: Commit and PR Creation

Stage and commit with conventional format:

# Stage relevant files (never git add -A)
git add <specific-files>

# Commit with issue reference — NO attribution
git commit -m "$(cat <<'EOF'
type(scope): description

Implements the core change described in the issue.

Refs #${ISSUE_NUM}
EOF
)"

# Commit scope conventions: server, app, desktop, tunnel, ws, cli, ci, docs, dashboard

git push -u origin ${BRANCH}

Create PR autonomously (NO user confirmation — PRs are the async checkpoints):

# Construct PR title: conventional commit format referencing the issue
# Infer type from issue labels (bug→fix, enhancement→feat, etc.)
ISSUE_LABELS=$(gh issue view "${ISSUE_NUM}" --json labels -q '[.labels[].name] | join(",")')
case "${ISSUE_LABELS}" in
  *bug*) PR_TYPE="fix" ;;
  *test*) PR_TYPE="test" ;;
  *refactor*) PR_TYPE="refactor" ;;
  *) PR_TYPE="feat" ;;
esac
PR_TITLE="${PR_TYPE}: ${ISSUE_TITLE} (#${ISSUE_NUM})"

PR_URL=$(gh pr create \
  --title "${PR_TITLE}" \
  --body "$(cat <<'EOF'
## Summary

- Change 1
- Change 2

Refs #${ISSUE_NUM}

## Test Plan

- [ ] Server tests pass
- [ ] App type-checks clean
- [ ] Dashboard tests pass
- [ ] Manual smoke test
EOF
)")

PR_NUM=$(echo "$PR_URL" | grep -oE '[0-9]+$')

Phase 4.5: Smoke Test (if applicable)

If the PR modified dashboard or UI files, run the project's smoke test to catch visual regressions before review. This prevents wasting review cycles on PRs that break the UI.

# Condition for when to run smoke test
CHANGED_FILES=$(git diff --name-only main...HEAD)
if echo "$CHANGED_FILES" | grep -qE 'dashboard-next|\.tsx$|\.css$|\.html$|components\.css|theme'; then
  NEEDS_SMOKE_TEST=true
fi

If NEEDS_SMOKE_TEST is true:

  1. Rebuild dashboard if needed:
    PATH="/opt/homebrew/opt/node@22/bin:$PATH" npm run build -w @chroxy/dashboard
  2. Run /smoke-test — this launches the app, opens a headless browser, and verifies key UI elements
  3. Check results:
    • All pass: Continue to Phase 5 (review)
    • Failures: Read the screenshots, diagnose whether it's an app bug or a test selector issue
      • App bug: Fix the code, re-run tests, amend commit, re-run smoke test
      • Test issue: Note it in the PR description, continue (don't block on flaky test selectors)
  4. Max 2 smoke test fix attempts — if still failing after 2 fixes, flag the PR as "Needs attention (smoke test failure)" and move on

If NEEDS_SMOKE_TEST is false, skip directly to Phase 5.

CRITICAL: The smoke test must NOT send real messages or create persistent state. It only verifies UI rendering and navigation.

Phase 5: Full Review

Pre-Skill Checkpoint (MANDATORY — prevents context drift in long sessions):

  1. Re-read CLAUDE.md for project conventions
  2. Re-read the skill files for /full-review, /agent-review, and /check-pr

Run /full-review ${PR_NUM}:

  • Phase 1: Agent review — deep expert review against project standards
  • Phase 2: Check-PR — process all review comments (Copilot + agent-review findings)

Capture results: verdict, findings counts, fixes committed, issues created/closed.

If critical findings exist: Fix them (standard /full-review behavior handles this). Two fix attempts max — after that, flag the PR as "Needs attention" and move on.

Merge — or don't — exactly as Critical Rule 5 directs. Rule 5 records whether this repo grants unattended merge authority at all; it is the only place that decides, and nothing here overrides it. If rule 5 grants gated self-merge: when the verdict is clean, ALL CI checks pass on the final commit, and ALL review threads are resolved, merge per repo convention (see unattended-merge), verify the PR reports MERGED, and record the merge as an entry in the final session report. NEVER use gh pr merge --auto or GitHub auto-merge — verify the gates first, then merge synchronously. If any gate fails, do NOT merge: flag the PR for the user with the failed gate named and keep working. If rule 5 withholds merge authority, leave the PR open and flag it — a clean review is not a reason to revisit that.

Phase 6: Assess, Report, and Continue

Based on /full-review results, classify the PR:

Verdict Meaning Action
Clean No critical findings, all comments addressed Edit PR body: Refs → Closes. Then follow Critical Rule 5: if this repo grants gated self-merge, merge and record the entry; if it withholds merge authority, flag the PR and leave it open. Mark the issue done, continue
Needs attention Critical findings or unresolved comments Keep Refs (don't auto-close). Flag for user, continue
Broken Tests failing after review fixes Keep Refs (don't auto-close). Flag for user, continue

Update task tracking:

TaskUpdate: "Issue #N" → completed (or flagged)

Output cumulative progress table:

## Session Progress ({completed}/{total})

| # | Issue | Branch | PR | Smoke | Review | Status |
|---|-------|--------|----|-------|--------|--------|
| 1 | #12 — Add retry logic | 12-add-retry | #45 | — | Approve (0 critical) | Done |
| 2 | #15 — Add leaderboard | — | — | — | — | Decomposed → #20, #21 |
| 3 | #20 — Leaderboard data model | 20-lb-model | #46 | 12/13 | Approve (1 suggestion) | Done |
| 4 | #18 — Add auth tests | — | — | — | — | In progress |
| 5 | #22 — Update error handling | — | — | — | — | Queued |

CRITICAL: Never block the session on a flagged PR. Flag and move on. The user handles flagged PRs during check-ins.

Return to Phase 1 for next issue.

Phase 7: Session Summary

After all issues are processed (or the queue is exhausted), output final summary:

## Autonomous Dev Session Complete

**Issues processed:** {N}
**Queue source:** {description}

### Results

| # | Issue | PR | Smoke | Review Verdict | Status |
|---|-------|----|-------|---------------|--------|
| 1 | #12 — Add retry logic | [#45](url) | — | Approve | Merged (`abc1234`) |
| 2 | #15 — Add leaderboard | — | — | — | Decomposed → #20, #21, #22 |
| 3 | #20 — Leaderboard data model | [#46](url) | 12/13 | Approve | Merged (`def5678`) |
| 4 | #18 — Add auth tests | [#47](url) | — | Request Changes | Needs attention |

### Merged by this session

One entry per self-merged PR — MANDATORY (Unattended Merge Gate rule 6). Omit this whole section when Critical Rule 5 withholds merge authority for this repo: there is nothing to report, and an empty "Merged by this session" table invites the reader to assume a merge happened:

| PR | Issue | Review | Checks | Merge SHA |
|----|-------|--------|--------|-----------|
| [#45](url) | #12 — Add retry logic | Approve, 0 unresolved | all green | `abc1234` |
| [#46](url) | #20 — Leaderboard data model | Approve, 0 unresolved | all green | `def5678` |

### Summary
- **Merged this session:** N PRs (entries above)
- **Open / needs attention:** M PRs (details below)
- **Decomposed:** K issues → L sub-issues created
- **Skipped:** J issues (reasons below)
- **Issues created during reviews:** #A, #B, #C
- **PRs merged by user during session:** #X, #Y

### Needs Attention
- **PR #47** (#18 — Add auth tests): 1 critical finding — auth token not validated before use. See review comment.

### Skipped Issues
- **#25**: Requires deployment setup — not automatable
- **#30**: Needs user decision on provider choice

### Next Steps
- Review the merged-PR entries (post-merge audit)
- Address flagged PRs (each names its failed gate)
- Review created issues for follow-up work

Session Boundaries

Long autonomous runs are a sequence of bounded sessions, not one endless context — context re-reads dominate their cost, and a restart that halves context pays for itself within ~6–10 requests. When this skill runs inside a marathon (/tackle-issues), the wave boundary is the session boundary; run standalone, apply the same discipline at wave boundaries of its own (queue checkpoints — every few issues, and always before starting a large one). How a session ends at a wave boundary is mode-aware:

  • Attended runs — end the session at the wave boundary; the user/orchestrator relaunches the next segment seeded from the handoff note ($CLAUDE_BRIEF_DIR/../handoffs/chroxy-<date>-handoff.md) + the queue (scratchpad/autonomous-queue.json).

  • Unattended with a configured re-launcher (none configured for this repo yet) — end the session; the re-launcher starts the next segment from the same seeds.

  • Unattended with no re-launcher — do NOT end the session (nothing would relaunch it): write the handoff seed, force/await a compaction at the boundary so the next segment starts lean, and continue. The cost goal — shed context at the boundary — holds in every mode.

  • ~150K main-thread context ceiling. Past ~150K tokens of main-thread context, finish the current issue only, write the short handoff note (queue position, open blockers, awaiting-user items, last verified merge), and end the session (unattended with no re-launcher: force a compaction instead). Resume Strategy below makes the fresh session lossless — it re-derives progress from GitHub state, so the handoff plus the queue is all the seed a restart needs.

  • Cost circuit breaker at wave boundaries (queue checkpoints) — PAUSED, track-only. The per-session budget is none: paused 2026-09-24 by the user while the restriction policy is re-evaluated (.claude/skill-profile.md, Cost Circuit Breaker). At each boundary, still record this session's spend in the STATE header and the wave's log entry — python3 ~/.claude/scripts/usage-benchmark-row.py (this session's eff units, subagent share, work credited; print-only mid-session — the row is appended once, at session end) and python3 ~/.claude/scripts/usage-pace.py --oneline (the live weekly meter); while paused, never stop on spend. If a budget is reinstated there: over budget → write the handoff and stop and notify instead of continuing. This breaker is the sole sanctioned exception to Critical Rule 4's "everything after is fully autonomous".

  • Verify state directly. A background monitor ending is not a verdict — assert PR/CI state with a direct query before recording it, and re-check mergeStateStatus at the current head after any push.

Resume Strategy

This skill resumes from GitHub state — GitHub remains the source of truth for issue/PR status. The wave handoff note (Session Boundaries) carries only session-boundary seeds — queue position, open blockers, awaiting-user items, last verified merge — and is disposable: everything in it is re-derivable from GitHub. It is a seed for the next segment, not a second source of truth.

If a session is interrupted (crash, timeout, user stops it), re-running with the same arguments will:

  1. Query GitHub for existing session branches (matching BRANCH_PREFIX) and PRs referencing each issue
  2. Skip issues that already have merged or open PRs
  3. Resume from the first issue without a PR

This makes the skill idempotent — safe to re-run without duplicating work. The same idempotence is what makes deliberate session-boundary restarts (above) lossless.

Critical Rules

  1. NO attribution — No Co-Authored-By, no "Generated with Claude", no AI mentions anywhere. Zero Attribution Policy.
  2. TDD is mandatory — RED → GREEN → REFACTOR for every issue. No skipping tests. If pure docs/config, note why tests are N/A.
  3. Branch from main every time — Never stack branches. Each PR is independently mergeable in any order.
  4. One confirmation point — The initial queue approval. Everything after is fully autonomous; the sole sanctioned stop is the cost circuit breaker, which is currently paused (track-only — see Session Boundaries).
  5. Self-merge authority for this repo — Merge only through the Unattended Merge Gate — /full-review clean + ALL checks green on the final commit + ALL review threads resolved. No gh pr merge --auto, no GitHub auto-merge, no protection overrides. A failed gate means flag, don't merge. Every self-merged PR MUST appear as an entry in the final session report.
  6. Never block on review findings — Flag and move on. The user handles flagged PRs during check-ins.
  7. Two fix attempts max — If /full-review finds critical issues, fix them. If a second attempt still fails, flag and move on.
  8. Progress table after every issue — The user may check in at any time. The table must be current.
  9. Respect the hard cap — Max 15 issues per session segment (wave). Refuse larger queues.
  10. Resume from GitHub state — GitHub is the source of truth for issue/PR status; query branches matching BRANCH_PREFIX and PR titles to detect prior work. The wave handoff note is a disposable session-boundary seed, never a second source of truth.
  11. Compose existing skills — /full-review is called as-is (chains /agent-review → /check-pr). Don't reinvent their logic.
  12. Decompose, don't skip — High-complexity issues get broken into sub-issues, not skipped. Only skip truly non-automatable work.
  13. Comment on skips — Every skipped issue gets a GitHub comment explaining why. The user sees the reason.
  14. Pre-Skill Checkpoint — Re-read CLAUDE.md and skill files before running /full-review to prevent context drift.
  15. Sync before branching — Always git checkout main && git pull before starting each issue. Check for merged PRs first.