@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.
- package/CHANGELOG.md +8 -0
- package/README.md +2 -2
- package/dist/args.js +291 -69
- package/dist/capabilities.js +2 -0
- package/dist/cli.js +109 -17
- package/dist/config.js +3 -1
- package/dist/env/draft.js +134 -0
- package/dist/env/legacy.js +54 -0
- package/dist/env/parse-env.js +50 -0
- package/dist/env/settings-toml.js +66 -0
- package/dist/env.js +126 -26
- package/dist/legacy.js +16 -17
- package/dist/onboard-consent.js +65 -0
- package/dist/onboard.js +836 -0
- package/dist/project.js +75 -13
- package/dist/ready.js +11 -1
- package/dist/secret.js +24 -3
- package/dist/var.js +118 -0
- package/package.json +3 -2
- package/skills/catalyst-github/SKILL.md +1 -1
- package/skills/catalyst-linear/SKILL.md +1 -1
- package/skills/catalyst-onboard/SKILL.md +1 -1
- package/skills/catalyst-onboard/references/declaring-a-repository.md +19 -12
- package/skills/catalyst-onboard/references/reading-ready.md +1 -1
- package/skills/catalyst-onboard/references/the-one-path.md +4 -4
- package/skills/catalyst-onboard/references/what-the-browser-owns.md +2 -2
- package/skills/catalyst-onboard/scripts/lib/project-coverage.mjs +53 -0
- package/skills/catalyst-onboard/scripts/where-am-i.mjs +885 -196
- package/skills/run-this-project/SKILL.md +1 -1
- package/skills/unstick/SKILL.md +1 -1
- package/skills/what-needs-me/SKILL.md +1 -1
- package/skills/what-this-repo-needs/SKILL.md +4 -4
- package/skills/what-this-repo-needs/scripts/check.mjs +12 -13
- package/skills/whats-happening/SKILL.md +19 -35
- package/skills/whats-happening/references/coding-accounts.md +6 -19
- package/skills/whats-happening/references/routing-work.md +4 -15
- package/skills/whats-happening/references/settings-and-where-they-live.md +15 -18
- package/skills/whats-happening/references/stages-and-mapping.md +12 -18
- package/skills/whats-happening/references/status-reply.md +11 -29
- package/skills/whats-happening/references/the-ladder.md +15 -25
- package/skills/whats-happening/references/what-runs-next.md +7 -26
- package/skills/whats-happening/references/when-a-phase-fails.md +16 -22
- package/skills/whats-happening/references/why-is-it-stuck.md +38 -48
- 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.
|
|
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
|
|
package/skills/unstick/SKILL.md
CHANGED
|
@@ -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.
|
|
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.
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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 —
|
|
3
|
-
//
|
|
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
|
|
6
|
+
const HELP = `Usage: node scripts/check.mjs [path] [--json]
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
"valid" or
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
|
21
|
+
| question | reference |
|
|
28
22
|
| -- | -- |
|
|
29
|
-
|
|
|
30
|
-
|
|
|
31
|
-
|
|
|
32
|
-
|
|
|
33
|
-
|
|
|
34
|
-
|
|
|
35
|
-
|
|
|
36
|
-
|
|
|
37
|
-
|
|
|
38
|
-
|
|
39
|
-
|
|
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
|
|
1
|
+
# Coding accounts
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
1
|
+
# Route requests
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1
|
+
# Settings
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Use live values and the person's cloud prefix. Owner/admin acts unless stated. Name screen, route, rule.
|
|
4
4
|
|
|
5
|
-
|
|
|
6
|
-
| -- | -- |
|
|
7
|
-
|
|
|
8
|
-
|
|
|
9
|
-
|
|
|
10
|
-
|
|
|
11
|
-
|
|
|
12
|
-
|
|
|
13
|
-
|
|
|
14
|
-
|
|
|
15
|
-
|
|
|
16
|
-
|
|
|
17
|
-
|
|
|
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
|
|
1
|
+
# Stages
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
5
|
+
Order: dispatch, intake, research, plan, implement, remediate, verify, review, pr, done, canceled.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
| slot | why it matters | allowed state types |
|
|
7
|
+
| required slot | allowed Linear type | purpose |
|
|
10
8
|
| -- | -- | -- |
|
|
11
|
-
|
|
|
12
|
-
|
|
|
13
|
-
|
|
|
14
|
-
|
|
|
15
|
-
|
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
1
|
+
# Status
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Open with takenAt, source and replica cursor/API reason. Then:
|
|
4
4
|
|
|
5
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
1
|
+
# Phases
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
#
|
|
1
|
+
# Dispatch
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
1
|
+
# Failures
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Quote live show-my-map.mjs thresholds; these are defaults. Failure itself moves no card.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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 <
|
|
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
|
-
|
|
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
|
-
|
|
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.
|