Skip to content

T-FQCN-self-driving-orchestrator-loop

Status: closed/done · Impact: high · Complexity: large

Formerly epic E0001 — retired into a parent Task per D-ORMG-data-model; all member tasks shipped, children link up via parent_key.

Stand up a hands-off orchestrator that drives the existing SDLC loop end-to-end: pull origin/main, reconcile worktree/PR state, dispatch ready tasks into /sdlc:task-work sub-agents (parallelism cap 2), shepherd open PRs through review/conflict/CI signals, and run Step 11 close-out the moment a PR merges. The deliverable boundary is “a single command — /loop /sdlc:orchestrate — keeps the project moving without manual scheduling for as long as the Claude Code session stays open.” All member tasks need to land together for that boundary to be real; without pr-check the loop can’t react to merged/conflicted PRs, and without task-close-out the loop accumulates dead worktrees on every merge.

The SDLC loop exists but is human-driven at every junction:

  • 3 tasks sit in status: ready (2026-05-17-add-astro-docs-site, 2026-05-19-add-update-skill-doc-skill, 2026-05-19-document-every-skill-with-mermaid-flowchart); none have readiness_verified_at stamped — a human has to invoke /sdlc:task-work (or /sdlc:task-ensure-ready) on each.
  • .claude/worktrees/ carries 10 active worktrees; at least one (2026-05-19-add-epic-entity-task-depends-on-dependencies) is post-merge but Step 11 close-out never ran, so it shows status: in-progress despite PR #18 being merged. Drift compounds with every merge.
  • PR triage is fully manual — there’s no skill that says “this PR has a merge conflict / new review comment / failed CI; here’s what to do.” Open PRs #21–#24 are waiting on human attention with no automated signal.
  • /sdlc:task-work’s Step 11 (mark closed/done, tear down worktree, delete branches) is documented to fire “when the user reports the merge or you notice it later.” There is no callable entry point for it — it’s prose inside a 13-step skill body.
  • Origin/main sync is ad-hoc. Local main was 5 commits behind origin when this epic was drafted (PRs #17–#20 already merged remotely).

A three-phase rollout, with this epic owning Phase 1:

Phase 1 — Foreground MVP (this epic’s tasks): /sdlc:orchestrate is the tick loop, driven by /loop /sdlc:orchestrate (self-paced via ScheduleWakeup). Per tick: fetch origin/main and rebase; classify every open PR via /sdlc:pr-check and dispatch sub-agents to either respond to comments, rebase to resolve conflicts, or invoke /sdlc:task-close-out for merges; then dispatch up to 2 new /sdlc:task-work sub-agents on ready tasks (after gating each through /sdlc:task-ensure-ready). Blockers are not interrupts — in-progress/blocked and proposed/needs-definition statuses naturally exclude tasks from the dispatch query, so the loop continues. The orchestrator writes a per-tick digest line to a log file so the user can scan what happened while away. PushNotification is reserved for state the loop genuinely can’t resolve on its own (e.g., a PR with conflicts the sub-agent couldn’t resolve, or all ready tasks gated on human-only work). Sub-agents are dispatched via Agent (not direct Skill invocation) so per-task work stays out of the parent’s context — the parent only sees one-line return verdicts.

Phase 2 — Cross-session durability (future, out of scope here): Move the tick from /loop (session-bound) to either CronCreate with durable: true or a dedicated claude --bg session driven by a Stop-hook re-injection (the /ralph-loop pattern). Both keep the local-git architecture intact and just remove the “must keep CC open” constraint. Phase 1 deliberately doesn’t pick between them — we’ll choose after running Phase 1 long enough to see where context rot, idle-timeout, and reliability actually bite.

Phase 3 — Standalone daemon (future, out of scope here): Extract /sdlc:orchestrate’s logic to a Python process using the Anthropic Agent SDK. Cron / launchd / systemd drives the cadence. Per-task work continues to shell out to claude --print "/sdlc:task-work <slug>" so we don’t rebuild the SDLC skills. Phase 1’s skill body becomes the spec.

Frontmatter tasks: is canonical; this section adds the prose for why each lives here.

  • T-3OVF-add-orchestrate-skill — the tick loop itself. Defines reconciliation order (pull → PR shepherding → ready-task dispatch), parallelism cap (2), blocker policy (skip + log, don’t notify), and the digest-log convention. Depends on pr-check and task-close-out existing because it dispatches to both.
  • T-8896-add-pr-check-skill — single-PR classifier that orchestrate calls per open PR. Returns one of {CLEAN, NEEDS-RESPONSE, CONFLICTS, CI-FAILED, MERGED} plus a one-line reason. Tight return contract is the whole point — keeps orchestrator parent context small.
  • T-RDKI-extract-task-close-out-skill — pulls Step 11 of /sdlc:task-work (mark closed/done, drop relevance_note, clear readiness_verified_at, add completion_note, tear down worktree, delete branches) into a standalone /sdlc:task-close-out skill. Orchestrator invokes it on pr-check → MERGED; task-work keeps its existing Step 11 prose but delegates to the new skill so behavior stays in one place.

These are outcomes of the bundle, not the sum of member-task ACs:

  • AC-E1: After running /loop /sdlc:orchestrate overnight against the current repo state (10 active worktrees, 4 open PRs, 3 unverified ready tasks), the loop converges: merged-PR worktrees torn down with their tasks closed/done; ready tasks either picked up (PRs opened) or downshifted to proposed/needs-definition with definition_gap recorded; no human intervention required for the convergence steps the loop is designed to handle.
  • AC-E2: Blockers don’t stop the loop. A task that hits /sdlc:task-work Step 12 (failure → in-progress/blocked) or /sdlc:task-ensure-ready rejection (→ proposed/needs-definition) is skipped on the next tick without notification. Blocker reason is captured in the task’s own frontmatter/body (existing <blocked> and definition_gap fields) plus a line in the orchestrator’s digest log.
  • AC-E3: The orchestrator’s parent context grows roughly linearly with ticks, not with work done per tick. Empirically: a tick that dispatches 2 task-work sub-agents adds <2k tokens to the parent transcript (one-line returns + minimal git status output), not the 30-100k of a full task-work run.
  • AC-E4: PR shepherding works without the user looking at GitHub. Merge conflicts, new review comments, and CI failures each surface a sub-agent attempt; if the sub-agent can’t resolve, the PR’s state is logged and the loop moves on.
  • Phase 2 (cross-session durability via CronCreate durable or claude --bg). Tasks for that get spawned after Phase 1 has run long enough to inform the choice.
  • Phase 3 (standalone Python daemon via Agent SDK). Same gating — Phase 1’s skill body is the spec for Phase 3.
  • Auto-promotion of draft/proposed/backlog tasks to ready. The orchestrator only dispatches tasks the user has already marked ready. Definition and triage remain human (or /sdlc:task-define-assisted) work.
  • Multi-repo orchestration. Single-repo only for v1.
  • Auto-merging PRs. The orchestrator opens PRs and shepherds them through review-readiness; the human merges. Step 11 fires after the human merge.
  • A bespoke notification UI. PushNotification + the digest log are it for Phase 1.

Sparked by the user wanting a “generally hands-off” orchestrator that leverages the Claude Code harness now and migrates to a standalone application later. Research (see conversation) surveyed /loop, CronCreate, RemoteTrigger, claude --bg, /ralph-loop, and hooks; the conclusion was that no single primitive gives “survives CC close + full local tools + can dispatch sub-agents” simultaneously, so a phased path is the right shape: /loop foreground today, durable session next, standalone daemon last. The architecture pivots on one insight from the same conversation — invoking a skill runs in the calling context, but dispatching via Agent isolates that context, so dispatching task-work through Agent sub-agents (Pattern B) keeps the orchestrator parent context bounded across many ticks.


← Back to Tasks