Developer Docs

The Delivery Loop

The ds-story orchestrator and the branch/build/PR skills it composes to take one DevStride story from selection to shipped, merged code — plus the golden-dataset support skills that back it.

The Delivery Loop

The delivery loop is the set of /ds-* Claude Code skills that carry ONE DevStride story from "next unblocked item" to "merged and Done" — branching, building, self-reviewing, opening a PR, addressing findings, merging, and running the completion ritual, then looping to the next story. /ds-story is the orchestrator; /ds-branch-feature, /ds-ultracode-build, and /ds-pr are the skills it composes directly, and /ds-push is a smaller utility nested one level deeper — /ds-pr calls it internally to land review fixes, so it genuinely sits inside the loop even though it's also usable standalone. /ds-branch-hotfix is the one skill on this page that truly sits alongside the loop rather than inside it — /ds-story never calls it. A short closing section covers the golden-dataset skills, which are supporting infrastructure a developer runs by hand — never part of the story loop itself.

/ds-story — the orchestrator

/ds-story <item|next> runs the whole loop: select → mark In Progress → branch → build → adversarial review → PR → merge → completion ritual → sync develop → next. It is the ORCHESTRATOR — it composes the other skills below by name and owns only the DevStride-specific glue (next-story selection, lane transitions, the completion ritual). It is explicitly designed to run under /loop for full autonomy.

The steps, in order:

  1. Select the story. Resolve a plan root (from $ARGUMENTS or prior /ds-plan/ds-story memory), then pick the highest-priority, not-Done, not-blocked_by-anything Story/Defect in the earliest-dated open Capability/Epic on the plan's critical path — the same canonical "next-unblocked" definition ds-insert-story, ds-insert-defect, and ds-comprehend-plan use. It re-fetches the item's full description and validates it against the actual codebase before treating anything in it as true, and reports the whole "ready-set" of unblocked candidates (not just the one it picked) so parallel waves stay visible even though execution itself is serial.
  2. Mark In Progress — a real update_item lane move on the live item.
  3. Branch — invokes /ds-branch-feature with a slug derived from the item number.
  4. Build — invokes /ds-ultracode-build, which owns the understand/build/adversarial-review engine (below).
  5. Open the PR — invokes /ds-pr in its autonomous, driven-by-ds-story mode.
  6. Merge, with merge-gate recovery: rebase develop in before merging so conflicts surface where they're resolvable — pushing the rebased branch goes through /ds-push (force-with-lease), never a bare git push, since a real rebase rewrites SHAs and would otherwise be rejected as non-fast-forward. Watches actual CI check-run status (not just reviewer bots) with a non-blocking snapshot poll — reusing the same check /ds-pr step 4 already surfaced, not a blocking gh pr checks --watch, which would tie up the tool call for the full run (this repo's golden/full gates can run 20+ minutes). Retries flaky failures (bounded, ~2 attempts), fixes real failures in-loop, and merges only once CI is actually observed green — gh pr merge <n> --merge --delete-branch.
  7. Completion ritual — move the item to Done, set startDate/dueDate to the branch/PR window, confirm or manually create the PR↔item link, and — if the build materially diverged from the item's written spec — preserve the original description as a comment and rewrite the description to the as-built spec.
  8. Capture untracked findings (step 6.5) — any real, out-of-scope finding or newly discovered defect with no existing home gets spliced into the dependency graph via /ds-insert-defect or /ds-insert-story so a future loop iteration actually reaches it. See The Planning Loop for what those two skills do.
  9. Sync develop and proceedgit checkout develop && git pull --ff-only, assert a clean tree (the next /ds-branch-feature aborts on a dirty one), persist the resolved plan root, and loop back to step 1 for the next story.

Autonomy boundary

