用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/meridian-online/orbit --skill rally命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
基于 SOC 职业分类
| name | rally |
| description | Coordinate multiple cards through the orbit pipeline as one delivery — proposal → design → implementation → review |
| argument-hint | [card-id-1 card-id-2 ...] [autonomy] |
| allowed-tools | Bash Read Edit Write Agent AskUserQuestion TaskCreate TaskUpdate CronCreate CronList CronDelete |
Drive multiple independent cards through the orbit pipeline as a coordinated rally. A rally packs the human work into two high-signal gates (ideation and assurance) and lets the agent work between them with maximum clarity from the best available evidence — instead of paying a per-card touchpoint tax for design, spec, review, and PR. State lives in rally.yaml at proposal-approval time; the children array encodes the implementation order via dep_predecessors. Individual cards run /orb:drive <spec-id> in full autonomy (serially in the main checkout, or in parallel inside isolated worktrees).
/orb:rally <goal_string> [guided|supervised] # fresh rally from a goal
/orb:rally <rally-id> # resume an existing rally (id matches `<date>-<slug>-rally`)
/orb:rally # resume the unique in-progress rally, if any
goal_string — a short description of the subsystem, theme, or
objective binding the cards together (e.g. "pipeline runtime readiness", "review workflow hardening")| Level | Behaviour |
|---|---|
| guided | Proposal and consolidated decision gate are interactive. Reviews serve as quality gates — no intermediate supervision between design and implementation. Default. |
| supervised | Same as guided plus explicit pauses after each rally phase (design, review, implementation, PR) for author greenlight. |
full autonomy is not offered — rally's value comes from sharper
human gates, not fewer.
Rally-level vs drive-level autonomy. Rally-level autonomy (guided | supervised) governs pauses between rally phases — proposal, consolidated decision gate, consolidated design review, batched diff review. Drive-level autonomy inside a rally is always full, both for parallel sub-agents running in worktrees and for serial cards running in the main checkout.
The skill operates on exactly one rally per session. Resolution proceeds in three branches:
Goal string provided (/orb:rally <goal_string> [autonomy]).
Run §pre-flight (scan-for-active-rally + thin-card guard), then
§Stage 1 (Proposal).
Rally id provided (/orb:rally <rally-id>, where the id
matches <date>-<slug>-rally). Validate that
.orbit/specs/<rally-id>/rally.yaml exists and its phase is not
complete; if not, halt and instruct the agent to start a fresh
rally. Otherwise, resume from the phase named in phase field.
No argument — query for in-progress rallies:
for f in .orbit/specs/*/rally.yaml; do
[[ -f "$f" ]] || continue
phase=$(yq -r '.phase // ""' "$f")
[[ "$phase" != "complete" && -n "$phase" ]] && basename "$f" .rally.yaml
done
Rally sub-agents run drive at full autonomy inside their worktrees;
the rally lead runs in main and gates only at proposal, consolidated
decisions, consolidated design review, and assurance. Both surfaces
honour the three-question test before invoking AskUserQuestion:
recommendation? evidence? authorisation? Three yeses → act, do not
ask. See plugins/orb/skills/drive/SKILL.md §"Halt-temptation guard"
for the substrate-typed phrasing and the PreToolUse hook that
reinforces it under ORBIT_NONINTERACTIVE=1. Per spec
2026-05-19-act-when-authorised.
Before launching a fresh rally, the input-contract resolution above
already ensures no in-progress rally exists. The skill never launches
a second rally over a first. If a stale rally is the problem, close it
explicitly by setting phase: complete in its rally.yaml before
starting a fresh rally.
One active rally at a time is non-negotiable. Children-graph orchestration loses its meaning if two rallies overlap on cards.
Before the proposal is presented to the author, check the scenario count on every candidate card. If any candidate has fewer than 3 scenarios, the proposal refuses to proceed:
Rally cannot proceed — the following candidate card is too thin:
.orbit/cards/0017-<slug>.yaml — 2 scenarios
Thicken this card via `/orb:card .orbit/cards/0017-<slug>.yaml` or remove it from
the rally list before continuing.
The author may then:
/orb:card on the thin card to thicken it, re-invoke rally/orb:drive <card> guided or
supervised (rally is not the venue for thin cards)The thin-card refusal is unconditional on the eventual serial-or- parallel outcome. The guard runs before the proposal is shown and before the post-design disjointness check (§Stage 4) — it is a pre-qualification gate, not a runtime decision. No silent downgrade.
Parse the goal string from $ARGUMENTS[0] and autonomy from
$ARGUMENTS[1] (default guided).
Scan .orbit/cards/ for candidate cards:
.orbit/cards/*.yamlfeature, goal, scenarios, and referencesRun the §thin-card guard against the candidate list before showing anything to the author. If any candidate is thin, halt per the guard.
The proposal surface has two strict halves: a markdown preview block that carries the evidence (per-card rationale), and an AskUserQuestion that carries the decision (three canonical, terse options). They are not collapsed — the preview block scales with N cards while the AskUserQuestion stays short and action-focused.
Preview block (markdown, above the AskUserQuestion) — owns per-card rationale:
## Rally Proposal — <goal string>
Candidate cards:
1. .orbit/cards/<id>-<slug>.yaml — <feature line>
Rationale: <why this card fits the goal>
2. .orbit/cards/<id>-<slug>.yaml — <feature line>
Rationale: <why this card fits the goal>
...
Autonomy: <guided|supervised>
AskUserQuestion — owns the decision. Exactly three canonical
options in this order. The description field for each option is a
one-line action summary — it describes the action, not the cards.
Per-card rationale must not appear in these descriptions (the preview
block already owns it).
approve-all — Proceed with all N candidatesmodify-list — Add or remove cards before proceedingdecline — Abort the rally; offer individual drive as alternativeOn approve-all: proceed to §Create the rally (below).
On decline: abort the rally and offer individual /orb:drive
invocations as the alternative.
On modify-list: the lead issues exactly one follow-up
AskUserQuestion with no pre-populated options (free-form only).
The prompt text reads:
Name cards to add (by path, e.g.
.orbit/cards/0019-foo.yaml) or remove (by number, e.g.2). Empty response cancels the modification and returns to the approval prompt.
An empty response cancels the modification and re-presents the unchanged candidate list with the same three canonical options. A non-empty response is interpreted as modification instructions.
Modify loop — sequence per iteration:
Invariant: no candidate list is shown to the author unless it has passed the thin-card guard in the current loop iteration. The author never decides against a list that cannot fly.
Guard re-runs inside the modify loop are pre-qualification retries — they are not rally-level strikes and do not count against any escalation budget.
The loop continues — verdict → (modify instructions → apply →
re-guard → re-present) → verdict → … — until the author returns
approve-all or decline.
The proposal gate is the only pre-design independence check. The agent's scan proposes; the author's approval qualifies. Do not attempt a lightweight heuristic disjointness check — the definitive check happens after designs exist (§Stage 4).
On approve-all:
# 1. Derive a rally slug and id from the goal string
SLUG=$(echo "<goal string>" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]\+/-/g; s/^-//; s/-$//' | cut -c1-40)
RALLY_ID="$(date -I)-${SLUG}-rally"
# 2. Promote each card to a spec
declare -a CHILDREN_YAML
for CARD in "${APPROVED_CARDS[@]}"; do
CARD_SLUG=$(basename "$CARD" .yaml)
SPEC_ID=$(orbit spec promote "$CARD")
CHILDREN_YAML+=("- card_path: $CARD")
CHILDREN_YAML+=(" spec_id: $SPEC_ID")
CHILDREN_YAML+=(" branch: rally/${CARD_SLUG#*-}")
CHILDREN_YAML+=(" card_phase: proposed")
CHILDREN_YAML+=(" dep_predecessors: []")
CHILDREN_YAML+=(" worktree: null")
CHILDREN_YAML+=(" rally_id: $RALLY_ID")
done
# 3. Write the rally sidecar at .orbit/specs/<rally-id>/rally.yaml
cat > ".orbit/specs/$RALLY_ID/rally.yaml" <<EOF
rally_id: $RALLY_ID
goal: <goal string>
autonomy: <guided|supervised>
phase: approved
started: $(date -Iseconds)
completed: null
children:
$(printf '%s\n' "${CHILDREN_YAML[@]}")
EOF
Per-child design artefacts (decisions.md, interview.md) are written as
sidecars at .orbit/specs/<child-spec-id>/decisions.md and
.orbit/specs/<child-spec-id>/interview.md. The rally itself does not
create folders.
The phase field advances through: approved → designing →
design-review → implementing → complete. Each transition is a
single rally.yaml.phase rewrite (the lead reads, mutates, writes).
rally.yaml.children lists every card-spec in the rally. The
claimable set is derived from this array:
A child is claimable when its
card_phaseisproposedordesigned(depending on the rally phase) AND every spec id indep_predecessorsbelongs to a child whosecard_phaseiscompleteorparked.
The lead computes this set on every queue tick — there is no separate
bd ready query.
This is the rally's central innovation. The goal: present the author with executive-ready decisions in a single consolidated gate, with options + trade-offs + recommendations drawn from the best available evidence — not raw questions they lack context to answer.
Principle: The goal of rally is to have the highest quality interactions at ideation and assertion. This means maximum clarity based on the best available evidence. Agent work between gates exists to make the next gate sharper — not just faster.
# Update rally.yaml: phase: designing
# Update each child: card_phase: designing
Design sub-agents write to the main checkout. Using the Agent tool, one call per card, all in the same message for parallelism. Each sub-agent receives a self-contained brief:
You are a design analyst for card <card_path> (spec <child-spec-id>).
Produce a decision pack.
Read your spec via `orbit --json spec show <child-spec-id>` to confirm
the card linkage. The two sidecar paths you may write to are:
- decisions: `.orbit/specs/<child-spec-id>/decisions.md`
- interview: `.orbit/specs/<child-spec-id>/interview.md` (Stage 3 re-launch)
Your job:
1. Read the card (<card_path>) and its references
2. Read prior specs in the card's `specs` array (if any)
3. Run a keyword scan on the codebase using terms from the card's goal and scenarios
4. Identify the 4–6 design decisions that this card's implementation requires
For each decision, produce:
- Title (one line, describes the choice)
- Context (1–2 sentences — why this decision exists)
- Options (2–3 concrete alternatives)
- Trade-offs (what each option gains, what it loses — grounded in evidence from the card, prior specs, or codebase)
- Recommendation (which option and why, citing the evidence)
Do NOT run interactive Q&A. Do NOT call AskUserQuestion. You produce a written decision pack that the lead agent will present to the author.
Write your decision pack to: `.orbit/specs/<child-spec-id>/decisions.md`
Do NOT write to any path other than the two named sidecars above.
Do NOT read or write any rally-coordination state. The lead owns the
rally sidecar (`.orbit/specs/<rally-id>/rally.yaml`) exclusively.
When done, return a JSON object with this shape (and nothing else):
{ "files": [".orbit/specs/<child-spec-id>/decisions.md", ...any other paths you wrote...] }
Path discipline is trust + post-verify. The brief names the target directory as a convention the sub-agent is expected to honour. The lead verifies on return via three primitives (§2c). Claude Code does not provide a tool-level path prefix guard, so the lead takes responsibility for the check; the brief takes responsibility for the contract.
Before launching each design sub-agent, the lead captures a pre-snapshot of the main checkout:
git status --porcelain > /tmp/rally-pre-<card-slug>.snap
After the sub-agent returns, the lead runs all three checks:
files list. If the JSON is missing or malformed, reject..orbit/specs/<child-spec-id>/decisions.md exists; assert every
path in the returned list matches one of the two named sidecars
(<child-spec-id>/decisions.md or <child-spec-id>/interview.md).git status --porcelain) and compute the set
difference post \ pre. Any entry in that difference that is not
one of the two named sidecars rejects the sub-agent's output. There
is no lead-owned allowlist beyond those two sidecars — rally state
lives in the rally sidecar .orbit/specs/<rally-id>/rally.yaml,
which the lead alone touches. Entries present in both pre and post
are pre-existing lead-side state and are ignored.On the first violation: re-brief the same sub-agent with an
explicit path warning naming the offending entry (e.g. your previous return created 'plugins/orb/scratch.md' which is not one of the two named sidecars; write only to .orbit/specs/<child-spec-id>/decisions.md or .orbit/specs/<child-spec-id>/interview.md). This re-brief is a
pre-qualification retry — NOT a rally-level strike.
On the second violation for the same card: park via the
rally.yaml.children[].card_phase=parked + orbit spec note + orbit spec close flow with reason_label: tool_surface_incomplete (see
§NO-GO Handling). The rally continues with the remainder.
For each non-parked child, update rally.yaml:
# children[i]: card_phase: designed
Once all packs are in (or parked), advance the rally:
# rally.yaml: phase: design-review
Read all decision packs. Present them to the author grouped by card, in a single consolidated response:
## Consolidated Decision Gate — <N> cards
### Card: <card feature> (<card_path>)
Spec: <child-spec-id>
#### Decision 1: <title>
Context: <context>
Options:
A. <option>
B. <option>
C. <option>
Trade-offs:
A: gains <x>, loses <y>
B: gains <x>, loses <y>
C: gains <x>, loses <y>
Recommendation: B — <rationale>
#### Decision 2: <title>
...
### Card: <next card>
...
Use AskUserQuestion per card to capture approvals and overrides. For each card, the author either accepts the recommendations wholesale or names specific overrides (e.g. "card 2 decision 3: option A instead of C"). Record every override explicitly — these flow into the interview.
Re-launch each sub-agent (or have the lead agent write directly —
whichever is cheaper) with its decisions + the author's
approvals/overrides. The sub-agent writes
.orbit/specs/<child-spec-id>/interview.md following the design
skill's interview record format, reflecting the approved decisions.
Re-launched sub-agents are subject to the same three-primitive verification as §2c (first violation → re-brief retry; second violation → park).
When all interviews exist, the rally moves on to Stage 4.
Once all interviews exist, present them to the author in a single session:
## Consolidated Design Review — <N> cards
1. Card: <name> — .orbit/specs/<child-spec-id>/interview.md
Goal: <goal>
Key decisions: <one-liners>
2. Card: <name> — .orbit/specs/<child-spec-id>/interview.md
Goal: <goal>
Key decisions: <one-liners>
Extract from each interview:
plugins/orb/skills/foo/SKILL.md)Compute the intersection. Any non-empty intersection is a hard input to implementation ordering — it gates, not advises.
Shared symbols detected:
- Engine trait — referenced by <card A> and <card C>
- .orbit/specs/.../hook.sh — both <card B> and <card C> modify it
Proposed implementation order: <card A> → <card C> → <card B>
Rationale: Card A establishes the Engine trait; card C extends it; card B depends on the hook update card C ships.
Use AskUserQuestion to confirm or modify the order. On confirm, encode
the order via rally.yaml.children[].dep_predecessors — for each
ordered pair (earlier, later):
# children[<later-index>].dep_predecessors: [<earlier-spec-id>]
The claimable-set rule (§Stage 1 "Create the rally") will then surface only the head of the chain at any moment, releasing the next card as each predecessor closes.
No shared symbols detected — parallel implementation is safe.
Rationale: Each design names disjoint files and types.
No dep_predecessors entries. Every child whose card_phase is
designed is claimable simultaneously, ready for parallel claim.
# rally.yaml: phase: implementing
Supervised mode gate: If autonomy is supervised, pause for
greenlight before proceeding to implementation.
Investigation fires at the routed stage, not here. Per choice 0029
(pipeline-orchestrates-investigation), each rally child runs /orb:drive,
which routes into /orb:implement / /orb:review-spec / /orb:review-pr
— those routed skills orchestrate /orb:code-investigate themselves.
Rally does not add an orchestrator-level investigation step.
The implementation queue is the claimable set computed from
rally.yaml.children (§Stage 1 rule). The shape of the queue
(single-head chain vs flat fan-out) is determined entirely by the
dep_predecessors arrays from §Stage 4. Rally does not maintain a
parallel queue structure — the children array IS the queue.
For each non-parked child, commit
.orbit/specs/<child-spec-id>/interview.md to the card's rally branch
as a clean first commit. This is git hygiene — the rally branch tells
the card's story in chronological order — and is independent of how
/orb:drive resumes.
# on main
git checkout -b rally/<slug> # or: git checkout rally/<slug>
git add ".orbit/specs/${CHILD_SPEC}/interview.md"
git commit -m "rally/<slug>: approved design"
git checkout main
When dep_predecessors arrays are non-empty, the claimable set returns exactly one card at a time. The lead loops:
card_phase is designed or implementing AND every entry in
dep_predecessors belongs to a child whose card_phase is
complete or parked).NEXT. If the set is empty, the
serial pass is done.rally.yaml: children[NEXT].card_phase=implementing, worktree=main.BRANCH=$(yq -r ".children[] | select(.spec_id == \"$NEXT\") | .branch" ".orbit/specs/${RALLY_ID}/rally.yaml")./orb:drive <NEXT> (which resumes from
drive.yaml's stage and closes the spec on APPROVE), then return to
main.card_phase becomes complete or
parked).Each serial card runs drive-full against the rally branch in the main checkout — rally-level autonomy does not reduce drive's internal autonomy.
When no dep_predecessors arrays are populated, the claimable set
returns all designed cards. Launch N implementation sub-agents
concurrently, each in its own git worktree.
For each card:
SLUG=$(yq -r ".children[] | select(.spec_id == \"$CHILD_SPEC\") | .branch" ".orbit/specs/${RALLY_ID}/rally.yaml" | awk -F/ '{print $NF}')
WORKTREE_PATH="$(realpath ..)/$(basename "$(pwd)")-rally-$SLUG"
git worktree add "$WORKTREE_PATH" "rally/$SLUG"
# Update rally.yaml: children[CHILD_SPEC].card_phase=implementing, worktree=$WORKTREE_PATH
Then, in a single message, spawn all N sub-agents via the Agent tool
with run_in_background: true:
# Sub-agent brief (parallel implementation)
You are an implementation agent for spec <child-spec-id>. Your working
directory is <worktree path>. Run `/orb:drive <child-spec-id>` inside
that worktree. Drive will:
1. Resume from .orbit/specs/<child-spec-id>/drive.yaml stage (or initialise it if absent)
2. Run review-spec → implement → review-pr internally as forked Agents
3. Close the spec via orbit spec close on APPROVE
4. Or escalate if iteration / review budgets exhaust
Do NOT read or write the rally sidecar. The lead owns
`.orbit/specs/<rally-id>/rally.yaml` exclusively. You may read your own
spec via `orbit --json spec show <child-spec-id>` and update your own
`.orbit/specs/<child-spec-id>/drive.yaml` as drive normally does.
When drive completes (APPROVE at review-pr), return a JSON object:
{ "verdict": "complete", "pr": "<pr-number-or-url>", "spec_id": "<child-spec-id>" }
If drive escalates, return:
{ "verdict": "parked", "reason_label": "<label>", "reason": "<one-line>",
"spec_id": "<child-spec-id>" }
where `reason_label` is one of the six fixed tokens (see §NO-GO):
budget | recurring_failure | contradicted_hypothesis | diminishing_signal | review_converged | tool_surface_incomplete
Do not attempt rally-level retries — your internal drive iterations are the
strike.
The Agent tool is invoked with run_in_background: true and
subagent_type: "general-purpose"; every call is in the same message
so the harness dispatches all N in parallel.
Recursive context separation. Each parallel sub-agent runs
/orb:drive inside its worktree. Drive's review-spec and review-pr
stages themselves run as nested forked Agents — the same context-
separation pattern drive uses at its top level. Rally does not invoke
reviewers directly; drive does, once per stage per cycle.
Parallel completion handling — Agent-return await (no polling, no
sentinels). The lead awaits each sub-agent's completion via the
Agent tool's built-in background-completion notification. The harness
surfaces the sub-agent's final message as the lead's next turn event
— no sleep, no polling loop, no Monitor call, no sentinel file.
On each completion:
complete: the child spec is already closed by drive. Update
rally.yaml.children[CHILD_SPEC].card_phase=complete (idempotent
— no-op if already set).parked: handle per §NO-GO Handling.If parallel implementation surfaces a shared-symbol contention mid-flight (e.g. two in-progress sub-agents about to touch the same file), the lead serializes by adding a single dep_predecessors entry:
# children[<later-index>].dep_predecessors: [<earlier-spec-id>]
The claimable-set rule will then withhold <later> from new claim
until <earlier> closes. In-progress work continues. The runtime
change is the queue, not the running cards. No sub-agent restart, no
rally-coord mutation beyond the single dep edge — the rally.yaml edit
is the operation.
If a sub-agent has not yet started (still queued by the harness), adding the edge prevents it from starting. If the sub-agent has already started, the lead may either (a) let both finish if the contention is mild, or (b) ask the later sub-agent to halt and re-claim once its predecessor closes (sub-agent honours the request via its own halt path).
A NO-GO verdict at any stage (drive's spec review BLOCK, supervised gate NO-GO, drive's PR review BLOCK, or drive-full escalation from a parallel sub-agent) parks the card immediately. No iteration retries within the rally. Rally is about throughput; retrying one card while others wait defeats the purpose.
Drive escalations from a sub-agent surface as the parked-verdict JSON
defined in the §5c sub-agent brief ({verdict, reason_label, reason, spec_id}). Rally lead converts that into:
orbit spec note <child-spec-id> "PARKED: [<reason_label>] <reason>"
orbit spec close <child-spec-id>
# Update rally.yaml: children[CHILD_SPEC].card_phase=parked, park_reason="PARKED: [<reason_label>] <reason>"
The reason_label vocabulary is preserved (six fixed tokens):
Drive escalation trigger reason_label
---------------------------------------------+----------------------
Budget exhausted (3 NO-GO iterations) budget
Recurring failure mode recurring_failure
Contradicted hypothesis contradicted_hypothesis
Diminishing signal diminishing_signal
Synthetic BLOCK after 3× REQUEST_CHANGES review_converged
Agent tool unavailable for cold-fork tool_surface_incomplete
An unrecognised or missing reason_label in the sub-agent's JSON
return parks the card with the literal string [unknown] prefixed —
the card is still parked, and the label drift becomes visible in the
spec note for later investigation.
Rally does not retry at its level; the sub-agent's internal iterations (drive's 3-iteration NO-GO budget plus each stage's 3-cycle REQUEST_CHANGES budget) are the strike.
The parked card can be driven individually later with /orb:drive <card_path>, where its full 3-iteration budget applies (a fresh
drive starts a new spec chain). The rally continues with remaining
cards.
Each card's PR targets the previous non-parked card's branch:
main
└── rally/card-a [PR #101 → main]
└── rally/card-c [PR #102 → rally/card-a]
└── rally/card-b [PR #103 → rally/card-c]
If a middle card is parked, subsequent PRs target the last
non-parked card's branch. E.g. if card C is parked in the stack
above, card B's PR targets rally/card-a, not rally/card-c.
The lead computes "last non-parked predecessor" by walking the
dep_predecessors chain and skipping any child whose card_phase is
parked.
Present the stack to the author bottom-up for review.
Each sub-agent creates an individual PR against main. The lead presents them together:
## Rally PR Review — <N> PRs ready
PR #201 — <card A feature>
Spec: .orbit/specs/<child-spec-id>/spec.yaml (<N> ACs)
Files changed: <count>
Review verdict: APPROVE — <one-line honest assessment>
PR #202 — <card B feature>
...
Author reviews in a single session.
When every entry in rally.yaml.children has card_phase either
complete or parked:
Write completion summary:
## Rally Complete — <goal string>
Duration: <started> → <now>
Autonomy: <autonomy>
Completed: <N> card(s)
- <card feature> — PR #<n>
- <card feature> — PR #<n>
Parked: <N> card(s)
- <card feature> — park_reason: PARKED: [<label>] <reason>
Implementation order: <serial chain order OR "parallel">
Rationale: <derived from dep_predecessors graph, or "no shared symbols" for parallel>
PRs:
- #<n>: <title> (<target branch>)
- #<n>: <title> (<target branch>)
Mark rally complete:
# rally.yaml: phase: complete
# rally.yaml: completed: $(date -Iseconds)
No archival step. The rally sidecar
(.orbit/specs/<rally-id>/rally.yaml) and the per-child
.decisions.md / .interview.md sidecars stay where they are —
they remain on disk as the design + orchestration record. When the
next rally begins, it writes its own sidecar alongside these.
These are invariants — not duplicates of the body. The body describes what to do at each step; these rules describe what must always hold, and what must never happen, regardless of where in the rally you are.
*.rally.yaml with
phase != complete). Children-graph orchestration loses meaning if
two rallies overlap on cards..orbit/specs/<rally-id>/rally.yaml.
Sub-agents never read or write the rally sidecar — they read
their own spec and update their own drive sidecar
(.orbit/specs/<child-spec-id>/drive.yaml). The lead alone touches
the rally sidecar./orb:drive <card_path>.When /orb:rally is invoked with a rally id (or detects an
in-progress rally per §Input contract):
Read the rally sidecar: .orbit/specs/<rally-id>/rally.yaml. Extract:
phaseautonomystarted, completedchildren[]For each child: the spec id, card_path, branch, card_phase,
dep_predecessors, worktree are all in the children array.
Cross-reference each child's spec status via orbit spec show <child-spec-id> if a freshness check is needed (the spec may have
been closed since the rally sidecar's last write).
Resume at the named phase. The rally sidecar is the source of truth — there is no separate state to scan or reconcile.
| phase | Resume at |
|---|---|
approved | §Stage 2 (decision packs not yet launched) |
designing | §Stage 2 (some decision packs may be returned) |
design-review | §Stage 3 (decision gate / interview production) |
implementing | §Stage 5 (queue replay via claimable-set rule) |
complete | Already done — report status |
For implementing-phase resume: the lead does not reconstruct
per-card sub-stage from any side file — each implementing child
resumes via /orb:drive <child-spec-id> which itself reads
.orbit/specs/<child-spec-id>/drive.yaml's stage field. Rally's
job at resume is only to (a) re-launch sub-agents for any child
whose card_phase=implementing and whose spec is still open,
(b) honour the claimable-set rule for serial flows, and (c) await
completions for any sub-agent that was running before the session
died.
Announce the resumption in one block: rally id, goal, phase, child counts (proposed / complete / parked / in progress), and per-child resume points (spec id, worktree, drive stage if implementing).
Next step: After completion, review all PRs in the order recommended by the assurance strategy (stacked bottom-up or batched together).