@wemuda/launchrail 1.12.0 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/assets/agents-docs/domain.md +2 -2
- package/assets/agents-docs/issue-tracker-github.md +1 -1
- package/assets/agents-docs/issue-tracker-linear.md +1 -1
- package/assets/ralph.workflow.js +640 -273
- package/assets/skills/NOTICE.md +4 -0
- package/assets/skills/launchrail/launch/SKILL.md +9 -7
- package/assets/skills/launchrail/launch/workflow.md +57 -4
- package/assets/skills/launchrail/launch-code-review/SKILL.md +1 -1
- package/assets/skills/launchrail/launch-design-handoff/SKILL.md +3 -2
- package/assets/skills/launchrail/launch-design-validation/SKILL.md +3 -3
- package/assets/skills/launchrail/launch-discovery/SKILL.md +3 -3
- package/assets/skills/launchrail/launch-grill/SKILL.md +51 -15
- package/assets/skills/launchrail/launch-grill/domain-modeling.md +3 -1
- package/assets/skills/launchrail/launch-implement/SKILL.md +10 -10
- package/assets/skills/launchrail/launch-project-alignment/SKILL.md +3 -3
- package/assets/skills/launchrail/launch-ralph/SKILL.md +79 -59
- package/assets/skills/launchrail/launch-ralph-implement/SKILL.md +8 -7
- package/assets/skills/launchrail/launch-resolving-merge-conflicts/SKILL.md +1 -1
- package/assets/skills/launchrail/launch-spec/SKILL.md +8 -6
- package/assets/skills/launchrail/launch-tickets/SKILL.md +10 -7
- package/assets/skills/launchrail/launch-vision-creation/SKILL.md +2 -2
- package/assets/skills/launchrail/launch-wayfinder/SKILL.md +15 -9
- package/dist/commands/add.js +2 -1
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/doctor.js +29 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.js +2 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/verify.d.ts +11 -2
- package/dist/commands/verify.js +22 -7
- package/dist/commands/verify.js.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/adr.d.ts +27 -0
- package/dist/lib/adr.js +87 -0
- package/dist/lib/adr.js.map +1 -0
- package/dist/lib/manifest.d.ts +7 -1
- package/dist/lib/manifest.js +8 -1
- package/dist/lib/manifest.js.map +1 -1
- package/dist/lib/project.d.ts +2 -0
- package/dist/lib/project.js +2 -1
- package/dist/lib/project.js.map +1 -1
- package/dist/lib/seeds.d.ts +2 -0
- package/dist/lib/seeds.js +14 -6
- package/dist/lib/seeds.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,33 +1,38 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launch-ralph
|
|
3
|
-
description: The Ralph implementation loop's contract — policies, dispatch steps, the loop-owned
|
|
3
|
+
description: The Ralph implementation loop's contract — policies, dispatch steps, the loop-owned local landing gate, checkpoints, and the supervisor's duties, whether the loop runs as the ralph workflow (the default engine) or as skill-mode orchestration (the declared exception). Behind /launch-implement — reach it through that door or an explicit user request, never on your own initiative.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Ralph — the autonomous implementation loop
|
|
7
7
|
|
|
8
|
-
The user starts this loop through `/launch-implement` (or by asking for it in so many words); it is never started unprompted — a campaign spawns many agents and
|
|
8
|
+
The user starts this loop through `/launch-implement` (or by asking for it in so many words); it is never started unprompted — a campaign spawns many agents and lands code, so the start is always a human decision.
|
|
9
9
|
|
|
10
|
-
You are the orchestrator. **You do not write code. You do not read diffs. You do not fix failing branches yourself.** You compute what's ready, dispatch, verify, and keep a running log. Tracker state and subagent reports in, decisions out.
|
|
10
|
+
You are the orchestrator. **You do not write code. You do not read diffs. You do not fix failing branches yourself.** You compute what's ready, dispatch, land, verify, and keep a running log. Tracker state and subagent reports in, decisions out.
|
|
11
11
|
|
|
12
12
|
**Output budget: decisions, not working.** You owe the user two reports per run — a one-line pre-launch echo (scope, target, engine) and the close-out recap — plus any *failure* or *changed plan* the moment it happens. Everything else is working, not output: precondition checks, base-branch resolution, guard-hook state, journal reads, arming check-ins. Do it silently. A passing check is not a status update; a launched run is not a recap; the scope, target, and engine are stated once at the echo and once at close-out, never restated between. Keep the running log for yourself — surface it only at those two moments.
|
|
13
13
|
|
|
14
|
-
One agent implementing a whole backlog in a single session degrades — context fills with diffs and half-remembered state, and quality drops with every ticket. This loop inverts that: every ticket gets a fresh-context implementer subagent that owns the build through
|
|
14
|
+
One agent implementing a whole backlog in a single session degrades — context fills with diffs and half-remembered state, and quality drops with every ticket. This loop inverts that: every ticket gets a fresh-context implementer subagent that owns the build through a pushed, fast-gate-green `ralph/<n>-*` branch; the loop lands that branch itself — a local squash-merge onto the integration base under its own gate run, pushed straight to the remote — and nothing anyone reports is trusted until the remote confirms it. There is no per-ticket PR and no cloud-CI wait anywhere in the loop: the same gate that CI would run runs locally in minutes (or seconds, on warm caches), and cloud CI runs once, on the release PR the run offers at the end (ADR-0032).
|
|
15
15
|
|
|
16
|
-
This skill is the loop's contract and its supervisor. The loop itself runs as the deterministic `ralph` workflow (`.claude/workflows/ralph.js`, installed by init; `launchrail sync` restores it) — **the workflow is the engine for every multi-ticket run**, launched with the resolved scope and integration target as JSON args and then supervised per this skill; its script state cannot be compacted away. Orchestrating dispatches from this session instead is the exception, and it is chosen out loud — name the engine and why before anything dispatches: the user asked to watch each dispatch, the Workflow tool is unavailable in this environment, or this is a targeted intervention (one parked ticket, re-run watchably). A hand-rolled fan-out that is neither is not the loop. And the exception swaps only who orchestrates, never the shape: fresh context per ticket, per-ticket
|
|
16
|
+
This skill is the loop's contract and its supervisor. The loop itself runs as the deterministic `ralph` workflow (`.claude/workflows/ralph.js`, installed by init; `launchrail sync` restores it) — **the workflow is the engine for every multi-ticket run**, launched with the resolved scope and integration target as JSON args and then supervised per this skill; its script state cannot be compacted away. Orchestrating dispatches from this session instead is the exception, and it is chosen out loud — name the engine and why before anything dispatches: the user asked to watch each dispatch, the Workflow tool is unavailable in this environment, or this is a targeted intervention (one parked ticket, re-run watchably). A hand-rolled fan-out that is neither is not the loop. And the exception swaps only who orchestrates, never the shape: fresh context per ticket, per-ticket pushed branches landed one at a time by the loop's own local gate onto the target, and the full gate at checkpoints survive every engine. An environment rule about branches or PRs re-targets the run (see Integration target) — it never selects this exception and never licenses sequential in-session implementation. The two forms share one policy block: change a policy here, change it in the workflow too (ADR-0005, field-revised by ADR-0010, ADR-0022, ADR-0026, and ADR-0032).
|
|
17
17
|
|
|
18
18
|
## Policies
|
|
19
19
|
|
|
20
|
-
- **Integration target: declared, singular, restated.** Every run
|
|
21
|
-
- **
|
|
22
|
-
- **
|
|
23
|
-
- **
|
|
24
|
-
- **
|
|
25
|
-
- **
|
|
26
|
-
- **
|
|
27
|
-
- **
|
|
28
|
-
- **
|
|
29
|
-
- **
|
|
30
|
-
- **
|
|
20
|
+
- **Integration target: declared, singular, restated.** Every run lands its per-ticket branches onto exactly one base, named before anything dispatches and again in the close-out. **Consolidation** (the default, ADR-0026): one integration branch (e.g. `spec/44-mvp`) collects the whole campaign and the default branch is never touched; the front door names it scope-native — the session's designated working branch when the environment pinned one at start, else the scope's own spec/epic/slice name when it maps to one, else a generated `launch/*` fallback — and passes it as the `target` arg. A pinned-branch session (ADR-0028) changes only that name: the user's start authorizes the loop's mechanics, per-ticket `ralph/*` branches included, and the pin's real demands — default branch untouched, release PR offered not opened — are exactly what consolidation already does. The run ends by *offering* one release PR `<target> → <default>` — opened only when the user says so; that PR is where cloud CI runs, once. **Trunk** (the explicit opt-in): the repository's default branch — each verified land is immediately on mainline, and when the run ends there is nothing left to integrate; select it only when the user asks for per-ticket lands on the default branch, and never when the environment forbids pushing there. A named target missing from the remote is created from the default branch's tip before preflight verifies it; a missing *default* branch stays a refusal. `Closes #n` never auto-fires off the default branch, so the explicit post-land close is load-bearing, not belt-and-suspenders.
|
|
21
|
+
- **The loop lands in the checkout it was launched from.** Preflight syncs the base into it (clean tree required — commit or stash first; a local base that has diverged from the remote is a refusal), builders work in their own worktrees, and every land and checkpoint runs there one at a time — the warm caches are what make the gate cheap. At the end the checkout sits on the target at its landed tip.
|
|
22
|
+
- **Width: 3** implementers at once, kept busy by a **work pool** — when one finishes, the next ready ticket dispatches; a slow ticket never holds the others. Width multiplies conflict rate and shared-machine load, not just throughput — use 1 until a run has landed tickets cleanly on this project (the workflow's `canary: true` encodes exactly that). Cut a batch below width when its tickets would obviously collide (same module, same files); when in doubt, narrow. Tickets that add DB migrations are a known collision (two parallel implementers both claim the next migration number): the workflow keeps **one migration-adding ticket in flight at a time** from the graph reader's flag; in skill mode, serialize them yourself.
|
|
23
|
+
- **Ordering: critical path first.** Among ready tickets, the one with the most transitive dependents dispatches first, so a wide graph unblocks quickly — computed from the parsed edges, never by a model.
|
|
24
|
+
- **Cap: none** by default. The user may bound a run ("the next 5"): stop once that many lands have been *verified*, keeping dispatch within the remainder so the run cannot overshoot. Failed and deferred dispatches never consume the cap. Hitting the cap ends the run cleanly: the rest of the frontier stays ready (reported, never parked), and close-out runs as usual.
|
|
25
|
+
- **Persistence: the pushed branch is the checkpoint.** An implementer pushes its `ralph/<n>-<slug>` branch the moment it branches and after every green step. A lost container costs the minutes since the last push, never a build: the next dispatch (this run's retry, or a relaunch after a recycle) adopts the pushed branch and continues from its last commit. Pushed `ralph/*` branches are never deleted mid-run; the release prunes only the branches of verified-landed tickets.
|
|
26
|
+
- **Attempts: 2** — retry a failed ticket once with a fresh context, then park it. The retry adopts the pushed branch and fixes forward; only when the failure shows the approach itself was wrong does it reset the branch and start over.
|
|
27
|
+
- **Re-syncs: 2 — a land hand-back spends no attempt.** When the base moved under a finished branch (the squash conflicts, or the merged tree fails the gate although the branch was fine on its own, or the remote base kept moving), the builder did nothing wrong: a fresh implementer re-syncs the pushed branch — merge the latest base in, resolve, fast gate, push, hand off again — up to twice per ticket before it counts as a real failure.
|
|
28
|
+
- **Deferrals are not attempts.** An implementer that stops at its dependency gate (a declared blocker had not actually landed) hands the attempt back and is retried after the next land or tracker refresh — capped at 2 deferrals, then it counts as a real failure.
|
|
29
|
+
- **Two gates, tiered.** The **fast gate** — `npx @wemuda/launchrail verify --fast` (`testing.checkCommand`, else the unit command; never e2e) — runs before every hand-off and again, by the loop, on every merged tree before it is pushed. The **full gate** — `npx @wemuda/launchrail verify` — runs at preflight, at **checkpoints** (after every 5 lands: `checkpointEvery`), and at release before the loop may report success. The full suite is paid once per checkpoint instead of once per ticket, and a red checkpoint has at most five suspects.
|
|
30
|
+
- **A red checkpoint gets one repair.** The loop dispatches a single fresh implementer with the failures and the tickets landed since the last green base; its branch lands under the *full* gate and becomes the new green checkpoint. If that repair does not land, the base is **red**: nothing else lands, finished tickets are **held** on their pushed branches, and the run ends unverified with the reason — a human fixes the base and relaunches with `knownGreen`.
|
|
31
|
+
- **Max builds: 60** — a backstop, not a target; retries, deferrals, re-syncs, and repairs all spend from it. Stop and report if the frontier hasn't drained.
|
|
32
|
+
- **Checkpoints: none** in the human sense by default — run to completion, report once. The user may ask for a pause after each land instead.
|
|
33
|
+
- **Review gate:** the implementer's own self-review via the `launch-code-review` skill, inside `launch-ralph-implement`.
|
|
34
|
+
- **Landing ownership: the loop, not the implementer.** Implementers build, push, and hand off at a green fast gate; the landing — fetch, fast-forward the base, squash-merge, the loop's own gate run, push, explicit issue close, `ralph:building` removal — belongs to the loop (you in skill mode, a per-ticket lander agent in the workflow), strictly one at a time. A lander never writes code: a conflict or a red gate is reported and handed back, never repaired in place.
|
|
35
|
+
- **Labels:** tickets enter as `ready-for-agent`, are marked `ralph:building` while owned, and leave as closed or `needs-info` (parked). A held ticket keeps `ralph:building` — the next run owns it.
|
|
31
36
|
|
|
32
37
|
## Preconditions — refuse to start if any fails
|
|
33
38
|
|
|
@@ -35,85 +40,100 @@ Verify them silently: a green base and a reachable tracker are the expected case
|
|
|
35
40
|
|
|
36
41
|
1. `.launchrail.yml` exists with `issueTracker` not `none`, and the tracker is reachable **from this environment**: check whether the CLI the project docs assume (e.g. `gh`) is installed here; if not, identify the substitute (e.g. GitHub MCP tools) and name it in every dispatch.
|
|
37
42
|
2. Open tickets labeled `ready-for-agent` exist and carry explicit `Blocked by: #n` edges (or the tracker's native blocking relations). No tickets with edges → nothing to orchestrate; point the user at `launch-tickets`. If anything wearing `ready-for-agent` is plainly not an implementable ticket — a published spec, research notes, an epic — stop and have it relabeled (e.g. `spec`) before starting: the frontier is computed from the label alone and cannot tell prose from work.
|
|
38
|
-
3. The integration target is resolved (a consolidation branch by default, or trunk when the user opts in — see Policies) and its branch is green
|
|
39
|
-
4. The verbatim local commands are known (from `AGENTS.md` / `.launchrail.yml`),
|
|
43
|
+
3. The integration target is resolved (a consolidation branch by default, or trunk when the user opts in — see Policies) and its branch is green **in this checkout**: the tree is clean, the base is synced (creating a named consolidation branch from the default branch's tip if the remote lacks it; a local base that has diverged from the remote is a refusal — push or reset it first), the install command has run, and `npx @wemuda/launchrail verify` exited 0 — report actual exit codes, not the reassuring summary line; a broken base poisons every implementer after it. A missing *default* branch is a refusal, not a cue to guess another. An **empty verification contract fails `verify` and is a refusal condition**: a run whose completion nothing can verify must not start. Tell the user to configure `testing` commands in `.launchrail.yml` first. **On a relaunch** whose base still sits at a sha a previous run verified green, pass that sha as `knownGreen`: preflight syncs and installs but skips re-proving the base.
|
|
44
|
+
4. The verbatim local commands are known (from `AGENTS.md` / `.launchrail.yml`): install, the fast gate, the full gate, and which checks belong to the shared local machine. If `testing.checkCommand` is unset the fast gate is the unit command — fine, but a project that names a quicker lint/typecheck/unit gate there makes every land cheaper.
|
|
40
45
|
|
|
41
46
|
## The loop
|
|
42
47
|
|
|
43
|
-
Sync → compute frontier →
|
|
48
|
+
Sync → compute frontier → keep *width* builders busy → land each finished branch as it arrives → verify on the remote → checkpoint every N lands → back to the frontier.
|
|
44
49
|
|
|
45
|
-
- **You resolve blocking edges yourself,** deterministically, from tracker state — read each ticket's `Blocked by` line verbatim and parse the `#n` references; never ask a subagent what's ready, and never let one paraphrase the edges. A single misread edge silently builds a ticket on a dependency that hasn't landed. The frontier is every ticket that is open, labeled `ready-for-agent`, not `needs-info`, not already attempted twice, and whose blockers are all settled (closed before the run, or
|
|
46
|
-
- Dispatch up to *width* frontier tickets, **spawning the
|
|
47
|
-
- **
|
|
50
|
+
- **You resolve blocking edges yourself,** deterministically, from tracker state — read each ticket's `Blocked by` line verbatim and parse the `#n` references; never ask a subagent what's ready, and never let one paraphrase the edges. A single misread edge silently builds a ticket on a dependency that hasn't landed. The frontier is every ticket that is open, labeled `ready-for-agent`, not `needs-info`, not already attempted twice, not in flight, and whose blockers are all settled (closed before the run, or landed and verified by this run). Parked and held tickets never block the loop; anything behind them is reported as stuck.
|
|
51
|
+
- Dispatch up to *width* frontier tickets, **spawning the subagents in a single message** so they run concurrently, and dispatch the next ready ticket the moment a slot frees — never wait for a whole batch.
|
|
52
|
+
- **Adopt pushed work.** Before dispatching, list the remote's `ralph/*` branches; a ticket that already has one is dispatched with that branch named so the builder adopts it instead of starting over.
|
|
53
|
+
- **Land one at a time, in your checkout,** as branches arrive — never two lands interleaved, and never a land onto a red base.
|
|
54
|
+
- **Verify every claimed land against the remote** before it counts: the landing commit is on the base branch, the issue is closed. A subagent's report is a claim, not evidence. Use a cheap, separate check (tracker/API only — a comment is not evidence).
|
|
48
55
|
|
|
49
56
|
## The dispatch prompt
|
|
50
57
|
|
|
51
|
-
Each implementer prompt is self-contained — assume it knows nothing about this session or the other implementers. It carries: the ticket number and title, the verbatim commands, how to reach the tracker from this environment, which branch is the base (the integration target), and these seven steps:
|
|
58
|
+
Each implementer prompt is self-contained — assume it knows nothing about this session or the other implementers. It carries: the ticket number and title, the verbatim commands (install, fast gate, full gate), how to reach the tracker from this environment, which branch is the base (the integration target), any pushed branch to adopt, and these seven steps:
|
|
52
59
|
|
|
53
|
-
1. **Dependency gate:** before anything else, confirm every ticket on the `Blocked by` line is closed with its work
|
|
60
|
+
1. **Dependency gate:** before anything else, confirm every ticket on the `Blocked by` line is closed with its work landed on the base. If any blocker is still open, do not build on a missing dependency — report "blocked" naming the open blocker, and stop. A deferral, not a failure; the loop retries after the blocker lands.
|
|
54
61
|
2. Read the ticket and everything it links (spec sections, ADRs, journeys), plus `AGENTS.md`/`CLAUDE.md`. If the tracker tool truncates the body (long code spans are a known trigger), fetch the full text by another route — the tracker's search API, the spec file in the repo — and never implement from a truncated ticket. If the ticket is already closed, report "already-done" and stop.
|
|
55
62
|
3. Label the ticket `ralph:building` so a lost session leaves a trace.
|
|
56
|
-
4. Branch from a fresh
|
|
57
|
-
5. Implement by
|
|
58
|
-
6. Pre-
|
|
59
|
-
7.
|
|
63
|
+
4. **Branch and push immediately.** Adopt a pushed `ralph/<n>-*` branch when one exists (fetch it, continue from its last commit — never start over); otherwise branch from a fresh fetch of the base — `git checkout -b ralph/<n>-<short-slug> origin/<base>`, never a checkout of the base itself in the worktree — and push at once. From then on **commit and push after every green step**: the pushed branch is the checkpoint a lost session resumes from and the loop's liveness signal.
|
|
64
|
+
5. Implement by calling the Skill tool with **`launch-ralph-implement`** — it owns TDD, the commit-and-push cadence, the fast gate, browser smoke for user-facing changes, self-review via `launch-code-review`, and commit conventions. Name the skill; do not paraphrase it.
|
|
65
|
+
6. Pre-land sync: merge the latest base into the branch; resolve conflicts by calling the Skill tool with **`launch-resolving-merge-conflicts`**; if the base gained DB migrations since branching, regenerate yours to follow them with the project's migration tool — never hand-edit the journal; re-run the fast gate if anything changed, then push.
|
|
66
|
+
7. **Hand off:** confirm the pushed tip matches `HEAD`, then report "ready" with the branch, its sha, and a Conventional Commit title for the squash — and stop. The landing belongs to the loop. Never push to the base, never merge your work into it, and never open a PR — the campaign is released by one PR at the end.
|
|
60
67
|
|
|
61
|
-
## The
|
|
68
|
+
## The landing — owned by the loop
|
|
62
69
|
|
|
63
|
-
In skill mode
|
|
70
|
+
In skill mode you land every branch the implementers hand off, in your own checkout, one at a time (the workflow runs it as a per-ticket lander agent, serialized by a script lock). Landing is bookkeeping, not repair:
|
|
64
71
|
|
|
65
|
-
1.
|
|
66
|
-
2.
|
|
67
|
-
3.
|
|
68
|
-
4.
|
|
72
|
+
1. Preconditions: a clean tree (never stash or discard); fetch the base and the branch; check out the base and fast-forward it to the remote — a local base that has diverged is a stop, not a reset.
|
|
73
|
+
2. Note whether the base moved since the implementer synced (is the base tip an ancestor of the branch?).
|
|
74
|
+
3. `git merge --squash origin/ralph/<n>-<slug>`; on conflicts, reset to the remote base and hand back "conflict" with the files. Otherwise commit with the implementer's Conventional Commit title, `(#n)`, and a `Closes #n` trailer.
|
|
75
|
+
4. If the change touched a dependency manifest or lockfile, run the install command. Then run the **fast gate** on the merged tree. Red → reset to the remote base and hand back "gate-failed" with the failing checks; a red base is never pushed.
|
|
76
|
+
5. Push the base. A rejected push means the remote moved outside the loop: reset to it and redo once; a second rejection is "stale".
|
|
77
|
+
6. Confirm on the remote that the base tip is your commit — that sha is the landing commit.
|
|
78
|
+
7. Close the issue explicitly (auto-close never fires off the default branch), read it back closed, remove `ralph:building`, leave one comment naming the base and the sha. Then verify as always: the remote's word, not yours.
|
|
69
79
|
|
|
70
|
-
|
|
80
|
+
A conflict, a gate that only fails on the merged tree, or a stale remote hands the ticket back for a **re-sync** (no attempt spent, twice at most); a gate that fails on a branch that already contained the base tip is the builder's own failure and spends the attempt. Order lands as branches arrive; when two are ready at once, land the one with more dependents first.
|
|
71
81
|
|
|
72
|
-
|
|
82
|
+
## Checkpoints and the repair
|
|
73
83
|
|
|
74
|
-
|
|
84
|
+
After every `checkpointEvery` lands (default 5) — and always at release — run the **full gate** on the synced base, in the same checkout, with no land interleaved. Green → the base tip is proven; note the sha. Red → dispatch exactly one **repair** implementer with the failures and the tickets landed since the last green base; it branches `ralph/repair-*` from the base, fixes the root cause (an integration break between two tickets, a migration-number collision, a journey a landing invalidated), makes the fast *and* full gates green, pushes, and hands off; land it under the full gate. Landed → green again, carry on. Not landed → the base is red: stop landing, hold finished tickets on their branches, and end the run unverified naming the failure. A failure that reproduces on the base at preflight is systemic — stop the run before it starts.
|
|
85
|
+
|
|
86
|
+
Every dispatch — retries, re-syncs, repairs included — also carries these two clauses verbatim:
|
|
87
|
+
|
|
88
|
+
> **Integrity.** No placeholders, no stubs, no "simplified for now". Never delete, skip, or weaken a test to get a green run; if a test is genuinely wrong, fix it deliberately and say so in the commit message. Never claim a gate passed without having run it.
|
|
89
|
+
|
|
90
|
+
> **Idempotency.** This step can be replayed after an interruption, so check before acting: if the ticket is already closed, report "already-done"; if a pushed `ralph/<n>-*` branch already exists, adopt it and continue from its last commit — don't restart, and never create a second branch for a ticket.
|
|
75
91
|
|
|
76
92
|
## Outcome handling
|
|
77
93
|
|
|
78
|
-
- **Verified
|
|
79
|
-
- **Blocked (deferred)** → the dependency gate stopped the build. Hand the attempt back and retry
|
|
80
|
-
- **
|
|
81
|
-
- **
|
|
82
|
-
- **
|
|
83
|
-
- **
|
|
94
|
+
- **Verified land** → one log line; the ticket settles and may unblock others.
|
|
95
|
+
- **Blocked (deferred)** → the dependency gate stopped the build. Hand the attempt back and retry after the next land or tracker refresh; after 2 deferrals it becomes a real failure. A deferral costs a dispatch, never an attempt.
|
|
96
|
+
- **Land hand-back (re-sync)** → the base moved under a finished branch. Re-dispatch a fresh implementer to adopt the pushed branch, merge the latest base, fast gate, push, hand off — no attempt spent, twice at most.
|
|
97
|
+
- **First failure** → re-dispatch later with a *fresh context* plus the failure summary; the retry adopts the pushed branch and fixes forward. A failed attempt's *context* is assumed poisoned — never resume it; its *code* is persisted and reused.
|
|
98
|
+
- **Claimed landed, remote disagrees** — including landed-but-issue-still-open — → a failure like any other; the retry finds the work on the base (an empty squash) or the issue open, finishes the bookkeeping, and settles cleanly.
|
|
99
|
+
- **Second failure** → park: comment both failure summaries and the pushed branch on the ticket, remove `ralph:building`, add `needs-info`, move on.
|
|
100
|
+
- **Held** → built and pushed while the base is red. Report it with its branch; a relaunch adopts it. Nothing to fix on the ticket.
|
|
101
|
+
- **Systemic failure** — the base breaks and the repair does not land, the tracker becomes unreachable, or the *same* infrastructure error hits different tickets (three dead agents in a row) → stop the whole run and report; another retry won't fix it.
|
|
84
102
|
|
|
85
103
|
## Supervising a workflow run
|
|
86
104
|
|
|
87
105
|
When the Ralph loop runs as the `ralph` workflow instead of through this skill, you are still on the hook — the script runs headless, but a human is watching *you*, not it. Babysit the run like a deploy:
|
|
88
106
|
|
|
89
|
-
0. **Launch it unattended-safe.** An unattended run must start in a non-prompting permission mode (bypass / autonomous). In an interactive mode (default / plan / acceptEdits) a single benign permission prompt — an un-allowlisted MCP or Bash call — stalls the whole run, and an idle ephemeral container can be reclaimed mid-ticket
|
|
90
|
-
1. **Read the resolved scope back, immediately.** The first `log()` lines state it ("Scoped to #11, #12", "Stopping after 5 verified
|
|
91
|
-
2. **Establish ground truth from the remote, never from the run's own reports.** On every check-in read the workflow journal (`journal.jsonl`) *and* the tracker
|
|
107
|
+
0. **Launch it unattended-safe.** An unattended run must start in a non-prompting permission mode (bypass / autonomous). In an interactive mode (default / plan / acceptEdits) a single benign permission prompt — an un-allowlisted MCP or Bash call — stalls the whole run, and an idle ephemeral container can be reclaimed mid-ticket. A guard hook warns at launch, but switching modes before you walk away is yours to do.
|
|
108
|
+
1. **Read the resolved scope back, immediately.** The first `log()` lines state it ("Scoped to #11, #12", "Stopping after 5 verified land(s)", or "No scope — building the whole ready frontier"), the width and cadence, and any pushed branches being adopted. An unscoped run when the user asked for three tickets is the cheapest failure to catch and the most expensive to miss — stop and relaunch if it is wrong. Scan the listed numbers for anything that is not an implementable ticket: a spec or research issue wearing `ready-for-agent` will be built as if it were work (the workflow excludes and logs obvious cases, but the label is the fix — have it corrected).
|
|
109
|
+
2. **Establish ground truth from the remote, never from the run's own reports.** On every check-in read the workflow journal (`journal.jsonl`) *and* the remote: `git ls-remote --heads origin` shows the base tip and every `ralph/*` branch with its sha; the tracker shows what closed. A land is real only when the commit is on the base branch and the issue is closed.
|
|
92
110
|
3. **Arm check-ins across the long waits.** If the session can schedule a self-message, arm one a few minutes out (confirm scope and the first dispatches) and a longer fallback (catch completion or a stall). The workflow's completion notification is the primary signal; the check-ins are the backstop so the run survives an interruption.
|
|
93
|
-
4. **Know the healthy shapes so you don't cry wolf.**
|
|
94
|
-
5. **Intervene by exception, not by reflex.** Parked ticket → dispatch a fresh scoped run for just that one.
|
|
95
|
-
6. **Report once at the end, concretely** —
|
|
111
|
+
4. **Know the healthy shapes so you don't cry wolf.** `build:#n` → `land:#n` → `verify:#n` is one ticket landing; `checkpoint:k` is the full gate on the base after N lands; `repair:k` followed by `land:repair:k` is a red checkpoint being fixed, not a stall; `build:#n:resync1` is a land hand-back after the base moved (not an attempt); `build:#n:retry` is the one real retry; a ticket can appear twice in Build without either (a *deferral* because its dependency had not landed yet). A long build is *alive* while its `ralph/<n>-*` branch keeps moving on the remote (`git ls-remote`, or the branch's last commit time on the tracker) — that is the liveness signal; a silent journal alone means nothing. A ticket only truly fails after two real attempts, then it parks.
|
|
112
|
+
5. **Intervene by exception, not by reflex.** Parked ticket → dispatch a fresh scoped run for just that one. Held tickets or a red base → the run's recap names the failure; fix the base by hand (or have a scoped run do it), verify it, then relaunch with `knownGreen: <that sha>` — the pushed branches are adopted, nothing is rebuilt. Container recycled mid-run → relaunch the same scope with `knownGreen` set to the last green sha from the journal or the recap; adopted branches resume from their last push. Never delete `ralph/*` branches by hand while a run may still adopt them. Wrong scope or wrong base → stop, fix, relaunch. Otherwise stay out of the way; the loop is built to self-correct.
|
|
113
|
+
6. **Report once at the end, concretely** — landing commits, issues closed, checkpoint verdicts, the verification outcome, held and parked tickets with their branches, anything punted — then disarm the check-ins.
|
|
96
114
|
|
|
97
115
|
## Loop close-out — verification-gated completion
|
|
98
116
|
|
|
99
|
-
When the frontier drains (or
|
|
117
|
+
When the frontier drains (or the cap, the build backstop, a red base, or a stop condition hits):
|
|
100
118
|
|
|
101
|
-
1. Sync a fresh base and run `npx @wemuda/launchrail verify
|
|
102
|
-
2. If `.launchrail.yml` has `modules.browser-testing: true` and any
|
|
103
|
-
3.
|
|
119
|
+
1. Sync a fresh base and run `npx @wemuda/launchrail verify` — unless the last green checkpoint already proved this exact tip. **The loop may not report success while this fails** — report "unverified" with the failures instead; a red base is unverified by definition.
|
|
120
|
+
2. If `.launchrail.yml` has `modules.browser-testing: true` and any landed ticket changed user-facing behavior, dispatch one smoke run per the `launch-browser-smoke` skill and reference its evidence bundle (`artifacts/verification/<run-id>/`).
|
|
121
|
+
3. Prune the remote `ralph/*` branches of the verified-landed tickets — only those; held and parked branches stay.
|
|
122
|
+
4. Report the campaign recap — it must let the user act without scrolling back:
|
|
104
123
|
- **Where the work lives:** the integration target and its head SHA; in consolidation mode, say explicitly that the default branch is untouched.
|
|
105
|
-
- The ticket →
|
|
124
|
+
- The ticket → landing-commit table; held tickets with their branches; parked tickets with their failure histories; stuck tickets and what blocks them; the checkpoint verdicts.
|
|
106
125
|
- Follow-ups and operator steps implementers punted, gathered into one list.
|
|
107
126
|
- The verification outcome with its evidence. Evidence over assertion — link what was run, never summarize what wasn't.
|
|
108
|
-
- **The single next step:** consolidation (the default) — offer the one release PR `<target> → <default>` with this recap as its body, and open it only when the user says so. Trunk — nothing; every
|
|
127
|
+
- **The single next step:** consolidation (the default) — offer the one release PR `<target> → <default>` with this recap as its body (cloud CI runs there, once), and open it only when the user says so; a red base or held tickets add the relaunch-with-`knownGreen` step. Trunk — nothing; every landed ticket is already live on the default branch.
|
|
109
128
|
|
|
110
129
|
## Rules
|
|
111
130
|
|
|
112
|
-
- Fresh context per dispatch, per retry. No exceptions.
|
|
131
|
+
- Fresh context per dispatch, per retry, per re-sync. No exceptions.
|
|
113
132
|
- One integration target and one engine per run, declared in the pre-launch echo and restated once in the close-out recap — never in between.
|
|
114
|
-
- Never implement, review, or repair code in the orchestrator session — dispatch instead.
|
|
133
|
+
- Never implement, review, or repair code in the orchestrator session — dispatch instead. Landing is bookkeeping, not repair; a red gate is handed back, never fixed by the lander.
|
|
115
134
|
- Name the skills (`launch-ralph-implement`, `launch-resolving-merge-conflicts`, `launch-browser-smoke`); never paraphrase their contents into a prompt.
|
|
116
135
|
- Blocking edges are parsed from the verbatim `Blocked by` line, by you — never resolved by a model in between.
|
|
117
|
-
- Nothing counts as
|
|
118
|
-
- A deferral is not a failure; a failure is never silently retried without its summary.
|
|
136
|
+
- Nothing counts as landed until the remote says so; nothing counts as done until the full gate is green on the final base.
|
|
137
|
+
- A deferral is not a failure; a re-sync is not an attempt; a failure is never silently retried without its summary.
|
|
138
|
+
- Push early, push often: work that is not on the remote does not exist to the next session.
|
|
119
139
|
- Width is a lever, not a goal. Narrow it whenever tickets might collide.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launch-ralph-implement
|
|
3
|
-
description: Implement a single ticket end to end under the Launchrail completion contract — TDD, the
|
|
3
|
+
description: Implement a single ticket end to end under the Launchrail completion contract — TDD, commit-and-push after every green step, the fast verification gate before hand-off, browser smoke for user-facing changes, self-review, and conventional commits. Used by Ralph loop dispatches and by /launch-implement's single-ticket mode.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Implement one ticket
|
|
@@ -8,10 +8,11 @@ description: Implement a single ticket end to end under the Launchrail completio
|
|
|
8
8
|
The per-ticket implementation contract. Ralph dispatches name this skill so the contract lives in one place — every implementer, on every run, gets the same one.
|
|
9
9
|
|
|
10
10
|
1. **Read before coding.** The ticket, every artifact it links (spec sections, ADRs, smoke journeys), and `AGENTS.md`/`CLAUDE.md`. The commands you run come from `.launchrail.yml` (`testing.*`) and `AGENTS.md`, verbatim.
|
|
11
|
-
2. **
|
|
12
|
-
3. **
|
|
13
|
-
4. **
|
|
14
|
-
5. **
|
|
15
|
-
6. **
|
|
11
|
+
2. **Push early, push often.** Your branch is pushed before you write a line, and you **commit and push after every green step** — a passing test slice, a finished subtask. The pushed branch is the checkpoint a lost session resumes from (a successor adopts it at its last commit instead of rebuilding) and the loop's liveness signal. Work that is not on the remote does not exist to the next session. Never push to the base branch and never open a PR from inside a loop dispatch — the loop lands your branch.
|
|
12
|
+
3. **TDD at the seams the ticket names.** Write the failing test first where the ticket or spec defines behavior. Typecheck and run single test files as you go; save whole-suite runs for the gate — the machine may be shared with other implementers.
|
|
13
|
+
4. **The gate — tiered.** Before you hand off, `npx @wemuda/launchrail verify --fast` (the fast gate: `testing.checkCommand`, else the unit command) must exit 0 on your branch. Inside a Ralph dispatch that is your gate: the loop runs it again on the merged tree before pushing the base, and runs the full `npx @wemuda/launchrail verify` (browser journeys included) at its checkpoints — so do not spend your turn on the whole suite; run only the slow test files your change touches (a journey you edited). Outside the loop (single-ticket mode, a PR of your own), the full `npx @wemuda/launchrail verify` must exit 0 before the PR. Never delete, skip, or weaken a test to get there; if a test is genuinely wrong, fix it deliberately and say so in the commit message.
|
|
14
|
+
5. **User-facing behavior, with `modules.browser-testing` enabled:** update or add the affected journey in `docs/testing/smoke-journeys.md` and drive it per the `launch-browser-smoke` skill. A journey you could not complete is a failure, not a pass.
|
|
15
|
+
6. **Self-review:** call the Skill tool with `launch-code-review` on the result and fix what it finds before handing off.
|
|
16
|
+
7. **Commit to the current branch** following the project's commit conventions (Conventional Commits when `.launchrail.yml` says so); the loop squashes your branch onto the base, so also hand it a Conventional Commit title for that squash. Update any artifact the change invalidates (spec, ADR, journey) in the same change.
|
|
16
17
|
|
|
17
|
-
Done means: the gate is green, the review found nothing unaddressed, and the evidence (test output, journey results) exists — not that the code "should work".
|
|
18
|
+
Done means: the gate is green, the review found nothing unaddressed, the branch is pushed, and the evidence (test output, journey results) exists — not that the code "should work".
|
|
@@ -11,5 +11,5 @@ When parallel work lands against the same base, conflicts are ordinary work with
|
|
|
11
11
|
2. **Understand both sides.** For each conflicted file, find out what the other side's change was *for* — read its commit message, PR, or ticket if needed. You are merging intents, not text blocks.
|
|
12
12
|
3. **Preserve both behaviors.** The resolved code must do what your change does *and* what theirs does. Taking "ours" or "theirs" wholesale is only correct when the two changes are genuinely the same fix.
|
|
13
13
|
4. **Regenerate, don't hand-merge, generated files.** Lockfiles and other generated artifacts are re-created by their tool after resolving the source of truth — never merged line by line.
|
|
14
|
-
5. **Prove it.** After resolving, run the
|
|
14
|
+
5. **Prove it.** After resolving, run the gate you own at that point — the fast gate (`npx @wemuda/launchrail verify --fast`) inside a Ralph dispatch, the full gate (`npx @wemuda/launchrail verify`) otherwise — then push. A resolution that was never run is not a resolution.
|
|
15
15
|
6. **Escalate ambiguity.** If both sides changed the same logic and any resolution you can see loses behavior, stop and report the conflict (which files, which intents collide) instead of guessing. In the Ralph loop that is the `conflict` outcome — a legitimate result, unlike a quiet wrong merge.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launch-spec
|
|
3
|
-
description:
|
|
3
|
+
description: Synthesize what the conversation already decided into a spec — published as a spec-labeled issue on the tracker, or committed under docs/specs/ in local mode. No interview.
|
|
4
4
|
disable-model-invocation: true
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -8,13 +8,15 @@ disable-model-invocation: true
|
|
|
8
8
|
|
|
9
9
|
This skill takes the current conversation context and codebase understanding and produces a spec. Do NOT interview the user — just synthesize what you already know: the vision, the grill's surviving constraints, the research notes, and the ADRs are the inputs; a conductor handing off this stage names them.
|
|
10
10
|
|
|
11
|
+
Synthesis preserves the grill's labels ([ADR-0029](https://github.com/wemuda/launchrail/blob/master/docs/adr/0029-planning-interaction-contract.md)): **Locked** decisions are stated as decisions; **Provisional** agent-defaults stay marked provisional in the spec (changeable without re-planning); **Deferred** questions land in Out of Scope with the trigger that reopens them — never silently dropped, never silently promoted into scope.
|
|
12
|
+
|
|
11
13
|
## Process
|
|
12
14
|
|
|
13
|
-
1. Explore the repo to understand the current state of the codebase, if you haven't already. Use the project's domain glossary vocabulary (`CONTEXT.md`) throughout the spec, and respect any ADRs in the area you're touching.
|
|
15
|
+
1. Explore the repo to understand the current state of the codebase, if you haven't already. Use the project's domain glossary vocabulary (`CONTEXT.md`) throughout the spec, and respect any ADRs in the area you're touching — find them through the registry index (`docs/adr/README.md`) rather than reading the whole directory, and remember an ADR records a decision, not what exists; the codebase is the evidence for current state.
|
|
14
16
|
|
|
15
17
|
2. Sketch out the seams at which you're going to test the feature. Existing seams should be preferred to new ones. Use the highest seam possible. If new seams are needed, propose them at the highest point you can. The fewer seams across the codebase, the better — the ideal number is one.
|
|
16
18
|
|
|
17
|
-
Check with the user
|
|
19
|
+
Check the seams with the user through the structured question tool (`AskUserQuestion`) rather than a freetext ask — one question, recommended answer first ([ADR-0029](https://github.com/wemuda/launchrail/blob/master/docs/adr/0029-planning-interaction-contract.md)): the seams as sketched, ready to write and publish. The other options are the real alternative placements you considered (a different existing seam, fewer seams, a higher one). Selecting the recommended answer flows straight into step 3 — write and publish with no further confirmation; an alternative answer re-sketches the seams and asks again. In an environment without a structured question tool, fall back to a numbered question with a ➡️ recommended answer.
|
|
18
20
|
|
|
19
21
|
3. Write the spec using the template below and publish it to **its tracker-appropriate home** — the spec's home follows the configured tracker, exactly as tickets do ([ADR-0025](https://github.com/wemuda/launchrail/blob/master/docs/adr/0025-spec-home-follows-tracker.md)). Read `docs/agents/issue-tracker.md` to know which applies:
|
|
20
22
|
|
|
@@ -23,7 +25,7 @@ This skill takes the current conversation context and codebase understanding and
|
|
|
23
25
|
|
|
24
26
|
On a real tracker, also bundle the spec under a **milestone** named for the feature: create the milestone, put the spec issue in it, and set its description to a one-line goal plus a link back to the spec issue. That milestone is the rollup `launch-tickets` hangs every ticket on, so the whole feature reads as one progress bar — a *view*, not the spec's home; the `spec`-labelled issue stays canonical. See `docs/agents/issue-tracker.md` for the exact per-tracker commands; local mode has no milestone (the feature's files are its bundle).
|
|
25
27
|
|
|
26
|
-
The spec then flows on: design validation (stage 8) revises it in place, and `launch-tickets` (stage 9) breaks it into tickets that reference it.
|
|
28
|
+
The spec then flows on: design validation (stage 8) revises it in place, and `launch-tickets` (stage 9) breaks it into tickets that reference it. Close by rendering the rail banner ([`workflow.md`](../launch/workflow.md)'s phase view) — the published spec under Done, design validation as Now, tickets as Next — with the one next command on the `➤` line.
|
|
27
29
|
|
|
28
30
|
<spec-template>
|
|
29
31
|
|
|
@@ -45,7 +47,7 @@ A LONG, numbered list of user stories. Each user story should be in the format o
|
|
|
45
47
|
1. As a mobile bank customer, I want to see balance on my accounts, so that I can make better informed decisions about my spending
|
|
46
48
|
</user-story-example>
|
|
47
49
|
|
|
48
|
-
This list of user stories should be extremely extensive and cover all aspects of the feature.
|
|
50
|
+
This list of user stories should be extremely extensive and cover all aspects of the feature *as decided* — behavior an approved prototype shows is in scope by presumption, while questions the grill deferred belong in Out of Scope, not as invented stories.
|
|
49
51
|
|
|
50
52
|
## Implementation Decisions
|
|
51
53
|
|
|
@@ -73,7 +75,7 @@ A list of testing decisions that were made. Include:
|
|
|
73
75
|
|
|
74
76
|
## Out of Scope
|
|
75
77
|
|
|
76
|
-
A description of the things that are out of scope for this spec.
|
|
78
|
+
A description of the things that are out of scope for this spec — including every question the grill deferred, each with the trigger that reopens it.
|
|
77
79
|
|
|
78
80
|
## Further Notes
|
|
79
81
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launch-tickets
|
|
3
|
-
description: Break a validated spec, plan, or the current conversation into tracer-bullet tickets
|
|
3
|
+
description: Break a validated spec, plan, or the current conversation into tracer-bullet tickets with blocking edges, published ready-for-agent to the configured tracker — the implementation loop's input.
|
|
4
4
|
disable-model-invocation: true
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -20,7 +20,7 @@ Work from whatever is already in the conversation context. If the user passes a
|
|
|
20
20
|
|
|
21
21
|
### 2. Explore the codebase (optional)
|
|
22
22
|
|
|
23
|
-
If you have not already explored the codebase, do so to understand the current state of the code. Ticket titles and descriptions should use the project's domain glossary vocabulary (`CONTEXT.md`), and respect ADRs in the area you're touching.
|
|
23
|
+
If you have not already explored the codebase, do so to understand the current state of the code. Ticket titles and descriptions should use the project's domain glossary vocabulary (`CONTEXT.md`), and respect ADRs in the area you're touching — found through the registry index (`docs/adr/README.md`), not by reading the whole directory. An ADR records a decision, not what exists: when a ticket depends on a component an ADR describes, verify in the code that it is actually built before slicing on that assumption.
|
|
24
24
|
|
|
25
25
|
Look for opportunities to prefactor the code to make the implementation easier. "Make the change easy, then make the easy change."
|
|
26
26
|
|
|
@@ -49,13 +49,12 @@ Present the proposed breakdown as a numbered list. For each ticket, show:
|
|
|
49
49
|
- **Blocked by**: which other tickets (if any) must complete first
|
|
50
50
|
- **What it delivers**: the end-to-end behaviour this ticket makes work
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
Then put the checkpoint through the structured question tool (`AskUserQuestion`) instead of freetext prose questions — one round, at most three questions, each shipping its recommended answer first ([ADR-0029](https://github.com/wemuda/launchrail/blob/master/docs/adr/0029-planning-interaction-contract.md)):
|
|
53
53
|
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
- Should any tickets be merged or split further?
|
|
54
|
+
- **Granularity** — recommended answer: publish as proposed. The other options are the concrete folds or splits you already weighed against this breakdown ("Fold #5 into #4", "Split #2"), never abstract "too coarse / too fine".
|
|
55
|
+
- **Blocking edges** — recommended answer: the edges as drawn. The other options name the specific edge to add or drop ("Make capture serial", "Let #4 start without #2").
|
|
57
56
|
|
|
58
|
-
|
|
57
|
+
Selecting the recommended answers **is** the approval — go straight to publishing (step 5), no freetext confirmation in between. An adjustment answer reshapes the breakdown: apply it, re-present what changed, and ask again. Freetext stays available through the tool's own "Other" escape, but the quick path never requires typing. In an environment without a structured question tool, fall back to the same questions as a numbered list, each carrying a ➡️ recommended answer.
|
|
59
58
|
|
|
60
59
|
### 5. Publish the tickets to the configured tracker
|
|
61
60
|
|
|
@@ -68,6 +67,10 @@ Work the **frontier**: any ticket whose blockers are all done. For a purely line
|
|
|
68
67
|
|
|
69
68
|
Do NOT close or modify any parent issue. Each new ticket is closed later by its own implementing PR (`Closes #n`, per the tracker doc's Issue ↔ PR linkage), not by hand here.
|
|
70
69
|
|
|
70
|
+
### 6. Close with the rail banner
|
|
71
|
+
|
|
72
|
+
End by rendering the banner from [`workflow.md`](../launch/workflow.md)'s phase view: the published tickets under Done (count and where they live), Build as Now, and `➤ /launch-implement` — the user-typed door — as the one next command. Never start it yourself.
|
|
73
|
+
|
|
71
74
|
<local-ticket-template>
|
|
72
75
|
|
|
73
76
|
# <NN> — <Ticket title>
|
|
@@ -18,7 +18,7 @@ Produce `docs/vision.md`: a short, honest statement of what this product is, who
|
|
|
18
18
|
## Process
|
|
19
19
|
|
|
20
20
|
1. **Read what exists.** Check for `docs/vision.md`, a README, and any notes the user points at. Do not ask questions the repository already answers.
|
|
21
|
-
2. **Interview the user** — briefly,
|
|
21
|
+
2. **Interview the user** — briefly, in their language, at most three questions per round with your recommended answer where you have one (the interaction contract in [`workflow.md`](../launch/workflow.md) applies here as everywhere):
|
|
22
22
|
- What problem hurts, and for whom? How do those people cope today?
|
|
23
23
|
- Why this, why now — what is the bet that makes this worth building?
|
|
24
24
|
- Who is the first concrete user (a person or team you could name), as opposed to the eventual market?
|
|
@@ -30,7 +30,7 @@ Produce `docs/vision.md`: a short, honest statement of what this product is, who
|
|
|
30
30
|
5. **Present and iterate** until the user approves.
|
|
31
31
|
6. **Sync the agent contract.** If the seeded `AGENTS.md` still carries the TODO under `## Project purpose`, replace it with a one-paragraph distillation of the approved vision — what this is, who it serves, what it is not. Touch only that section: `AGENTS.md` belongs to the project, and the rest of it is not this skill's business.
|
|
32
32
|
7. **Commit** `docs/vision.md` and the `AGENTS.md` update together (respect the project's commit conventions).
|
|
33
|
-
8. **Hand off
|
|
33
|
+
8. **Hand off with the rail banner.** Close with the banner from [`workflow.md`](../launch/workflow.md)'s phase view — the committed vision under Done, visual exploration (Claude Design, to make the intent concrete) as Now, discovery research (`launch-discovery`, mapping the real options for the vision's hard parts) as Next, and the grill on the Later arc — so the user sees exactly where they are and what one thing comes next.
|
|
34
34
|
|
|
35
35
|
## Template
|
|
36
36
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launch-wayfinder
|
|
3
|
-
description:
|
|
3
|
+
description: Chart work too big for one session as a shared map of decision tickets on the tracker, then resolve them one at a time until the way to the destination is clear — planning only, never execution; launch-spec synthesizes once the way is clear.
|
|
4
4
|
disable-model-invocation: true
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -12,7 +12,12 @@ The destination varies per effort, and naming it is the first act of charting
|
|
|
12
12
|
|
|
13
13
|
## Plan, don't do
|
|
14
14
|
|
|
15
|
-
Wayfinder is **planning
|
|
15
|
+
Wayfinder is **planning, only**: each ticket resolves a decision, and the map is done when the way is clear — nothing left to decide before someone goes and does the thing. **Execution never enters the map** ([ADR-0029](https://github.com/wemuda/launchrail/blob/master/docs/adr/0029-planning-interaction-contract.md)): a ticket that would *deliver* part of the destination — build the worker, ship the page, migrate the data for real — is implementation wearing a planning label, and it belongs after the spec, in `launch-tickets` and the build loop. The test, applied at creation and again if a ticket balloons: **name the decision this ticket unblocks.** No decision named, no ticket. The pull to just do the work is usually the signal you've reached the edge of the map and it's time to hand off.
|
|
16
|
+
|
|
17
|
+
Two more bounds keep the map from recursing into itself:
|
|
18
|
+
|
|
19
|
+
- **One layer of map.** A ticket never spawns its own map, and its grill never re-runs the foundation's. If a single ticket looks big enough to need either, the destination is drawn too far out — redraw this map instead.
|
|
20
|
+
- **Touch ground every two tickets.** Never resolve more than **two planning tickets in a row without a runnable or visual checkpoint** — a prototype ticket, a spike, or pausing the map to build a slice that's already safe. When charting, sequence the frontier so those checkpoints land; when working the map, track the count and force the checkpoint before the third.
|
|
16
21
|
|
|
17
22
|
## Refer by name
|
|
18
23
|
|
|
@@ -76,10 +81,10 @@ The answer isn't part of the body — it's recorded on resolution (see [Work thr
|
|
|
76
81
|
|
|
77
82
|
Every ticket is either **HITL** — human in the loop, worked _with_ a human who speaks for themselves — or **AFK**, driven by the agent alone. A HITL ticket only resolves through that live exchange; the agent never stands in for the human's side of it (a grilling agent that answers its own questions has broken this).
|
|
78
83
|
|
|
79
|
-
- **Research** (AFK): Reading documentation, third-party APIs, or local resources like knowledge bases to surface a fact a decision waits on. Resolved by a `launch-research
|
|
84
|
+
- **Research** (AFK): Reading documentation, third-party APIs, or local resources like knowledge bases to surface a fact a decision waits on. Resolved by a **subagent** that calls the Skill tool with `launch-research`. Use when knowledge outside the current working directory is required.
|
|
80
85
|
- **Prototype** (HITL): Raise the fidelity of the discussion by making a cheap, rough, concrete artifact to react to — an outline, a rough take, a stub, or throwaway UI/logic code. Links the prototype as an asset. Use when "how should it look" or "how should it behave" is the key question.
|
|
81
|
-
- **Grilling** (HITL): Conversation. The default case. Always
|
|
82
|
-
- **Task** (HITL or AFK): Manual work that must happen before a _decision_ can be made — nothing to decide, prototype, or research, but the discussion is blocked until it's done. Signing up for a service so its API can be judged, provisioning access, moving data so its shape can be seen. This is the one type that _does_ rather than decides — and it earns its place by unblocking a decision,
|
|
86
|
+
- **Grilling** (HITL): Conversation. The default case. Always call the Skill tool with `launch-grill` — the ticket's resolution comment is the artifact, in place of the grill's usual `docs/research/` doc. The ticket's question is the grill's **entire scope**, and the map's Decisions-so-far (plus the foundation's constraints) are **inherited, never re-opened** — hand the grill those settled decisions as context and a tight budget (a few decide-now questions, not a fresh session's six). A ticket grill that re-converges what the map already closed is the recursion this rule exists to stop.
|
|
87
|
+
- **Task** (HITL or AFK): Manual work that must happen before a _decision_ can be made — nothing to decide, prototype, or research, but the discussion is blocked until it's done. Signing up for a service so its API can be judged, provisioning access, moving data so its shape can be seen. This is the one type that _does_ rather than decides — and it earns its place **only** by unblocking a decision: its body names that decision (an "Unblocks:" line pointing at the ticket or fog patch that waits on it), and a task that can't name one is implementation mis-filed on the map — delivering the destination belongs after the spec, in `launch-tickets` (see [Plan, don't do](#plan-dont-do)). The agent drives it alone where it can (AFK); otherwise it hands the human a precise checklist (HITL). Resolved when the work is done; the answer records what was done and any resulting facts (credentials location, new URLs, row counts) later tickets depend on.
|
|
83
88
|
|
|
84
89
|
## Fog of war
|
|
85
90
|
|
|
@@ -110,11 +115,11 @@ Two modes. Either way, **never resolve more than one ticket per session** — wi
|
|
|
110
115
|
|
|
111
116
|
User invokes with a loose idea.
|
|
112
117
|
|
|
113
|
-
1. **Name the destination.**
|
|
114
|
-
2. **Map the frontier.** Grill again, **breadth-first** this time: fan out across the whole space rather than deep on any one thread, surfacing the open decisions and the first steps takeable now. **If this surfaces no fog** — the way to the destination is already clear, the whole journey small enough for one session — you don't need a map. Stop and ask the user how they'd like to proceed.
|
|
118
|
+
1. **Name the destination.** Call the Skill tool with `launch-grill` to pin down what this map is finding its way to — the spec, decision, or change. The destination fixes the scope, so it's settled first.
|
|
119
|
+
2. **Map the frontier.** Grill again, **breadth-first** this time: fan out across the whole space rather than deep on any one thread, surfacing the open decisions and the first steps takeable now. Both charting grills share **one session budget** — breadth-mapping is mostly triage (the agent's job: label, default, park), and the user's questions go to naming the destination and the genuinely consequential forks. **If this surfaces no fog** — the way to the destination is already clear, the whole journey small enough for one session — you don't need a map. Stop and ask the user how they'd like to proceed.
|
|
115
120
|
3. **Create the map** (label `wayfinder:map`): Destination and Notes filled in, Decisions-so-far empty, the fog sketched into **Not yet specified**.
|
|
116
121
|
4. **Create the tickets you can specify now** as child issues of the map — then wire blocking edges in a **second pass** (issues need ids before they can reference each other). Wiring sorts them into the frontier and the blocked; everything you can't yet specify stays in the fog — the **Not yet specified** section.
|
|
117
|
-
5. **Fire the research subagents.** For each `research` ticket you just created, spin up a `launch-research`
|
|
122
|
+
5. **Fire the research subagents.** For each `research` ticket you just created, spin up a subagent that calls the Skill tool with `launch-research` to resolve it in parallel, capturing its findings on a throwaway `research/<name>` branch with a context pointer from the ticket.
|
|
118
123
|
6. Stop — charting is one session's work; it hand-resolves nothing.
|
|
119
124
|
|
|
120
125
|
### Work through the map
|
|
@@ -123,8 +128,9 @@ User invokes with a map (URL or number). A ticket is **optional** — without on
|
|
|
123
128
|
|
|
124
129
|
1. Load the **map** — the low-res view, not every ticket body.
|
|
125
130
|
2. Choose the ticket. If the user named one, use it. Otherwise take the first frontier ticket in order. **Claim it**: assign it to yourself before any work.
|
|
126
|
-
3. Resolve it — **zoom as needed**: fetch the full body of any related or closed ticket on demand;
|
|
131
|
+
3. Resolve it — **zoom as needed**: fetch the full body of any related or closed ticket on demand; call the Skill tool for whichever skills the `## Notes` block names. If in doubt, `launch-grill`.
|
|
127
132
|
4. Record the resolution: post the answer as a **resolution comment**, **close** the issue, and **append a context pointer** to the map's Decisions-so-far.
|
|
128
133
|
5. Add newly-surfaced tickets (create-then-wire); graduate any fog the answer has made specifiable, clearing each graduated patch from **Not yet specified** so it lives only as its new ticket. If the answer reveals a ticket — this one or another — sits beyond the destination, **rule it out of scope** rather than resolving it on the route. If the decision invalidates other parts of the map, update or delete those tickets.
|
|
134
|
+
6. **Close legibly.** End the session with the rail banner and the four-block summary — **Locked** (this resolution), **Provisional**, **Deferred**, **Next command** (the next frontier ticket by name, the checkpoint now due, or the handoff once the way is clear) — per [`workflow.md`](../launch/workflow.md)'s phase view. Check the checkpoint count here: if this was the second planning ticket since the last runnable or visual checkpoint, the next move is the checkpoint, not another ticket.
|
|
129
135
|
|
|
130
136
|
The user may run unblocked tickets in parallel, so expect other sessions to be editing the tracker concurrently.
|
package/dist/commands/add.js
CHANGED
|
@@ -107,6 +107,7 @@ function planRalph(parsed) {
|
|
|
107
107
|
"Produce tickets with explicit `Blocked by: #n` edges and the ready-for-agent label (launch-tickets, stage 9 of the workflow).",
|
|
108
108
|
"Start building: /launch-implement in Claude Code drives the ready tickets to verified merges (add a ticket number to build just one).",
|
|
109
109
|
"For an unattended run, launch in a non-prompting permission mode (bypass/autonomous) — a guard hook warns if you start Ralph in an interactive mode, since one benign prompt can stall a walk-away run.",
|
|
110
|
+
"Name a fast gate as testing.checkCommand in .launchrail.yml (lint + typecheck + quick unit tests) — the loop runs `verify --fast` before every land and the full `verify` at its checkpoints; without it the fast gate is the unit command.",
|
|
110
111
|
"Start with width 1 until a few tickets have landed cleanly, then widen.",
|
|
111
112
|
],
|
|
112
113
|
};
|
|
@@ -150,7 +151,7 @@ export async function runAdd(opts) {
|
|
|
150
151
|
const lockBefore = JSON.stringify(lockfile);
|
|
151
152
|
const specs = [
|
|
152
153
|
...plan.specs,
|
|
153
|
-
claudeGeneratedFile({ projectName: detection.projectName, manifest: plan.manifest, launchrailVersion: VERSION }),
|
|
154
|
+
claudeGeneratedFile({ projectName: detection.projectName, manifest: plan.manifest, launchrailVersion: VERSION, cwd: opts.cwd }),
|
|
154
155
|
];
|
|
155
156
|
const actions = planWrites(opts.cwd, specs, lockfile);
|
|
156
157
|
// Ralph's guard hook file rides `actions`; its registration in the shared,
|