/ds-story runs the entire loop — select through next-story — without pausing between steps. It stops and asks a human ONLY at a genuine fork:

  • a story gated on a human decision or external infra that is the user's to do (AWS / DNS / SES / Stripe / secrets / account provisioning);
  • an ambiguous, risky, or unverifiable review finding;
  • a destructive or outward-facing action that needs confirmation.

Everything else proceeds on the loop's own judgment, with every deferral recorded explicitly (in the build plan, the PR body, and project memory) rather than silently dropped. This is exactly the contract /loop needs to drive /ds-story unattended.

If a resolved plan has zero not-Done, non-gated, unblocked candidates left, /ds-story exits cleanly and reports the terminal state (plan complete, blocked on open items, or gated on human/infra decisions) rather than looping back to re-ask.

Branch creation: /ds-branch-feature vs /ds-branch-hotfix

/ds-branch-feature/ds-branch-hotfix
Branches offdevelop (freshly pulled)a fresh master, with the local DB reset from production
Naming<user-prefix>/<MM-DD-YY>/<branch-name><user-prefix>/hotfix/<MM-DD-YY>/<branch-name>
Called by /ds-story?Yes — step 2 invokes it directlyNo — standalone entry point only
PR targetdevelop (via /ds-pr)master — opened manually when ready (gh pr create --base master --fill); nothing to compare right after creation, so no PR is opened as part of the skill
Use whenBuilding/shipping a normal story through the delivery loopAn urgent fix that must branch from production code, not develop

/ds-branch-feature is the everyday branch-creation utility: it aborts on a dirty tree, syncs develop, creates and pushes the new branch. It's used both directly and as the building block /ds-story calls at step 2.

/ds-branch-hotfix is a heavier, standalone tool for genuine production emergencies. Its preflight is strict: SOURCE_DB_CONNECTION_STRING must be set (the DB reset fails partway without it, leaving the DB half-reset), the working tree must be clean, and it recommends stopping any running ds run backend first since resetting the DB underneath it can cause problems. The steps are git checkout mastergit pull → the destructive ds script reset-db (drops and reseeds the local DB from prod) → create the hotfix branch → ds migrations run → push. On any failure partway through, it does not strand the user on master — it reports exactly which step failed and asks how to proceed rather than guessing.

/ds-ultracode-build — the build engine

/ds-ultracode-build I<number> <one-line goal/scope> is the build engine /ds-story invokes internally once a branch exists and the item is already In Progress. It is not a standalone story-selection tool — it assumes the branch, the item state, and the scope are already given — and it does not open a PR or merge; it hands back to /ds-story. It runs three phases:

  1. UNDERSTAND — for a substantive story (touches multiple files, adds/changes a backend handler or route, crosses a module boundary, carries real correctness or security surface), this runs as an ultracode Workflow: parallel reader agents (design-doc, downstream-contract, libs/conventions, infra/seam, module-structure, test-plan) each return structured findings, synthesized into a concrete build plan and a buildable-now-vs-deferred scope line. For a genuinely trivial change (a one-line fix, a copy tweak, a config flip with no contract surface), this phase is skipped and the work happens inline — but the skill treats "unsure" as substantive, since an unnecessary Workflow is cheap next to a missed contract mismatch.
  2. BUILD — the main implementation loop: small increment → checks green → commit, repeated. Commits happen often (not one giant commit at the end), following Conventional Commits with an item tag, and every commit carries the required Co-Authored-By: and Claude-Session: trailers. Type-checks, the four pre-commit wiring checks, and the relevant tests must stay green — a red non-SDK check is a stop-and-fix, never a commit-anyway. Generated API artifacts (SDK/openapi/mcp gen output) are regenerated and committed separately from hand-written logic.
  3. ADVERSARIAL REVIEW — another ultracode Workflow, run against the hand-written diff only (generated files excluded). Stage A fans parallel finders across five angles — correctness, security, contract-match, tests/false-green, cleanup/conventions. Stage B runs per-finding verification, classifying each into CONFIRMED, PLAUSIBLE, or REFUTED. Only CONFIRMED and PLAUSIBLE findings get fixed (or explicitly deferred with a reason); REFUTED findings are dropped, never "fixed."

