@catalyst-cloud/cli 0.13.1 → 0.14.1

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.
Files changed (44) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +2 -2
  3. package/dist/args.js +291 -69
  4. package/dist/capabilities.js +2 -0
  5. package/dist/cli.js +109 -17
  6. package/dist/config.js +3 -1
  7. package/dist/env/draft.js +134 -0
  8. package/dist/env/legacy.js +54 -0
  9. package/dist/env/parse-env.js +50 -0
  10. package/dist/env/settings-toml.js +66 -0
  11. package/dist/env.js +126 -26
  12. package/dist/legacy.js +16 -17
  13. package/dist/onboard-consent.js +65 -0
  14. package/dist/onboard.js +836 -0
  15. package/dist/project.js +75 -13
  16. package/dist/ready.js +11 -1
  17. package/dist/secret.js +24 -3
  18. package/dist/var.js +118 -0
  19. package/package.json +3 -2
  20. package/skills/catalyst-github/SKILL.md +1 -1
  21. package/skills/catalyst-linear/SKILL.md +1 -1
  22. package/skills/catalyst-onboard/SKILL.md +1 -1
  23. package/skills/catalyst-onboard/references/declaring-a-repository.md +19 -12
  24. package/skills/catalyst-onboard/references/reading-ready.md +1 -1
  25. package/skills/catalyst-onboard/references/the-one-path.md +4 -4
  26. package/skills/catalyst-onboard/references/what-the-browser-owns.md +2 -2
  27. package/skills/catalyst-onboard/scripts/lib/project-coverage.mjs +53 -0
  28. package/skills/catalyst-onboard/scripts/where-am-i.mjs +885 -196
  29. package/skills/run-this-project/SKILL.md +1 -1
  30. package/skills/unstick/SKILL.md +1 -1
  31. package/skills/what-needs-me/SKILL.md +1 -1
  32. package/skills/what-this-repo-needs/SKILL.md +4 -4
  33. package/skills/what-this-repo-needs/scripts/check.mjs +12 -13
  34. package/skills/whats-happening/SKILL.md +19 -35
  35. package/skills/whats-happening/references/coding-accounts.md +6 -19
  36. package/skills/whats-happening/references/routing-work.md +4 -15
  37. package/skills/whats-happening/references/settings-and-where-they-live.md +15 -18
  38. package/skills/whats-happening/references/stages-and-mapping.md +12 -18
  39. package/skills/whats-happening/references/status-reply.md +11 -29
  40. package/skills/whats-happening/references/the-ladder.md +15 -25
  41. package/skills/whats-happening/references/what-runs-next.md +7 -26
  42. package/skills/whats-happening/references/when-a-phase-fails.md +16 -22
  43. package/skills/whats-happening/references/why-is-it-stuck.md +38 -48
  44. package/dist/env/declaration-rules.js +0 -163
@@ -4,7 +4,7 @@ description: >-
4
4
  Own one Catalyst Cloud project end to end until it closes. Use when the person says "run this project for me", "own this until it ships", "keep this moving", or hands you a project id or a set of tickets to drive. Subscribes to the account's event stream for the scope through the catalyst CLI, reacts to each change in the same turn, makes tickets ready and moves them to dispatch, parks what should stop, chases stalls, escalates inward, and keeps one status summary current. Writes to Linear as the app actor; never polls.
5
5
  allowed-tools: Bash(catalyst:*) Bash(npx -p @catalyst-cloud/cli catalyst:*)
6
6
  ---
7
- <!-- vendored-from: @catalyst-cloud/catalyst-skills@0.13.1 — written in this repository for customer accounts -->
7
+ <!-- vendored-from: @catalyst-cloud/catalyst-skills@0.14.1 — written in this repository for customer accounts -->
8
8
 
9
9
  # Run this project
10
10
 
@@ -4,7 +4,7 @@ description: >-
4
4
  Get a stuck Catalyst Cloud ticket moving again. Use when the person asks "why is this parked and can you release it?", "unpark this", "get things flowing again", "the outage is over, retry what failed", or hands you a ticket that is not moving. Reads why nothing runs and what holds the ticket through the catalyst CLI, decides whether the recorded cause is fixed, previews the release, releases every governor holding the ticket the right way (or one failure class across a team), and raises an ask only for what a person has to do. Never releases a cause it cannot show changed without saying so.
5
5
  allowed-tools: Bash(catalyst:*) Bash(npx -p @catalyst-cloud/cli catalyst:*)
6
6
  ---
7
- <!-- vendored-from: @catalyst-cloud/catalyst-skills@0.13.1 — written in this repository for customer accounts -->
7
+ <!-- vendored-from: @catalyst-cloud/catalyst-skills@0.14.1 — written in this repository for customer accounts -->
8
8
 
9
9
  # Unstick
10
10
 
@@ -4,7 +4,7 @@ description: >-
4
4
  The human's decision inbox on Catalyst Cloud, and the one way an agent raises a decision on their behalf. Use when the person asks "what needs me?", "what am I blocking?", or when active work is gated on a choice only they can make. Lists open asks ranked by how much open work each one holds, files an ask through the cloud's ask route with the account's own template, and records the answer so the held work releases. Never answers as the human, never duplicates an open ask.
5
5
  allowed-tools: Bash(catalyst:*) Bash(npx -p @catalyst-cloud/cli catalyst:*)
6
6
  ---
7
- <!-- vendored-from: @catalyst-cloud/catalyst-skills@0.13.1 — written in this repository for customer accounts -->
7
+ <!-- vendored-from: @catalyst-cloud/catalyst-skills@0.14.1 — written in this repository for customer accounts -->
8
8
 
9
9
  # What needs me
10
10
 
@@ -1,10 +1,10 @@
1
1
  ---
2
2
  name: what-this-repo-needs
3
3
  description: >-
4
- What environment variable names does this repository need, and where does each one come from? Scans the repository offline (no login, no network) and lists the names in three groups (build/test, deploy-only, bindings), each with where it was found, what uses it, and where a local value would come from. Never reads or prints a value. Also validates a catalyst.env.json file the same way the cloud does. Use when someone asks "what does catalyst.env.json mean", "what env vars does this repo need", "why does the container need this", or before reviewing or writing a repository's environment declaration.
4
+ What environment variable names does this repository need, and where does each one come from? Scans the repository offline (no login, no network) and lists the names in three groups (build/test, deploy-only, bindings), each with where it was found, what uses it, and where a local value would come from. Never reads a value or prints one. Also checks the environment variable table in `.catalyst/catalyst.toml` offline. Use when someone asks "what does catalyst.env.json mean", "what env vars does this repo need", "why does the container need this", or before reviewing or writing the declaration.
5
5
  allowed-tools: Bash(catalyst:*) Bash(npx -p @catalyst-cloud/cli catalyst:*)