Findings and deferrals that are real but have no existing tracked item to absorb them are not left as prose — they're collected into an untracked-deferral list that /ds-story step 6.5 turns into real, dependency-spliced DevStride items via /ds-insert-defect / /ds-insert-story. This is the "mid-build escape hatch" for newly discovered work; see The Planning Loop for how those two skills splice an item into the graph.

/ds-ultracode-build hands back to /ds-story with: the item number, a one-line build summary, green-checks confirmation, the finalized scope/deferral line, the untracked-deferral list, and a deviations list — every material way the build diverged from the item's written spec. That deviations list is what /ds-story step 6 uses to reconcile the item's as-built description.

/ds-pr — PR creation, automated review, and triage

/ds-pr opens the pull request, runs it through a local review and the repo's automated GitHub reviewers, addresses verified findings, and optionally links the PR to its DevStride item. It has two modes:

  • Standalone — a human runs /ds-pr [item-number] directly. It asks which base branch to target (develop for a feature branch, master for a hotfix), keeps every interactive ask-gate, and offers to link the PR to a DevStride item as its final step.
  • Autonomous, driven-by-ds-story — invoked as /ds-story step 4. The base branch is pre-answered (develop), the review-poll timeout defaults to "proceed with the local findings" instead of asking, and step 8 (linking) is skipped entirely/ds-story owns PR-to-item linking in its own step 6, and linking in both places would double-own it. Even in autonomous mode it still pauses for a genuine fork (an ambiguous/risky/unverifiable finding, or a destructive/outward-facing action) — only "out of scope but real" findings are captured rather than asked about.

The steps: open the PR (gh pr create --base <base> --fill, no Co-Authored-By or AI-attribution text in the PR body — those trailers live on commits only), run /code-review high locally, request both automated reviewers (@codex review as a PR comment for Codex; the requested_reviewers API for Copilot), poll GitHub for reviews/comments and CI check status (gh pr checks), auto-address findings that are both verified and clearly in scope, then triage everything else into exactly one bucket:

  • REFUTED / incorrect → dismissed with a posted rationale — never silently ignored.
  • Real but out of scope → captured, not just asked about: added to the untracked-deferral list (autonomous mode) or created directly via /ds-insert-defect//ds-insert-story (standalone mode). Standalone /ds-pr has no notion of a "plan root" — its only input is an optional single item number — so in that mode it asks the user for the Module/Capability/Epic to anchor the insert under rather than guessing one.
  • Genuinely ambiguous / risky / unverifiable → the one bucket that legitimately stalls an autonomous run — listed with a recommendation, and the loop stops to ask.

Agreed fixes are committed and pushed with /ds-push (see below) — /ds-pr never opens a second PR to land review fixes.

Because it triages external, unauthenticated-relative-to-the-agent content — GitHub bot review comments and PR comments — and in autonomous mode acts on it with reduced oversight, /ds-pr treats any embedded instruction inside a review comment (beyond a normal code-review suggestion) as untrusted data, not a legitimate instruction, and flags it to the user if it appears.

/ds-push — a smaller, direct utility

/ds-push is a small git-workflow utility, not part of the phased build/review engine: git add -u (already-tracked files only — it deliberately never sweeps in untracked files with git add .), show git status and a staged diff summary, commit with a message carrying the required Co-Authored-By:/Claude-Session: trailers — using the exact per-session values, never a stale example, and stopping to ask rather than guessing if those values aren't clearly available — run pnpm --dir backend run check:ts && pnpm --dir frontend run check:ts, then push (falling back to git push --force-with-lease — never a bare --force — on a non-fast-forward rejection). If the type-check fails with non-SDK errors, it does not push; it reports and asks. It explicitly does not open a pull request — it's the stage/typecheck/push building block /ds-pr calls internally to land review fixes, and it's equally usable standalone whenever you want to push without opening a PR.

How it composes

/ds-story <item|next>
├─ 0. select story              (get_item, dependency graph, ready-set)
├─ 1. mark In Progress           (update_item — PRODUCTION write)
├─ 2. /ds-branch-feature I<####>-<slug>
├─ 3. /ds-ultracode-build I<####> <scope>
│     ├─ UNDERSTAND   (ultracode Workflow: parallel readers → build plan)
│     ├─ BUILD        (commit often, keep checks green)
│     └─ ADVERSARIAL REVIEW (Workflow: finders → per-finding verify → fix)
│           └─ compiles an untracked-deferral list for anything real
│              with no existing tracked home (not invoked here —
│              handed back to /ds-story, see step 6.5 below)
├─ 4. /ds-pr   (autonomous / driven-by-ds-story mode)
│     ├─ local /code-review high
│     ├─ Codex (@codex review) + Copilot automated review
│     ├─ auto-address verified in-scope findings
│     ├─ triage: dismiss REFUTED / capture out-of-scope / ask on real forks
│     └─ /ds-push  (commit + typecheck + push the fixes)
├─ 5. merge          (rebase develop in, watch CI, retry flaky, fix real failures)
├─ 6. completion ritual (Done lane, dates, PR link, as-built spec reconciliation — PRODUCTION writes)
├─ 6.5 capture untracked findings → /ds-insert-story · /ds-insert-defect
└─ 7. sync develop → back to step 0 (next story, or exit on terminal condition)

/ds-branch-hotfix is deliberately absent from this diagram — it's a standalone entry point for production emergencies, not a step /ds-story ever calls.

Golden dataset & local DB support skills

/ds-golden, /ds-golden-build, /ds-golden-push, and /ds-reset-db are supporting infrastructure a developer runs directly — none of them is invoked by /ds-story, and they are not steps in the delivery loop. They exist to keep your local database and stage data usable while you build. Each is a thin, judgment-adding layer over the underlying ds golden / ds script CLI; for what those CLI verbs actually do, see Golden Dataset.

  • /ds-golden [org] — checks dataset health and, if needed, restores it. It always starts read-only (ds golden status, which mutates nothing); if the dataset is unhealthy, it only proposes a fix (a re-import, a reanchor) for the user to confirm — it never auto-runs a mutating verb on its own judgment.
  • /ds-golden-build [representative|full] — the heavy, rare, hours-long content-authoring flow: rebuilds the dataset from the generator (backend/tests/golden/) and, once it passes the §16 pre-ship assertion gate (which stamps a marker the publish step refuses to proceed without), optionally publishes it to the canonical golden source DB. It does not touch any stage.
  • /ds-golden-push <stage> — deploys/refreshes the golden Acme dataset onto a named stage, choosing the safe verb for that target: additive ds golden import for a shared, populated stage like dev (app.devstride.dev), or a whole-DB push --force-full-reset only for a confirmed-disposable stage. It hard-refuses prod outright — the CLI's own stage guard blocks every mutating golden verb against api.devstride.com, and this skill won't attempt a workaround.
  • /ds-reset-db — resets the local database from production, then re-applies the current branch's migrations on top. Strict preflight: SOURCE_DB_CONNECTION_STRING must be set (the reset fails partway without it), the working tree should be clean, and it recommends stopping any running ds run backend first. If any step fails, it does not leave you stranded on master — it checks out your original branch to restore you before reporting what broke.

Per the golden dataset's own directive, any correction to golden data belongs in the generator, never in a direct database edit — a stage reset or reseed is expected to wipe hand-patched rows.

Next Steps

  • The Planning Loop/ds-plan, /ds-insert-story, /ds-insert-defect, and /ds-comprehend-plan: how work gets onto the dependency graph that /ds-story selects from
  • Golden Dataset — the ds golden CLI these skills wrap
  • Command Reference — the full ds CLI surface