6
6
  ---
7
- <!-- vendored-from: @catalyst-cloud/catalyst-skills@0.13.1 — written in this repository for customer accounts -->
7
+ <!-- vendored-from: @catalyst-cloud/catalyst-skills@0.14.1 — written in this repository for customer accounts -->
8
8
 
9
9
  # What this repository needs
10
10
 
@@ -13,7 +13,7 @@ Say this first, in your own words, before you scan: the fleet builds and tests t
13
13
  ## Run first
14
14
 
15
15
  - `node scripts/inventory.mjs [path] --help`: scans the repository (default: here) and prints the names in three groups: build/test, deploy-only, bindings. Each name shows where it was found (file:line), what uses it, and where a local value would come from: a `.env` file, your shell, a CI secret, or a Cloudflare binding. `--json` gives the same data in machine form.
16
- - `node scripts/check.mjs <file> --help`: validates an existing `catalyst.env.json` offline with the cloud's rules, and never prints a value from it either.
16
+ - `node scripts/check.mjs [path] --help`: checks TOML syntax and the environment variable table in `.catalyst/catalyst.toml` (default) or the repo-relative path you name. It never reads or prints a variable value. The old root JSON declaration is not read by the cloud.
17
17
 
18
18
  Then ask the person to review the grouped list: for each name, keep it, drop it, or move it to a different group. Keep your own reasoning short; the list is the point.
19
19
 
@@ -25,7 +25,7 @@ Then ask the person to review the grouped list: for each name, keep it, drop it,
25
25
 
26
26
  ## Rules
27
27
 
28
- - Report only. This tool writes no `catalyst.env.json` and proposes nothing.
28
+ - Report only. This tool writes no `.catalyst/catalyst.toml` and proposes nothing.
29
29
  - Print names only: never a `.env` value, a secret, or a committed `wrangler.toml [vars]` value. Give the name, where it was found, and where a local value would come from.
30
30
  - A Cloudflare (or other platform) binding is not an environment value; keep the two apart.
31
31
  - This reads the repository only, with no login and no network call. The account-scope `catalyst environment` verb reads your cloud account's own declaration.
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
- // check.mjs — validates a catalyst.env.json file offline, with the same rules this bundle vendors
3
- // from the cloud's own validator. Never reads or prints a value. Offline: no login, no network —
4
- // wraps `catalyst env check`.
2
+ // check.mjs — checks the repository settings TOML offline. Never reads or prints a value. Offline:
3
+ // no login, no network — wraps `catalyst env check`.
5
4
  import { runCliOffline } from "./lib/cli.mjs";
6
5
 
7
- const HELP = `Usage: node scripts/check.mjs <file> [--json]
6
+ const HELP = `Usage: node scripts/check.mjs [path] [--json]
8
7
 
9
- Validates a catalyst.env.json file against this bundle's offline copy of the cloud's rules. Prints
10
- "valid" or the refusal reasons — never a value. Exit 0 valid, 1 invalid or unreadable.
8
+ Checks TOML syntax and the environment variable table in .catalyst/catalyst.toml (default), or at
9
+ the repo-relative path you name. Prints "valid" or refusal reasons — never a value. A legacy root
10
+ catalyst.env.json is not read by the cloud. Exit 0 valid or absent, 1 invalid or unreadable.
11
11
 
12
12
  --json prints {state, errors}. This is a local, offline check: no login, no network required.`;
13
13
 
@@ -18,13 +18,12 @@ if (args.includes("--help") || args.includes("-h")) {
18
18
  }
19
19
  const json = args.includes("--json");
20
20
  const file = args.find((a) => a !== "--json");
21
- if (!file) {
22
- console.error("env check needs a file: node scripts/check.mjs <path to catalyst.env.json>");
23
- console.log(HELP);
24
- process.exit(1);
25
- }
26
-
27
- const res = runCliOffline(["env", "check", file, ...(json ? ["--json"] : [])]);
21
+ const res = runCliOffline([
22
+ "env",
23
+ "check",
24
+ ...(file ? [file] : []),
25
+ ...(json ? ["--json"] : []),
26
+ ]);
28
27
  if (res.stdout) process.stdout.write(res.stdout);
29
28
  if (res.stderr) process.stderr.write(res.stderr);
30
29
  await finish(res.code);
@@ -1,49 +1,33 @@
1
1
  ---
2
2
  name: whats-happening
3
3
  description: >-
4
- The desk for a Catalyst Cloud account, and the facts behind it. Use when the person asks "what's happening?", "where are we?", "why is that stuck?", "what closed?", "what's next?", "how does this work?", "why did it do that?", "how does it prioritise?" or "what does this setting do, where is it set?", or asks for something to be done rather than known. Reads the contract, what is running and queued, the eligibility explainer, the coding accounts and the open asks through the catalyst CLI, and answers in one reply with ticket ids. Explains the ladder, the stage map, failures, parks and holds, the queue order and every reason a ticket is excluded. Routes work to a project owner and decisions to what-needs-me. Read-only: never composes a URL, never polls, never answers as the human.
4
+ Use for "what's happening?", "where are we?", "why is that stuck?", "what closed?", "what's next?", "how does this work?", "why did it do that?", "how does it prioritise?" and "what does this setting do, where is it set?" in Catalyst Cloud, or asks for something to be done rather than known. Reads the contract via catalyst CLI. Read-only: route work/decisions, never answer as the human.
5
5
  allowed-tools: Bash(catalyst:*) Bash(npx -p @catalyst-cloud/cli catalyst:*)
6
6
  ---
7
- <!-- vendored-from: @catalyst-cloud/catalyst-skills@0.13.1 — written in this repository for customer accounts -->
7
+ <!-- vendored-from: @catalyst-cloud/catalyst-skills@0.14.1 — written in this repository for customer accounts -->
8
8
 
9
9
  # What's happening
10
10
 
11
- You are the one desk the person talks to about their Catalyst Cloud account: where things stand, why something is stuck, what closed, what is next, and how Catalyst works. Answer each in one reply from their own account's data.
11
+ Use one snapshot and the person's login. Run scripts, never read them. --help explains usage; exit 2 needs onboard, exit 1 means failure.
12
12
 
13
- Every account-specific fact (stage names and ids, labels, the ladder keying, thresholds, merge policy) comes from the contract, `GET /api/v1/agent/contract`; the references hold only what is the same for every account.
13
+ - `node scripts/snapshot.mjs` prints contract, running work, queue, ranked asks, replica verdict. --board adds stages, --accounts coding accounts, --team K narrows.
14
+ - `node scripts/explain.mjs <ticket>` explains eligibility; --history adds attempts, rounds, holds and releases.
15
+ - `node scripts/show-my-map.mjs [--team K]` prints stages, labels, ladder and thresholds.
14
16
 
15
- ## Run first
16
-
17
- Scripts are run, never read; each prints `--help`. Exit 2 means this machine is not connected (`catalyst-onboard`), exit 1 that the check itself failed.
18
-
19
- - `node scripts/snapshot.mjs`: the trimmed contract, what is running, the queue, the ranked open asks, and the replica verdict. `--board` adds open tickets by stage, `--accounts` the coding accounts, `--team K` narrows.
20
- - `node scripts/explain.mjs <ticket>`: why one ticket is or is not about to run. `--history` adds attempts, rounds, holds and past releases.
21
- - `node scripts/show-my-map.mjs [--team K]`: this account's slot-to-stage map, labels, ladder and live thresholds.
22
-
23
- One ticket's comments and relations are the `catalyst-linear` skill; a pull request's checks and threads, `catalyst-github`; readiness ("am I set up?"), `catalyst-onboard`.
17
+ Comments/relations: catalyst-linear. PRs: catalyst-github. Readiness: catalyst-onboard. Use current account facts/URLs, never memory. Unknown means inconclusive. PR labels/reactions are unmirrored; print their URL. Accounts/history are readable.
24
18
 
25
19
  ## Load on demand
26
20
 
27
- | when | read |
21
+ | question | reference |
28
22
  | -- | -- |
29
- | writing any status answer, or deciding whether something is stuck | `references/status-reply.md` (schema: `assets/status-reply.json`) |
30
- | `explain` returned a reason and the person wants the next action | `references/why-is-it-stuck.md` |
31
- | "what runs next?", "do this one first", the WIP limit, capacity, routing | `references/what-runs-next.md` |
32
- | a phase failed, a card went to Remediate, a ticket is parked or on hold | `references/when-a-phase-fails.md` |
33
- | the person asks for work to be done, or a decision surfaces | `references/routing-work.md` |
34
- | "what is Catalyst Cloud?", the phases, what each produces, when a ticket is Done | `references/the-ladder.md` |
35
- | "which column is which, why does nothing dispatch, what is a slot?" | `references/stages-and-mapping.md` |
36
- | "why is nothing running", walls, quarantine, which provider ran a phase | `references/coding-accounts.md` |
37
- | "what does this setting do, where is it set, who can change it?" | `references/settings-and-where-they-live.md` |
38
-
39
- ## Rules
40
-
41
- - **Their account, as them.** Every read goes through the CLI with the person's own login; "you" in a reply means the connected person.
42
- - **Print, never recall.** A stage name, label, threshold or route in your answer comes from a script's output in this session. A settings answer names the screen, its route and the rule from `references/settings-and-where-they-live.md`.
43
- - **One reply, ticket ids on every line, source named** (`references/status-reply.md`).
44
- - **A reason is a row** in `references/why-is-it-stuck.md`: name what releases it and who can. Unknown is not absent; report it as inconclusive.
45
- - **Parks and holds have their own release.** Once the cause is fixed, the person's own login releases a park, a no-change hold or a validate-budget hold through the `unstick` skill (`catalyst release`). A round-threshold hold and a review that will not converge refuse that release; `references/when-a-phase-fails.md` says what clears each.
46
- - **Say what a key cannot see.** PR labels and reactions are not mirrored; repeat the settings URL the CLI prints. Coding accounts and execution history are readable, so read them.
47
- - **System causes are one alert.** A provider outage, the runner image breaker or a paused repository is said once, for every ticket it holds.
48
- - **One snapshot per question.** Waiting on a change is the project owner's job (`run-this-project` subscribes to the stream).
49
- - **You route; the owner acts** (`references/routing-work.md`). The human answers for themselves: a decision is an ask through `what-needs-me`, filed before anyone proceeds on its default.
23
+ | status or stuck? | references/status-reply.md; schema assets/status-reply.json |
24
+ | eligibility reason? | references/why-is-it-stuck.md |
25
+ | order, capacity, WIP or routing? | references/what-runs-next.md |
26
+ | failure, park or hold? | references/when-a-phase-fails.md |
27
+ | request or decision? | references/routing-work.md |
28
+ | phases or Done? | references/the-ladder.md |
29
+ | columns or slots? | references/stages-and-mapping.md |
30
+ | accounts, windows, quarantine or provider? | references/coding-accounts.md |
31
+ | setting, screen, route or role? | references/settings-and-where-they-live.md |
32
+
33
+ Read-only: give ids, source, release and actor. Route releases to `unstick`, decisions to what-needs-me before defaults, ownership to run-this-project. Subscribe, never poll. Report each system cause once.
@@ -1,24 +1,11 @@
1
- # Coding accounts: slots, windows, walls
1
+ # Coding accounts
2
2
 
3
- The person's own rows print with `node scripts/snapshot.mjs --accounts`, with no credential or email. An owner or admin enrols, pauses or removes one at `<their cloud>/settings/coding-accounts`.
3
+ snapshot.mjs --accounts omits credentials/emails. An owner/admin enrols, pauses, removes or replaces credentials at `<their cloud>/settings/coding-accounts`.
4
4
 
5
- ## Slots and providers
5
+ Slots identify credentials, not emails. Claude/GLM/Qwen use Claude CLI, Codex uses Codex; GLM/Qwen also use OpenCode. Routing names the model.
6
6
 
7
- A slot is one enrolled credential that runs phases; identity is the credential, so one email may hold several. Claude, GLM and Qwen run under the Claude CLI, Codex under Codex, and GLM and Qwen also under OpenCode. The routing rows (`references/what-runs-next.md`), not the harness, name the model.
7
+ Declared state is operator-set active/disabled. Observed health is healthy/degraded/unknown, polled every five minutes for active slots and daily for disabled ones. Credential conflicts/auth mismatches quarantine; Replace credential on the account's page clears it.
8
8
 
9
- ## State
10
-
11
- - **Declared:** `active` or `disabled`, set by the operator.
12
- - **Observed:** `healthy`, `degraded` or `unknown`, set by the poller (every 5 minutes for an active slot, daily for a disabled one).
13
- - **Quarantined:** system-set on a credential conflict or an authentication mismatch. Replace credential on the account's page clears it, and a workspace owner or admin can do that.
14
-
15
- ## Windows and walls
16
-
17
- Subscriptions meter usage over a **5-hour** and a **7-day** window. A **wall** is the limit a session can die at mid-run, so a slot whose remaining headroom cannot fit the phase's projected burn is not offered. A Claude slot serves several phases at once up to a cap; a Codex slot serves one, because its refresh tokens are single-use. Vendor status pages say nothing about the person's own windows.
18
-
19
- ## "Why is nothing running?"
20
-
21
- 1. `node scripts/explain.mjs <ticket>`: `routing_unavailable` naming a slot or provider, or `no_eligible_account_slot` in the routing block, points at accounts.
22
- 2. `node scripts/snapshot.mjs --accounts`: an empty list means none is enrolled; a wall is the `walled` field, a quarantine `quarantined` with its reason. Read them; silence proves nothing.
23
- 3. Report it as one fleet-level cause for every ticket it holds.
9
+ Subscriptions have 5-hour and 7-day windows. Walls kill sessions; phase burn must fit headroom. Claude slots allow concurrent phases up to a cap; Codex permits one because refresh tokens are single-use. Vendor status does not reveal account windows.
24
10
 
11
+ When idle, explain. routing_unavailable or no_eligible_account_slot points here. Read --accounts: empty means no enrolment; inspect walled, quarantined and reason. Silence proves nothing.
@@ -1,18 +1,7 @@
1
- # Routing work
1
+ # Route requests
2
2
 
3
- Your first sentence says which of three things the message is:
3
+ Classify first: question, work request, human decision, or both request/decision. Questions: status-reply.md. Decisions: what-needs-me before defaults.
4
4
 
5
- 1. **A question** ("where is X, why is Y stuck, what closed?"): answer it in the one-reply shape (`references/status-reply.md`).
6
- 2. **A request for work** ("get X done, own this until it closes"): turn it into a project with an owner, in one pass, as below.
7
- 3. **A decision only they can make**: raise it through `what-needs-me` before anyone proceeds on the default. `what-needs-me` owns what is and is not an ask.
5
+ Search projects with catalyst query projects and `catalyst query search <terms>`. Reuse fitting projects. Otherwise name outcome, one or two catalyst-linear tickets and owner; the person creates the project. Assign a person or run-this-project session, giving its start command. Report returned ids, owner and next event; never guess ids.
8
6
 
9
- A request containing a decision is both; do and say both.
10
-
11
- ## A request becomes a project with an owner
12
-
13
- 1. **Find the existing home** with `catalyst query projects` and `catalyst query search <terms>`. A request that fits an open project is a ticket there, never a duplicate project.
14
- 2. **Scaffold when there is none:** the outcome in a sentence, the first ticket or two (through `catalyst-linear`), and the owner. The person creates a project in Linear; name it for them.
15
- 3. **Name the owner:** a `run-this-project` session for that project, or a person. Give the one command that starts the owner session; long-running work belongs there, not at the desk.
16
- 4. **Say what you did:** the identifiers created, the owner, and the next thing the person will see. Cite an identifier only after the create call returned it; a guessed number is usually a real, unrelated ticket.
17
-
18
- The human answers for themselves: pick no option on an open ask, close none, and post nothing in their voice. An answer they give in chat is recorded on the ask through `what-needs-me`, as the app actor. A system-level failure is one line in the status reply, not a question per ticket.
7
+ Pick no ask option, close no ask and post nothing in the human's voice. Record their chat answer through what-needs-me as the app actor.
@@ -1,20 +1,17 @@
1
- # Settings and where they live
1
+ # Settings
2
2
 
3
- Live values come from the contract or a script. Prefix every route with the person's own `<their cloud>`, never an invented host. Unless a row says otherwise, an owner or admin sets it.
3
+ Use live values and the person's cloud prefix. Owner/admin acts unless stated. Name screen, route, rule.
4
4
 
5
- | what | where | the rule |
6
- | -- | -- | -- |
7
- | **Connecting Linear** | `<their cloud>/settings/connections` | Needs an owner or admin browser session, which also decides the account. |
8
- | **One workspace, one account** | `<their cloud>/settings/connections` | A Linear workspace binds to exactly one account, and the reverse; a second account for the same workspace is refused. Raise it as a decision, not a retry. |
9
- | **Installing the GitHub App** | `<their cloud>/settings/connections`, after `<their cloud>/settings/profile` | The admin's personal GitHub grant comes first: a refusal naming a missing GitHub identity or someone else's installation means "grant your personal GitHub first". |
10
- | **Uninstalling** | `<their cloud>/settings/connections` | Removing the App on GitHub self-heals the registry; unlinking in Catalyst uninstalls upstream. Neither needs support. |
11
- | **One team, one repository** | `<their cloud>/settings/repositories` | A Linear team maps to at most one repository per account, and a GitHub repository to at most one, case-insensitively. |
12
- | **Neither half can be re-pointed** | `<their cloud>/settings/repositories` | A repository is one team plus one GitHub repo; the only editable field is its name, so a monorepo across two teams cannot be modelled. |
13
- | **An archived repository holds both keys** | `<their cloud>/settings/repositories` | Re-registering the same team-plus-repo pair is refused until the archived entry is restored. |
14
- | **Merge policy** | `<their cloud>/settings/repositories/$repoId/merging` | The effective policy and its source are on the contract's `merge` block; this page changes it (`catalyst-github` only reads it). |
15
- | **Reviewers** | `<their cloud>/settings/repositories/$repoId/code-reviews` | "Post review requests as" names one connected member. A strict merge policy with no reviewer never earns the merge label: configure one, or change the policy. |
16
- | **The merge queue** | no settings page; the repository's own merge automation | The merge phase's one write is the ready label; the merge itself is whatever the repository's own setup does with it. This bundle cannot see which queue runs; say so, naming no vendor the person has not named. The GitHub repository's administrator owns it. |
17
- | **The runner cap** | `<their cloud>/settings/repositories` | 20 running phases per repository by default, which an operator changes; the page only displays it, and a paused repository resolves to zero. See `references/what-runs-next.md`. |
18
- | **Secrets and environment variables** | `<their cloud>/settings/secrets`, `<their cloud>/settings/environment`, and each repository's sections | Secrets are write-only; variables are readable. A name is one or the other, never both; a repository value wins over an account one; a variable may reference a vault secret by name, expanded only in the container. |
19
- | **"My secrets are not in the container"** | `<their cloud>/settings/repositories` | When a repository was registered without its team, nothing reaches a runner, and the failure is silent: a phase's build cannot find its environment. Raise the fix, an admin or operator action, as an ask. |
20
- | **Routing** | none: there is no settings page for this | Stage defaults are global and the per-account table is empty, so routing always resolves to the default provider. A Codex-first pipeline is not something to promise (`references/what-runs-next.md`). |
5
+ | screen and route | rule |
6
+ | -- | -- |
7
+ | Integrations, /settings/connections | Connecting Linear needs admin browser session, which chooses the account. A workspace binds to exactly one account and vice versa; a conflict needs a decision, not retry. |
8
+ | Profile, /settings/profile, then Connections | The personal GitHub grant comes first; missing identity or another person's installation refusal means grant personal GitHub first. |
9
+ | Connections | Removing the App on GitHub self-heals the registry; Catalyst unlink uninstalls upstream; neither needs support. |
10
+ | Your projects, /settings/projects | Each Catalyst project pairs one Linear team with its registered GitHub repositories. Manage the project, attach repositories, and choose the team's default repository here. |
11
+ | Merging, /settings/projects/$projectId/repositories/$repoId/merging | Merge policy is changed here; contract merge gives value/source; catalyst-github only reads. |
12
+ | Code reviews, /settings/projects/$projectId/repositories/$repoId/code-reviews | Post review requests as selects a connected member. Strict policy without reviewer never earns ready label; configure reviewer or change policy. |
13
+ | Merge queue, no Catalyst page | After ready label, the merge itself is whatever the repository's own setup does with it; the repo admin owns this. This bundle cannot identify its queue vendor; never guess. |
14
+ | Repositories | Shows operator-set runner cap, default 20, paused effective zero; see what-runs-next.md. |
15
+ | Secrets /settings/secrets and Environment /settings/environment, plus repository sections | Secrets write-only, variables readable; names are never both. Repository values override account values. Variables may reference vault secrets, expanded only in container. |
16
+ | Repositories | Without a registered team nothing reaches a runner, and the failure is silent; raise admin/operator fix as ask. |
17
+ | Routing, no settings page for this | Global stage defaults and empty per-account table select default provider; never promise Codex-first. |
@@ -1,25 +1,19 @@
1
- # Stages and mapping
1
+ # Stages
2
2
 
3
- A **slot** is Catalyst's name for a position on the board; a **stage** is the Linear workflow state a team has; the **mapping** binds each slot to one stage per team. Every team's live map is on the contract under `teams[].stages`; `node scripts/show-my-map.mjs [--team <key>]` prints it with the load-bearing slots starred.
3
+ Slots are board positions; stages are Linear states. teams[].stages maps them per team; show-my-map.mjs stars required slots.
4
4
 
5
- The slots, in pipeline order: `dispatch`, `intake`, `research`, `plan`, `implement`, `remediate`, `verify`, `review`, `pr`, `done`, `canceled`.
5
+ Order: dispatch, intake, research, plan, implement, remediate, verify, review, pr, done, canceled.
6
6
 
7
- ## Five slots are load-bearing
8
-
9
- | slot | why it matters | allowed state types |
7
+ | required slot | allowed Linear type | purpose |
10
8
  | -- | -- | -- |
11
- | `dispatch` | moving a card here dispatches work; nothing is offered from any other column | `unstarted`, `backlog` |
12
- | `intake` | where a never-seen ticket lands for the optional intake pass | `unstarted`, `backlog`, never Linear's triage type |
13
- | `pr` | a card must sit here for `merge` to be offered | `started` |
14
- | `done` | written by the merge webhook | `completed` |
15
- | `canceled` | terminal; never work | `canceled` |
16
-
17
- An absent or wrongly typed mapping on one of these stops the ladder silently (on the others it costs a readiness warning): until dispatch, pr, done and canceled each point at a live stage, Catalyst starts nothing in that team, and `explain` says so. `teams[].gitAutomation` is a stored consent for a feature not built yet; nothing reads it, so its value neither stops nor starts work.
18
-
19
- `teams[].workflowMode` is **adopted** (Catalyst created the stages), **mapped** (a human chose each) or **mixed**. Mappings live at `<their cloud>/settings/linear-teams`; `.catalyst/catalyst.toml` has no stage section.
9
+ | dispatch | unstarted/backlog | starts work |
10
+ | intake | unstarted/backlog, never triage | optional classification of unseen tickets |
11
+ | pr | started | permits merge phase |
12
+ | done | completed | merge webhook writes it |
13
+ | canceled | canceled | terminal |
20
14
 
21
- ## The state id is the authority
15
+ Missing/wrong required mappings stop work; others warn. Dispatch/pr/done/canceled must be live. `teams[].gitAutomation` stores consent; nothing reads it.
22
16
 
23
- Only a stage's `stateId` is a lookup key, because a Linear import can keep every name while re-minting every id. Move cards by slot (`catalyst-linear` does) and let the CLI resolve the id. `stateStillExists: false` means the team needs re-mapping (`catalyst team map <KEY>`) before that slot can be written; the CLI refuses the move.
17
+ workflowMode: adopted means Catalyst-created, mapped means human-chosen, mixed means both. Configure at `<their cloud>/settings/linear-teams`, never catalyst.toml.
24
18
 
25
- Backlog is not a slot: parking a card moves it to the team's backlog-type state, which the CLI resolves from the live workflow. Readiness over the mapping, and who fixes each check, is the `catalyst-onboard` skill.
19
+ stateId is authoritative; imports can replace ids but keep names. catalyst-linear resolves slots to ids. stateStillExists: false refuses the move; remap with `catalyst team map <KEY>`. Backlog is not a slot: parking resolves a live backlog-type state. catalyst-onboard explains readiness and who fixes it.
@@ -1,34 +1,16 @@
1
- # The one-reply shape
1
+ # Status
2
2
 
3
- One question gets one reply, complete enough that the person needs no second surface. Every line names a ticket identifier, and a fact you could not read is named as unreadable, with where it lives.
3
+ Open with takenAt, source and replica cursor/API reason. Then:
4
4
 
5
- Open with one clause: the snapshot's `takenAt` and its source (a fresh replica's cursor, or the API and why). Then the blocks, in order:
5
+ 1. In flight: ticket, phase and elapsed time from running.
6
+ 2. Blocked: reason and release actor.
7
+ 3. Waiting on human: ranked waitingOnHuman asks, question and what each releases. Details belong to what-needs-me.
8
+ 4. Closed: query issues at the contract's done stage or read the change feed for the requested window; otherwise since the last reply.
9
+ 5. Next: queue order and phase.
10
+ 6. Cannot see, when nonempty: unreadable facts and CLI-printed URLs. PR labels/reactions are not mirrored. Metrics such as cycle time, throughput, or how long pull requests have been open are not computed; never substitute ticket dates.
6
11
 
7
- 1. **In flight.** From the snapshot's `running` block: identifier, the phase running, how long.
8
- 2. **Blocked, and on whom.** The queue's excluded rows, with `explain` on the ones the person cares about. Every line carries the reason in the person's words and who releases it: the person, a role, the cloud itself, or a clock.
9
- 3. **Waiting on the human.** `waitingOnHuman` in the snapshot, ranked by what each ask holds: identifier, the question, what it releases. `what-needs-me` owns the detail.
10
- 4. **Closed.** What reached the done slot in the window asked about (`query issues` by the done-slot stage name, or the change feed); with no window read, "since my last reply".
11
- 5. **Next.** The snapshot's `queue` block in the cloud's order, with each ticket's next phase.
12
- 6. **Cannot see**, only when non-empty: PR labels and reactions (not mirrored), each with the URL the CLI printed. A flow number goes here by name: cycle time, throughput, or how long pull requests have been open are not computed by anything a key reads, so say they are not computed rather than counting ticket dates.
12
+ Lines use identifier, contract stage, then one clause. Age uses updated_at/lease start and expected phase duration. Omit empty blocks.
13
13
 
14
- ## Writing the lines
14
+ Read --board by slot. Long dispatch with nothing running: explain its first ticket. Unmoved cards may run, retry or remediate; count repair separately, never as progress. Asks wait on humans; local-lane work runs elsewhere. Comments and explain --history must agree.
15
15
 
16
- - Identifier first, then the stage as the contract spells it, then one clause: `KEY-123 · <stage name> · implement running 14 min`.
17
- - Age in human units from `updated_at` or the lease start, judged against the phase's natural duration.
18
- - A reason is its translation from `references/why-is-it-stuck.md`. One ticket in flight and nothing blocked is a three-line reply.
19
-
20
- ## Reading the board
21
-
22
- `node scripts/snapshot.mjs --board` groups open tickets by stage in slot order; read it by slot, never by name. A long dispatch column with nothing in flight is a capacity or eligibility question: `explain` the first row. A card that has not moved is running, retrying in place, or in remediate, which is an interrupt to count separately, never progress. An ask-labelled ticket belongs in the waiting-on-human block; a local-lane ticket is in flight elsewhere. The ticket's comments (`catalyst-linear`) and `catalyst explain --history <ticket>` must agree.
23
-
24
- ## What counts as stuck
25
-
26
- A ticket is **stuck** only when all three hold:
27
-
28
- 1. Nothing is offered for it: the queue excludes it, or `explain` gives a reason rather than a position.
29
- 2. The reason does not release itself (`references/why-is-it-stuck.md` marks which do).
30
- 3. No one is acting on the release: no open ask names it, and no human comment or push landed after the failure.
31
-
32
- Everything else is **waiting**, and the reply says on what; calling a wait "stuck" sends the human to fix what the cloud is handling.
33
-
34
- The reply answers no ask, proposes no default for the human, and moves nothing: requests go to `references/routing-work.md`, decisions to `what-needs-me`.
16
+ Stuck: nothing offered, no automatic release, no ask or post-failure human comment/push. Otherwise name the wait. Move nothing; route requests to routing-work.md and decisions to what-needs-me.
@@ -1,30 +1,20 @@
1
- # What Catalyst is, and the ladder
1
+ # Phases
2
2
 
3
- ## In the person's terms
3
+ Explain using their tickets/repos. Dispatch starts repository-configured cloud containers on enrolled accounts, never laptop coding sessions. Agents react to events; documents/outcome comments stay on the ticket.
4
4
 
5
- Use their repositories and tickets as examples. Moving a card into the team's dispatch column starts the work, and nothing else does. Each phase runs in a cloud container set up for the repository, on a coding account their workspace enrolled, and leaves a document and an outcome comment on the ticket, so the ticket is the record. Their laptop runs no coding sessions, and agents react to events rather than polling.
5
+ Tickets need outcome title, acceptance criteria, priority, no open blocker and no assumed chat context. Catalyst owns working stages/Done. Draft PRs become ready; green, thread-free PRs queue-merge unless held. Linear asks carry options/default/blocked work. Human comments get eyes and threaded replies.
6
6
 
7
- What changes in their day: they write each ticket for a reader who cannot see their chat (an outcome title, what done looks like, a priority, no open blocker). They leave working stages and Done to Catalyst. A draft pull request appears that a later phase marks ready, and a green one with no open threads merges through the queue unless a hold label keeps it out. A decision only they can make arrives as an ask in their own Linear, with options, a silent default and what it holds. A comment they post gets an eyes reaction and a threaded reply.
7
+ | phase | output or effect |
8
+ | -- | -- |
9
+ | intake | optional classification, no artifact; ladder.intakeEnabled |
10
+ | research | research.md, offered from dispatch |
11
+ | plan | plan.md |
12
+ | implement | implement.md; ticket-id branch and draft PR |
13
+ | validate | validation.md; success enters the shared verify/review stage |
14
+ | pr | pr.md, title first then body; rebase, force-push, mark ready |
15
+ | remediate | remediation.json; failure interrupt, never advances beyond PR |
16
+ | merge | receipt; evidence gate then queue-ready label |
8
17
 
9
- ## The phases
18
+ Read ladder.advance and keying: trailing stages name the completed phase, leading stages the next. Failure, remediate and merge do not advance the card; see when-a-phase-fails.md. show-my-map.mjs translates stages; explain names the next phase.
10
19
 
11
- The contract's `ladder` block (`node scripts/show-my-map.mjs`) says whether intake is on and which keying applies.
12
-
13
- | phase | produces | notes |
14
- | -- | -- | -- |
15
- | `intake` | nothing (a classification pass) | optional, for a new ticket, when `ladder.intakeEnabled` |
16
- | `research` | `research.md` | offered from the dispatch slot |
17
- | `plan` | `plan.md` | |
18
- | `implement` | `implement.md` | creates the branch, named exactly the ticket identifier, and opens a draft pull request |
19
- | `validate` | `validation.md` | success moves the card to the review stage (verify and review share it) |
20
- | `pr` | `pr.md` | first line is the PR title, then the body; rebases, force-pushes, marks the PR ready |
21
- | `remediate` | `remediation.json` | an interrupt that repairs a failed phase; never advances past the PR slot |
22
- | `merge` | a receipt | applies the queue-ready label once its evidence gate passes |
23
-
24
- ## What moves the card
25
-
26
- The contract's `ladder.advance` maps each completed phase to a card move; its keying decides whether a stage names the phase just finished (trailing, the default) or the one ahead (leading). A failed phase, `remediate` and `merge` move nothing (`references/when-a-phase-fails.md`).
27
-
28
- **Done is written by the merge.** GitHub's merged event moves the ticket to Done within seconds, with a sweep behind a dropped webhook, so a ticket not Done a minute after its PR merged is a finding, not a chore to hand-close. Done means merged; a separately deployed change is live only once deployed.
29
-
30
- To place a ticket, its stage says which phase last finished (`node scripts/show-my-map.mjs --team <key>` translates it) and `explain` says what runs next.
20
+ Done means merged. The webhook writes it within seconds; a sweep recovers losses. Missing Done after one minute is a finding; never hand-close. Live requires deployment.
@@ -1,32 +1,13 @@
1
- # What runs next: order, capacity, routing, and the person's levers
1
+ # Dispatch
2
2
 
3
- ## Queue order
3
+ Queues update within seconds. Dispatch sorts by priority, created time, identifier; mid-ladder tickets precede them by phases completed. Order never grants eligibility.
4
4
 
5
- The cloud derives each team's queue from its tickets within seconds of any board change. Cards in the dispatch slot rank by Linear **priority** (urgent first), then **created time**, then **identifier**. Tickets already **mid-ladder** join the same set and sort ahead by phases completed, so a ticket near the end goes first; that count orders, and never makes an ineligible ticket eligible.
5
+ An operator sets the repository concurrency cap, default 20, displayed in settings. Pause means zero, preserving the cap. Teams share capacity, including comment-wake.
6
6
 
7
- ## Capacity
7
+ WIP limits starts per project, one Linear team across repositories: project setting, operator's account value, then 12; zero prevents starts. Members read `catalyst project wip-limit get --team <KEY>`; owners/admins use `set <n>` or set default. Only first phases are held; later phases continue. Count live tickets past dispatch or granted a first phase, including waits/blocks/parks; exclude never-started, backlog and local-lane. Idle at the limit means started tickets wait; use unstick, catalyst-github or what-needs-me.
8
8
 
9
- - Each repository has a concurrency cap of 20 running phases by default, which an operator raises or lowers; the account's own settings page displays it. A paused repository resolves to zero and keeps the stored value for resuming.
10
- - Dispatch splits slots across teams so none starves, and comment-wake work shares the cap.
9
+ Routing selects the first candidate passing capability, configured model, provider availability, eligible slot/headroom when needed, and parameters. No survivor gives `no_eligible_account_slot` if capacity skipped a candidate, otherwise routing_unavailable. Stage defaults are global; no routing setting exists and a Codex-first pipeline cannot be promised.
11
10
 
12
- ## The work-in-progress limit
11
+ Priority reorders; dispatch starts; backlog stops future phases/rounds without canceling. The person/project owner moves cards. Contract merge.prLabels holds keep PRs out of the queue; ask relations block tickets; the release label corrects ask-shape false positives. Nothing interrupts a running phase. Failed phases need no requeue; manual moves usually restart counts. Priority never overrides blockers.
13
12
 
14
- A project (one Linear team across its repositories) at its limit starts no new ticket: its own setting, else an account-wide value an operator set, else 12. `0` holds every new start. Members read it, its source and the count with `catalyst project wip-limit get --team <KEY>`; an owner or admin runs `set <n>` (or `set default`).
15
-
16
- It holds only first phases (`explain` prints `wip_limit`, e.g. "14 tickets in progress, at or above its WIP limit of 12"); a started ticket keeps getting every later phase. In progress counts tickets, not containers: every live ticket past the dispatch column (or granted a first phase), blocked, parked and waiting ones included; never-started, backlog and local-lane tickets are not counted. A fleet idle at the limit means the tickets in progress are all waiting; unstick those (`unstick`, `catalyst-github`, `what-needs-me`).
17
-
18
- ## Routing
19
-
20
- A phase about to start takes the first route that passes, in order: capability match, a configured model, the provider available, an eligible coding-account slot with headroom (when the route needs one), and resolvable parameters. With no survivor, the routing block reads `no_eligible_account_slot` when a candidate was skipped on capacity, else `routing_unavailable`. Stage defaults are global and there is no routing setting yet, so a Codex-first pipeline is not something to promise. Slots are in `references/coding-accounts.md`.
21
-
22
- ## The person's levers
23
-
24
- 1. **Priority on the ticket** reorders the queue: the lever for "do this one first".
25
- 2. **The dispatch column.** Moving a card there starts work; moving it to a backlog-type state stops work, and further rounds, without cancelling. Describe the move and let the person or the project owner (`run-this-project`) make it.
26
- 3. **Holds.** A hold label from the contract's `merge.prLabels` keeps a mergeable pull request out of the queue until removed. An ask's blocking relation holds every ticket it names. The contract's release label frees a ticket the ask-shape detector flagged by mistake.
27
-
28
- No lever interrupts a running phase. A failed phase needs no re-queueing, and moving its card by hand usually restarts its count. Priority is the fleet's order, not the person's urgency: an urgent ticket blocked on an ask still waits for the ask.
29
-
30
- ## "Why is that one not next?"
31
-
32
- Run `explain` on it. A position means capacity bounds it: say how many are ahead and whether anything runs at all; if nothing runs anywhere, read the coding accounts first. A reason goes to `references/why-is-it-stuck.md`. A ticket missing from the explainer is on another team, terminal, or unknown; check the identifier.
13
+ Explain why not next: position means capacity, so report tickets ahead/running. With none running, read accounts. Reasons use why-is-it-stuck.md; missing means another team, terminal or unknown, so verify the id.
@@ -1,27 +1,21 @@
1
- # When a phase fails: retries, repair rounds, parks and holds
1
+ # Failures
2
2
 
3
- Numbers here are fleet defaults; quote the live `thresholds` that `node scripts/show-my-map.mjs` prints. A failed phase writes no board state: the ticket stays at its stage, and four layers decide what happens next.
3
+ Quote live show-my-map.mjs thresholds; these are defaults. Failure itself moves no card.
4
4
 
5
- 1. **Retry in place.** A failure that is not the ticket's fault (one before any branch existed, or infrastructure: a vendor 5xx, a dropped stream, a timeout, an environment gap) re-offers the same phase with no repair round.
6
- 2. **Backoff.** Each retry in place, and a routing refusal at kickoff, waits out a rung first: 2, 5, then 15 minutes (`thresholds.retryBackoffMs`).
7
- 3. **Remediate.** Any other failure moves the card to the remediate stage and queues a repair round; a successful round returns the card to its exact pre-failure stage. A team with no remediate stage gets the hold label (`teams[].labels.hold`) instead. Rounds are capped per failure episode at `thresholds.remediateRoundCap` (default 3); a failed round queues no other, a repeated validate fingerprint spends one round per episode, and a ticket with no recorded branch gets none.
8
- 4. **Park.** After `thresholds.parkAfterConsecutiveFailures` consecutive failures (default 3) the phase parks. A repeated-failure park, and a park at the round cap, release through the person's own login once the cause is fixed (`catalyst release`, never a clock; at the cap it buys one more round). A missing-branch or rebase-conflict park is released by the cloud's own budgeted loop.
5
+ - Pre-branch or infrastructure failures, including 5xx, stream loss, timeout and environment gaps, retry the same phase without repair.
6
+ - Retry and kickoff routing refusal back off 2, 5, 15 minutes, thresholds.retryBackoffMs.
7
+ - Other failures enter remediate; success restores the exact prior stage. Without a remediate stage, use teams[].labels.hold. thresholds.remediateRoundCap defaults to 3 per episode. Failed rounds queue no further round; repeated validate fingerprints consume one round per episode; no recorded branch means no round.
8
+ - thresholds.parkAfterConsecutiveFailures defaults to 3. Repeated-failure and round-cap parks need release after a fix, never a clock; cap release grants one extra round. The cloud's budgeted loop releases missing-branch/rebase-conflict parks.
9
9
 
10
- `catalyst release <ticket> --because <what changed>` releases every governor holding the ticket, or nothing, naming what a person must do; a cause it cannot see change needs `--retry-unchanged`. The `unstick` skill runs it.
10
+ unstick previews and runs `catalyst release <ticket> --because <change>`. Release clears all governors or none, naming required action. Without visible change, require --retry-unchanged.
11
11
 
12
- ## Holds, and what clears each
12
+ | hold | trigger | release |
13
+ | -- | -- | -- |
14
+ | validate_class_spent | same validate failure after one repair | push, human non-bookkeeping comment, validate pass, ask answer; release after push/comment or --retry-unchanged plus --because; unanswered ask defaults to re-plan after 48 hours |
15
+ | round_threshold | lifetime repair budget | non-fleet push or ask answer grants one cycle; unanswered ask defaults to re-plan after 48 hours; comments and release refused |
16
+ | review_not_converging | nonconverging validate/repair cycles | human comment resumes validate; catalyst: resume implement resumes implement; push and release refused; no ask or 48-hour default |
17
+ | no_change_hold | repair changed nothing | push, human comment or release; never a clock |
18
+ | hand fix pending | ask answered human fixes it | commit on branch |
19
+ | runner pin | runner change merged before image covers it | image pin moves, then Done |
13
20
 
14
- A hold stops the cloud retrying what would fail the same way. Each kind clears differently; keep them apart.
15
-
16
- | hold | created by | cleared by | refused |
17
- | -- | -- | -- | -- |
18
- | **validate budget** (`validate_class_spent`) | the same validate failure returns after its one repair round | a push to the branch; a human comment (a `[bookkeeping]` one does not count); a validate pass; the person's own `catalyst release` after a push or comment since the hold, or with `--retry-unchanged` and a `--because`; an answer to the ask it raised; that ask's default (re-plan) after 48 hours unanswered | nothing a person can do is refused |
19
- | **round threshold** (`round_threshold`) | the ticket's counted repair rounds reach its lifetime budget | each grants one more cycle: a push the fleet did not make, or an answer to its ask; the ask's default (re-plan) applies after 48 hours unanswered | a human comment does not clear it; `catalyst release` is refused |
20
- | **review convergence** (`review_not_converging`) | validate and repair cycles that do not converge | a human comment, which resumes at validate; `catalyst: resume implement` in the comment resumes at implement | a push alone does not clear it; `catalyst release` is refused; it raises no ask and has no 48-hour default |
21
- | **no change** (`no_change_hold`) | a repair round that changed nothing | a push, a human comment, or `catalyst release` | never a clock |
22
- | **hand fix pending** | an ask answered "a human fixes it" | a commit landing on the branch | |
23
- | **runner pin** | a runner change merged before the live runner image covers it | the image pin moving, which moves the ticket to Done | |
24
-
25
- The 48-hour default applies only to the asks a validate-budget or round-threshold hold raises; every other ask waits for its answer (`what-needs-me`).
26
-
27
- Two holds are fleet-wide, one alert for every ticket they hold: the **runner image breaker** (three distinct tickets failing the same startup class on the live image pauses their dispatch until the image pin moves) and a **paused repository** (an operator resumes it). `catalyst explain --history <ticket>` prints the attempts, rounds against the cap, holds with what releases each, and past releases.
21
+ Only validate-budget/round-threshold asks default after 48 hours; others await answers. Runner image breaker needs three distinct tickets failing the same startup class on the live image; dispatch waits for the pin. Paused repositories need operator resume. Report each fleet cause once. explain --history prints attempts, rounds/cap, holds, release conditions and past releases.