@catalyst-cloud/cli 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +27 -30
  3. package/dist/args.js +299 -61
  4. package/dist/ask.js +30 -18
  5. package/dist/capabilities.js +7 -0
  6. package/dist/cli.js +125 -20
  7. package/dist/config.js +3 -1
  8. package/dist/env/draft.js +134 -0
  9. package/dist/env/legacy.js +54 -0
  10. package/dist/env/parse-env.js +50 -0
  11. package/dist/env/settings-toml.js +66 -0
  12. package/dist/env.js +126 -26
  13. package/dist/environment.js +1 -1
  14. package/dist/legacy.js +224 -0
  15. package/dist/onboard-consent.js +65 -0
  16. package/dist/onboard.js +836 -0
  17. package/dist/project.js +191 -0
  18. package/dist/ready.js +11 -1
  19. package/dist/release.js +1 -1
  20. package/dist/repo.js +297 -0
  21. package/dist/runtime-verb.js +1 -1
  22. package/dist/secret.js +25 -4
  23. package/dist/skill-shape.js +21 -13
  24. package/dist/skills.js +44 -4
  25. package/dist/transport.js +26 -1
  26. package/dist/var.js +118 -0
  27. package/package.json +6 -4
  28. package/skills/catalyst-github/SKILL.md +7 -7
  29. package/skills/catalyst-github/references/is-it-mergeable.md +8 -2
  30. package/skills/catalyst-github/references/what-a-pr-accumulates.md +3 -3
  31. package/skills/catalyst-github/scripts/is-it-mergeable.mjs +3 -3
  32. package/skills/catalyst-github/scripts/lib/cli.mjs +9 -7
  33. package/skills/catalyst-github/scripts/lib/credential.mjs +2 -2
  34. package/skills/catalyst-github/scripts/read-pr.mjs +2 -2
  35. package/skills/catalyst-linear/SKILL.md +17 -19
  36. package/skills/catalyst-linear/agents/openai.yaml +1 -1
  37. package/skills/catalyst-linear/agents/portability.yaml +1 -1
  38. package/skills/catalyst-linear/references/reading-a-ticket.md +9 -26
  39. package/skills/catalyst-linear/references/what-a-ticket-accumulates.md +2 -2
  40. package/skills/catalyst-linear/references/writing-to-linear.md +7 -9
  41. package/skills/catalyst-linear/scripts/comment.mjs +1 -1
  42. package/skills/catalyst-linear/scripts/create-ticket.mjs +1 -1
  43. package/skills/catalyst-linear/scripts/label.mjs +1 -1
  44. package/skills/catalyst-linear/scripts/lib/cli.mjs +9 -7
  45. package/skills/catalyst-linear/scripts/lib/credential.mjs +2 -2
  46. package/skills/catalyst-linear/scripts/move.mjs +1 -1
  47. package/skills/catalyst-linear/scripts/read-ticket.mjs +1 -1
  48. package/skills/catalyst-linear/scripts/search.mjs +1 -1
  49. package/skills/catalyst-onboard/SKILL.md +37 -57
  50. package/skills/catalyst-onboard/agents/openai.yaml +2 -2
  51. package/skills/catalyst-onboard/agents/portability.yaml +1 -1
  52. package/skills/catalyst-onboard/references/connecting-this-machine.md +35 -0
  53. package/skills/catalyst-onboard/references/declaring-a-repository.md +18 -21
  54. package/skills/catalyst-onboard/references/local-sync.md +19 -7
  55. package/skills/catalyst-onboard/references/reading-ready.md +79 -0
  56. package/skills/catalyst-onboard/references/replacing-a-credential.md +8 -33
  57. package/skills/catalyst-onboard/references/repository-agent-setup.md +23 -0
  58. package/skills/catalyst-onboard/references/skill-sources.md +13 -19
  59. package/skills/catalyst-onboard/references/the-one-path.md +18 -74
  60. package/skills/catalyst-onboard/references/what-a-phase-needs.md +21 -28
  61. package/skills/catalyst-onboard/references/what-the-browser-owns.md +20 -37
  62. package/skills/{catalyst-setup → catalyst-onboard}/scripts/check.mjs +10 -9
  63. package/skills/catalyst-onboard/scripts/lib/cli.mjs +6 -4
  64. package/skills/catalyst-onboard/scripts/lib/credential.mjs +2 -2
  65. package/skills/catalyst-onboard/scripts/lib/project-coverage.mjs +53 -0
  66. package/skills/catalyst-onboard/scripts/where-am-i.mjs +929 -184
  67. package/skills/run-this-project/SKILL.md +23 -25
  68. package/skills/run-this-project/agents/openai.yaml +1 -1
  69. package/skills/run-this-project/agents/portability.yaml +1 -1
  70. package/skills/run-this-project/references/making-work-ready.md +20 -37
  71. package/skills/run-this-project/references/reacting-to-events.md +25 -48
  72. package/skills/run-this-project/references/stalls-and-escalation.md +20 -42
  73. package/skills/run-this-project/scripts/lib/cli.mjs +7 -5
  74. package/skills/run-this-project/scripts/lib/credential.mjs +2 -2
  75. package/skills/run-this-project/scripts/scope-status.mjs +0 -0
  76. package/skills/run-this-project/scripts/watch-scope.mjs +1 -1
  77. package/skills/unstick/SKILL.md +12 -12
  78. package/skills/unstick/agents/openai.yaml +1 -1
  79. package/skills/unstick/agents/portability.yaml +1 -1
  80. package/skills/unstick/references/playbook.md +13 -13
  81. package/skills/unstick/scripts/lib/cli.mjs +6 -4
  82. package/skills/unstick/scripts/lib/credential.mjs +2 -2
  83. package/skills/unstick/scripts/unstick.mjs +1 -1
  84. package/skills/what-needs-me/SKILL.md +12 -14
  85. package/skills/what-needs-me/agents/openai.yaml +2 -2
  86. package/skills/what-needs-me/agents/portability.yaml +1 -1
  87. package/skills/what-needs-me/references/raising-a-decision.md +8 -16
  88. package/skills/what-needs-me/references/reading-the-inbox.md +6 -13
  89. package/skills/what-needs-me/references/settling-an-answer.md +6 -12
  90. package/skills/what-needs-me/scripts/inbox.mjs +14 -13
  91. package/skills/what-needs-me/scripts/lib/cli.mjs +6 -4
  92. package/skills/what-needs-me/scripts/lib/credential.mjs +2 -2
  93. package/skills/what-needs-me/scripts/raise.mjs +1 -1
  94. package/skills/what-needs-me/scripts/settle.mjs +1 -1
  95. package/skills/what-this-repo-needs/SKILL.md +10 -19
  96. package/skills/what-this-repo-needs/references/what-each-group-means.md +14 -44
  97. package/skills/what-this-repo-needs/scripts/check.mjs +13 -14
  98. package/skills/what-this-repo-needs/scripts/inventory.mjs +2 -2
  99. package/skills/what-this-repo-needs/scripts/lib/cli.mjs +11 -9
  100. package/skills/what-this-repo-needs/scripts/lib/credential.mjs +2 -2
  101. package/skills/whats-happening/SKILL.md +20 -30
  102. package/skills/whats-happening/agents/openai.yaml +1 -1
  103. package/skills/whats-happening/references/coding-accounts.md +11 -0
  104. package/skills/whats-happening/references/routing-work.md +4 -33
  105. package/skills/whats-happening/references/settings-and-where-they-live.md +17 -0
  106. package/skills/whats-happening/references/stages-and-mapping.md +19 -0
  107. package/skills/whats-happening/references/status-reply.md +11 -31
  108. package/skills/whats-happening/references/the-ladder.md +20 -0
  109. package/skills/whats-happening/references/what-runs-next.md +13 -0
  110. package/skills/whats-happening/references/when-a-phase-fails.md +21 -0
  111. package/skills/whats-happening/references/why-is-it-stuck.md +38 -62
  112. package/skills/whats-happening/scripts/explain.mjs +1 -1
  113. package/skills/whats-happening/scripts/lib/cli.mjs +7 -5
  114. package/skills/whats-happening/scripts/lib/credential.mjs +2 -2
  115. package/skills/{how-catalyst-works → whats-happening}/scripts/show-my-map.mjs +18 -32
  116. package/skills/whats-happening/scripts/snapshot.mjs +10 -6
  117. package/dist/env/declaration-rules.js +0 -163
  118. package/skills/catalyst-onboard/references/choosing-a-coding-account.md +0 -52
  119. package/skills/catalyst-onboard/references/who-fixes-what.md +0 -64
  120. package/skills/catalyst-setup/SKILL.md +0 -36
  121. package/skills/catalyst-setup/agents/openai.yaml +0 -6
  122. package/skills/catalyst-setup/agents/portability.yaml +0 -4
  123. package/skills/catalyst-setup/references/what-each-check-means.md +0 -88
  124. package/skills/catalyst-setup/scripts/lib/cli.mjs +0 -103
  125. package/skills/catalyst-setup/scripts/lib/credential.mjs +0 -29
  126. package/skills/catalyst-setup/scripts/replica-status.mjs +0 -46
  127. package/skills/connect-me/SKILL.md +0 -63
  128. package/skills/connect-me/agents/openai.yaml +0 -6
  129. package/skills/connect-me/agents/portability.yaml +0 -5
  130. package/skills/connect-me/references/keeping-the-replica-running.md +0 -88
  131. package/skills/connect-me/scripts/lib/cli.mjs +0 -185
  132. package/skills/connect-me/scripts/lib/credential.mjs +0 -29
  133. package/skills/connect-me/scripts/verify-connection.mjs +0 -68
  134. package/skills/how-catalyst-works/SKILL.md +0 -45
  135. package/skills/how-catalyst-works/agents/openai.yaml +0 -6
  136. package/skills/how-catalyst-works/agents/portability.yaml +0 -4
  137. package/skills/how-catalyst-works/references/coding-accounts.md +0 -51
  138. package/skills/how-catalyst-works/references/settings-and-where-they-live.md +0 -20
  139. package/skills/how-catalyst-works/references/stages-and-mapping.md +0 -56
  140. package/skills/how-catalyst-works/references/the-ladder.md +0 -41
  141. package/skills/how-catalyst-works/references/what-catalyst-is.md +0 -30
  142. package/skills/how-catalyst-works/references/what-runs-next.md +0 -95
  143. package/skills/how-catalyst-works/references/when-a-phase-fails.md +0 -57
  144. package/skills/how-catalyst-works/scripts/explain-ticket.mjs +0 -41
  145. package/skills/how-catalyst-works/scripts/lib/cli.mjs +0 -164
  146. package/skills/how-catalyst-works/scripts/lib/credential.mjs +0 -29
  147. package/skills/how-catalyst-works/scripts/whats-running.mjs +0 -65
  148. package/skills/whats-happening/references/reading-the-board.md +0 -43
  149. package/skills/whats-happening/references/reprioritising.md +0 -37
@@ -1,68 +1,38 @@
1
1
  # What each group means
2
2
 
3
- `node scripts/inventory.mjs` sorts every environment variable name it finds into exactly one of
4
- three groups. This page explains what each one means and why a name lands where it does — it never
5
- restates a value, because the scan itself never reads one.
3
+ `node scripts/inventory.mjs` sorts every environment variable name it finds into exactly one of three groups. This page explains why a name lands where it does; the scan never reads a value.
6
4
 
7
5
  ## build/test
8
6
 
9
- Needed to install, build and run the tests in a container. This is the default group: a name lands
10
- here unless something specific pulls it into `deploy-only` or `bindings`. Examples: a name read by
11
- the repository's own source (`process.env.X`), a name documented in a `.env.example`-shaped file, a
12
- name a non-deploy workflow job uses.
7
+ Needed to install, build and run the tests in a container. This is the default group: a name lands here unless something specific pulls it into `deploy-only` or `bindings`. Examples: a name the source reads (`process.env.X`), a name in a `.env.example`-shaped file, a name a non-deploy workflow job uses.
13
8
 
14
- The scan does not read `package.json` scripts. A name that only a script's own shell line mentions
15
- and nothing else refers to is therefore not listed — add it by hand if the container needs it.
9
+ The scan does not read `package.json` scripts. A name only a script's shell line mentions is therefore not listed; add it by hand if the container needs it.
16
10
 
17
- A name referenced from **both** a deploy job and a non-deploy job (or build step) still lands here,
18
- not in `deploy-only` — a container that builds and tests the repository needs it too, so the
19
- stricter requirement wins.
11
+ A name referenced from **both** a deploy job and a non-deploy job (or build step) lands here, because a container that builds and tests the repository needs it too.
20
12
 
21
13
  ## deploy-only
22
14
 
23
- A CI secret used **only** by a job the scan classifies as deploying something: a workflow job that
24
- sets `environment:`, whose id looks like `deploy`, `publish`, `release` or `cd`, or that runs a
25
- recognised deploy command (`wrangler deploy`, `npm publish`, `gh release create`, and similar). If
26
- the same name is referenced anywhere outside a deploy job, it moves to `build/test` instead.
27
-
28
- Its local value comes from a CI secret — something a repository or organisation admin sets in the
29
- CI provider, not something a person types into a local `.env` file.
15
+ A CI secret used **only** by a job the scan classifies as deploying: a workflow job that sets `environment:`, whose id looks like `deploy`, `publish`, `release` or `cd`, or that runs a recognised deploy command (`wrangler deploy`, `npm publish`, `gh release create`, and similar). A reference anywhere outside a deploy job moves the name to `build/test`. Its local value is a CI secret a repository or organisation admin sets in the CI provider.
30
16
 
31
17
  ## bindings
32
18
 
33
- A Cloudflare (or other platform) binding: a name bound to a resource — a KV namespace, a D1
34
- database, a Durable Object, an R2 bucket, a queue — declared in `wrangler.toml`. A binding is not an
35
- environment value a process reads from `process.env`; it is wired up by the platform at deploy
36
- time, which is why this scan keeps the two apart even though both are "names the container needs".
37
-
38
- A `wrangler.toml` binding table names the binding through one attribute's value — `binding = "NAME"`
39
- for most tables, `name = "NAME"` for `durable_objects.bindings` — never through the table's own key.
19
+ A Cloudflare (or other platform) binding: a name bound to a resource (a KV namespace, a D1 database, a Durable Object, an R2 bucket, a queue) declared in `wrangler.toml`. The platform wires it up at deploy time, so it is not a `process.env` value, and the scan keeps the two apart. A binding table names the binding through one attribute's value (`binding = "NAME"` for most tables, `name = "NAME"` for `durable_objects.bindings`), never through the table's own key.
40
20
 
41
21
  ## wrangler.toml `[vars]`: build/test, not a binding, and nothing to declare
42
22
 
43
- A `[vars]` (or `[env.<name>.vars]`) table is different from every other wrangler table: its keys ARE
44
- the names, and their values are committed in `wrangler.toml` itself — checked into the repository,
45
- not a secret and not something a person supplies locally. So a `[vars]` name lands in `build/test`
46
- (it is a plain value a build or test step could read, not a resource binding), and the scan marks it
47
- `needsDeclaration: false`: there is nothing for a customer to declare, because the value is already
48
- sitting in the file everyone can already read.
23
+ A `[vars]` (or `[env.<name>.vars]`) table's keys ARE the names, and their values are committed in `wrangler.toml` itself, readable by everyone. So a `[vars]` name lands in `build/test` as a plain value a step could read, marked `needsDeclaration: false`: there is nothing to declare.
49
24
 
50
25
  ## Where a local value comes from
51
26
 
52
- For every name, "where the local value comes from" is one of:
27
+ For every name, one of:
53
28
 
54
- - **a `.env` file or your shell** — the ordinary case for `build/test`.
55
- - **a CI secret** — for `deploy-only`, and for any `build/test` name whose only non-committed source
56
- is a workflow's `secrets.X` reference.
57
- - **a Cloudflare binding** — for `bindings`; there is no local value to supply, the platform wires
58
- it up.
59
- - **value committed in wrangler.toml — nothing to declare** — for a `[vars]` entry.
29
+ - **a `.env` file or your shell:** the ordinary case for `build/test`.
30
+ - **a CI secret:** for `deploy-only`, and for a `build/test` name whose only non-committed source is a workflow's `secrets.X` reference.
31
+ - **a Cloudflare binding:** for `bindings`; the platform wires it, so there is no local value.
32
+ - `value committed in wrangler.toml — nothing to declare`: for a `[vars]` entry.
60
33
 
61
- None of these is the value itself — only where it would come from, so a person reviewing the list
62
- knows what to check without this tool ever showing them what is actually set.
34
+ Each says where a value would come from, never the value, so a reviewer knows what to check without seeing what is set.
63
35
 
64
36
  ## A `wrangler.jsonc` or `wrangler.json` file
65
37
 
66
- Modern Wrangler configs are often JSONC. This scan does not read them yet — `wrangler.toml` is the
67
- only Cloudflare config format it understands — so a repository configured that way gets a note
68
- saying so, rather than a silent, confidently wrong "no bindings found".
38
+ The scan reads only `wrangler.toml`, so a repository configured with JSONC gets a note saying so rather than a confident "no bindings found".
@@ -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-skills 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,19 +18,18 @@ 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);
31
30
 
32
31
  /**
33
- * ⛔ NEVER `process.exit(code)` STRAIGHT AFTER A WRITE — the same rule `bin/catalyst-skills.js`
32
+ * ⛔ NEVER `process.exit(code)` STRAIGHT AFTER A WRITE — the same rule `bin/launch.js`
34
33
  * states in full, reintroduced here at validate attempt 29 (M-3). When this script's own stdout is a
35
34
  * PIPE — which is how an agent harness runs it — writes are asynchronous, so `process.exit` severs
36
35
  * whatever is still in flight AND STILL REPORTS THE ORIGINAL EXIT CODE. Measured: a `--json` body of
@@ -2,7 +2,7 @@
2
2
  // inventory.mjs — lists the environment variable NAMES this repository needs, grouped build/test,
3
3
  // deploy-only and bindings, each with where it was found, what uses it, and where a local value
4
4
  // would come from. Never reads or prints a value. Offline: no login, no network — wraps
5
- // `catalyst-skills env inventory`.
5
+ // `catalyst env inventory`.
6
6
  import { runCliOffline } from "./lib/cli.mjs";
7
7
 
8
8
  const HELP = `Usage: node scripts/inventory.mjs [path] [--json]
@@ -27,7 +27,7 @@ if (res.stderr) process.stderr.write(res.stderr);
27
27
  await finish(res.code);
28
28
 
29
29
  /**
30
- * ⛔ NEVER `process.exit(code)` STRAIGHT AFTER A WRITE — the same rule `bin/catalyst-skills.js`
30
+ * ⛔ NEVER `process.exit(code)` STRAIGHT AFTER A WRITE — the same rule `bin/launch.js`
31
31
  * states in full, reintroduced here at validate attempt 29 (M-3). When this script's own stdout is a
32
32
  * PIPE — which is how an agent harness runs it — writes are asynchronous, so `process.exit` severs
33
33
  * whatever is still in flight AND STILL REPORTS THE ORIGINAL EXIT CODE. Measured: a `--json` body of
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // lib/cli.mjs — the one way a skill script reaches the Catalyst Cloud SDK and API: by spawning the
3
- // catalyst-skills CLI this bundle installed. It reads customer.json to find that CLI and nothing
3
+ // catalyst CLI this bundle installed. It reads customer.json to find that CLI and nothing
4
4
  // else; it never holds the key itself. This file is a library — run a sibling script with
5
5
  // --help for usage. Per-skill (skills install one directory at a time, so nothing shared outside the
6
6
  // skill would ever be installed) — see runCliOffline below for the one way this skill's copy differs.
@@ -10,7 +10,9 @@ import { join } from "node:path";
10
10
  import { fileURLToPath } from "node:url";
11
11
  import { CONNECT_COMMAND, hasCredential } from "./credential.mjs";
12
12
 
13
- export const PACKAGE = "@catalyst-cloud/catalyst-skills";
13
+ export const PACKAGE = "@catalyst-cloud/cli";
14
+ /** The package ships two commands, so npx needs the one to run named: `npx -p <package> catalyst`. */
15
+ export const NPX_ARGS = ["-p", PACKAGE, "catalyst"];
14
16
  export const CONNECT_HINT = `this machine is not connected to a tenant yet — run: ${CONNECT_COMMAND}`;
15
17
 
16
18
  /** ~/.config/catalyst-cloud/customer.json, honouring CATALYST_SKILLS_HOME before HOME. */
@@ -41,8 +43,8 @@ export function requireCustomerConfig() {
41
43
  }
42
44
 
43
45
  /**
44
- * Run one catalyst-skills verb and return {code, stdout, stderr}. Spawns the CLI whose path the
45
- * connect step recorded in customer.json; falls back to `npx @catalyst-cloud/catalyst-skills` when
46
+ * Run one catalyst verb and return {code, stdout, stderr}. Spawns the CLI whose path the
47
+ * connect step recorded in customer.json; falls back to `npx -p @catalyst-cloud/cli catalyst` when
46
48
  * no path is recorded or it no longer exists. Exits 2 when the machine is not connected.
47
49
  */
48
50
  export function runCli(args, opts = {}) {
@@ -51,12 +53,12 @@ export function runCli(args, opts = {}) {
51
53
  }
52
54
 
53
55
  /**
54
- * Run `catalyst-skills env inventory` / `env check` without requiring a credential at all. Unlike
56
+ * Run `catalyst env inventory` / `env check` without requiring a credential at all. Unlike
55
57
  * every other verb this launcher can reach, `env inventory` and `env check` are LOCAL and OFFLINE —
56
58
  * they never call the cloud — so gating them on `requireCustomerConfig` would break the feature they
57
59
  * exist to provide. Still resolves the recorded `cliPath` when a customer.json happens to exist (so
58
60
  * an already-connected machine reuses the same installed CLI), and still falls back to
59
- * `npx @catalyst-cloud/catalyst-skills` otherwise.
61
+ * `npx -p @catalyst-cloud/cli catalyst` otherwise.
60
62
  */
61
63
  export function runCliOffline(args, opts = {}) {
62
64
  let cfg = null;
@@ -72,7 +74,7 @@ export function runCliOffline(args, opts = {}) {
72
74
  function spawnCli(cfg, args, opts) {
73
75
  const recorded = Boolean(cfg) && typeof cfg.cliPath === "string" && existsSync(cfg.cliPath);
74
76
  const command = recorded ? process.execPath : process.platform === "win32" ? "npx.cmd" : "npx";
75
- const argv = recorded ? [cfg.cliPath, ...args] : [PACKAGE, ...args];
77
+ const argv = recorded ? [cfg.cliPath, ...args] : [...NPX_ARGS, ...args];
76
78
  const res = spawnSync(command, argv, {
77
79
  encoding: "utf8",
78
80
  input: opts.stdin,
@@ -81,7 +83,7 @@ function spawnCli(cfg, args, opts) {
81
83
  shell: !recorded && process.platform === "win32",
82
84
  });
83
85
  if (res.error) {
84
- console.error(`could not run ${recorded ? cfg.cliPath : `npx ${PACKAGE}`}: ${res.error.message}`);
86
+ console.error(`could not run ${recorded ? cfg.cliPath : `npx -p ${PACKAGE} catalyst`}: ${res.error.message}`);
85
87
  process.exit(2);
86
88
  }
87
89
  return { code: res.status ?? 1, stdout: res.stdout ?? "", stderr: res.stderr ?? "" };
@@ -95,7 +97,7 @@ function spawnCli(cfg, args, opts) {
95
97
  export function runCliOrExit(args, opts = {}) {
96
98
  const res = runCli(args, opts);
97
99
  if (res.code === 0) return res;
98
- const why = res.stderr.trim() || res.stdout.trim() || `catalyst-skills ${args.join(" ")} exited ${res.code}`;
100
+ const why = res.stderr.trim() || res.stdout.trim() || `catalyst ${args.join(" ")} exited ${res.code}`;
99
101
  console.error(why);
100
102
  process.exit(res.code === 2 ? 2 : 1);
101
103
  }
@@ -6,12 +6,12 @@
6
6
  //
7
7
  // customer.json carries exactly one credential: a personal key (`key`), or the keyless login's
8
8
  // session (`auth`, the recommended rail). A script never reads either for its value: it spawns the
9
- // catalyst-skills CLI, which authenticates with whichever is present and refreshes a login's token
9
+ // catalyst CLI, which authenticates with whichever is present and refreshes a login's token
10
10
  // itself. A new credential kind lands here, once.
11
11
 
12
12
  /** The command that connects this machine, as every not-connected line names it. */
13
13
  export const CONNECT_COMMAND =
14
- "npx @catalyst-cloud/catalyst-skills login (or, with a personal key: CATALYST_CLOUD_TOKEN=<your personal key> npx @catalyst-cloud/catalyst-skills login)";
14
+ "npx -p @catalyst-cloud/cli catalyst login (or, with a personal key: CATALYST_CLOUD_TOKEN=<your personal key> npx -p @catalyst-cloud/cli catalyst login)";
15
15
 
16
16
  /** True when `cfg` (parsed customer.json) holds a usable credential of either kind. Never throws. */
17
17
  export function hasCredential(cfg) {
@@ -1,43 +1,33 @@
1
1
  ---
2
2
  name: whats-happening
3
3
  description: >-
4
- The desk for a Catalyst Cloud tenant. Use when the person asks "what's happening?", "where are we?", "why is that stuck?", "what closed?", "what's next?", or asks for something to be done rather than known. Reads the tenant contract, what is running and queued, the eligibility explainer and the open asks through the catalyst-skills CLI, and answers in one reply with ticket ids. Routes work to a project owner and decisions to what-needs-me. Never composes a URL, never polls, never answers as the human.
5
- allowed-tools: Bash(catalyst-skills:*) Bash(npx @catalyst-cloud/catalyst-skills:*)
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
+ allowed-tools: Bash(catalyst:*) Bash(npx -p @catalyst-cloud/cli catalyst:*)
6
6
  ---
7
- <!-- vendored-from: @catalyst-cloud/catalyst-skills@0.13.0 — written in this repository for customer tenants -->
7
+ <!-- vendored-from: @catalyst-cloud/catalyst-skills@0.14.0 — 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 tenant. They ask four questions: where are we, why is that stuck, what closed, what is next. You answer each in one reply, from their tenant's data only, with a ticket identifier on every line. When they ask for something to be done, you route it to an owner; when only they can decide something, you raise it through `what-needs-me`.
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
- ## Run first
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
- Scripts are run, never read. Each prints `--help`; exit 2 means this machine is not connected (run the `connect-me` skill), exit 1 means the check itself failed.
16
-
17
- - `node scripts/snapshot.mjs --help` — one JSON document: the trimmed contract (teams, stage names by slot, thresholds, ladder), what is running, the queue, the open asks ranked by what they hold, and the replica verdict. Add `--board` for open tickets grouped by stage in the contract's slot order, `--team K` to narrow.
18
- - `node scripts/explain.mjs --help` — why nothing is offered for one ticket, in one paragraph.
19
-
20
- For a single ticket's comments, relations and linked PRs use the `catalyst-linear` skill (`catalyst-skills query issue <id>`); for a pull request's checks and threads, `catalyst-github`.
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.
21
18
 
22
19
  ## Load on demand
23
20
 
24
- | when | read |
21
+ | question | reference |
25
22
  | -- | -- |
26
- | writing any status answer | `references/status-reply.md` (schema: `assets/status-reply.json`) |
27
- | the board looks wrong, a column is long, or you must decide whether something is stuck | `references/reading-the-board.md` |
28
- | `explain` returned a reason and the person wants the next action | `references/why-is-it-stuck.md` |
29
- | "do this one first", "why is that not next", "stop that" | `references/reprioritising.md` |
30
- | the person asks for work to be done, or a decision surfaces | `references/routing-work.md` |
31
-
32
- For depth beyond these, load the fact skills: `how-catalyst-works` (the ladder, slots and mapping, failure layers, queue order, coding accounts), `catalyst-linear` (what a ticket accumulates, reading and writing), `catalyst-github` (what a PR accumulates, mergeability), `catalyst-setup` (readiness).
33
-
34
- ## Rules
35
-
36
- - **Their tenant, as them.** Every read goes through the CLI, which holds the person's own key, the tenant and who they are. You never name, guess at, or try another tenant, and you never paste the key anywhere. "You" in your reply means the connected person: their assigned tickets, their asks.
37
- - **Tenant facts come from the contract, live.** Stage names, label names, team keys, thresholds and the ladder are in the snapshot's `tenant` block; read them there each time and never restate them from memory.
38
- - **One reply, ticket ids on every line, source named.** The reply opens with when the snapshot was taken and whether the replica or the API answered. A stale replica is stated, never hidden.
39
- - **Say what a key cannot see.** PR labels and reactions are not mirrored; the CLI prints the settings URL, and you repeat it instead of guessing. A park or hold is released from the person's own login once its cause is fixed: route that to the `unstick` skill (`catalyst-skills release`), never tell them it needs an operator. Coding-account status (`accounts`) and per-ticket execution history (`explain --history`) are readable — read them.
40
- - **No polling.** One snapshot per question. Waiting on a change is the project owner's job (`run-this-project` subscribes to the tenant stream); the desk never loops a read.
41
- - **You are not the owner.** You route work and make it visible; you do not dispatch, overrule a project owner, or run long work in this session.
42
- - **Never answer as the human.** A decision is an ask through `what-needs-me`, filed before anyone proceeds on its default; the answer is recorded there as the app actor.
43
- - **Cite an identifier only after a create call returned it.**
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,6 +1,6 @@
1
1
  interface:
2
2
  display_name: "What's happening"
3
- short_description: "Where your Catalyst work stands: in flight, blocked and on whom, closed, and what runs next"
3
+ short_description: "Where your Catalyst work stands and how Catalyst decides: in flight, blocked and on whom, closed, what runs next, and why"
4
4
  default_prompt: "Use $whats-happening to tell me where my work stands and why anything is stuck."
5
5
  policy:
6
6
  allow_implicit_invocation: true
@@ -0,0 +1,11 @@
1
+ # Coding accounts
2
+
3
+ snapshot.mjs --accounts omits credentials/emails. An owner/admin enrols, pauses, removes or replaces credentials at `<their cloud>/settings/coding-accounts`.
4
+
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
+
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
+
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.
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,36 +1,7 @@
1
- # Routing work
1
+ # Route requests
2
2
 
3
- This reference restates an invariant: what this skill does when the person asks for something to be done rather than known, and where a decision goes. Nothing here is tenant-specific.
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
- ## Three kinds of request
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.
6
6
 
7
- A message from the person is one of three things, and you decide which in the first sentence of your reply:
8
-
9
- 1. **A question.** "Where is X? Why is Y stuck? What closed today?" Answer it in the one-reply shape (`references/status-reply.md`). No routing.
10
- 2. **A request for work.** "Get X done. Ship the Y change. Own this until it closes." Turn it into a project with an owner, in one pass, as below.
11
- 3. **A decision only they can make**, surfaced by you or by the cloud. That is never answered here; it goes to `what-needs-me`.
12
-
13
- A request that contains a decision is both: route the work and raise the decision, and say in the reply that you did both.
14
-
15
- ## A request becomes a project with an owner, in one pass
16
-
17
- You hold no authority over project owners. Your job is to make the work visible and hand it to a single-threaded owner, then get out of the way.
18
-
19
- 1. **Find the existing home first.** `catalyst-skills query projects` and `query search <terms>`. A request that fits an open project is a ticket in that project, not a new project. Duplicate projects split one goal's status across two places.
20
- 2. **Scaffold when there is no home.** State the outcome in one sentence, the first ticket or two, and who owns it. Tickets are created through the `catalyst-linear` skill (the app actor, the team key from the contract); a project itself is created by the person in Linear, so name what you want it called and ask them to create it if none fits.
21
- 3. **Name the owner.** The owner is a `run-this-project` session for that project, or a person. Say which, in the reply. Tell the person the one command that starts the owner session, and do not start long-running work inside this session: the desk answers questions; the owner reacts to events.
22
- 4. **Say what you did.** The reply ends with the identifiers created, the owner named, and the next thing the person will see.
23
-
24
- Cite an identifier only after the create call returned it. A guessed number is usually a real, unrelated ticket.
25
-
26
- ## What goes to what-needs-me
27
-
28
- Anything that gates active work on a choice only the human can make: a product call, a priority call between two things that cannot both go first, an approval, or an action only they can physically take (a click in settings, a credential). It is raised as an ask through the `what-needs-me` skill with the question, the options, the default that fires if they stay silent, and what it blocks, and it is raised **before** anyone proceeds on the default.
29
-
30
- Not an ask: brainstorming, a design back-and-forth, a question the person asked first, a retry-or-abandon call an owner can make, a provider outage (that is one status line, not a per-ticket question).
31
-
32
- ## Three rules that bind this skill
33
-
34
- - **Never answer as the human.** You do not pick an option on an open ask, close one, or post in their voice. When their answer arrives in chat, it is recorded on the ask through `what-needs-me` so the record is complete, and it is recorded as the app actor, never as them.
35
- - **Escalate inward, never outward.** An instrument reports to the project owner; the owner asks the desk; the desk asks the human, as an ask. A single stuck ticket is never a page to the human. A system-level failure (provider down, out of capacity, rate-limited) is one line in the status reply, not a question per ticket.
36
- - **One door.** If the person needs a second place to look after your reply, add the missing block to the reply next time rather than pointing them at a dashboard.
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.
@@ -0,0 +1,17 @@
1
+ # Settings
2
+
3
+ Use live values and the person's cloud prefix. Owner/admin acts unless stated. Name screen, route, rule.
4
+
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. |
@@ -0,0 +1,19 @@
1
+ # Stages
2
+
3
+ Slots are board positions; stages are Linear states. teams[].stages maps them per team; show-my-map.mjs stars required slots.
4
+
5
+ Order: dispatch, intake, research, plan, implement, remediate, verify, review, pr, done, canceled.
6
+
7
+ | required slot | allowed Linear type | purpose |
8
+ | -- | -- | -- |
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 |
14
+
15
+ Missing/wrong required mappings stop work; others warn. Dispatch/pr/done/canceled must be live. `teams[].gitAutomation` stores consent; nothing reads it.
16
+
17
+ workflowMode: adopted means Catalyst-created, mapped means human-chosen, mixed means both. Configure at `<their cloud>/settings/linear-teams`, never catalyst.toml.
18
+
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,36 +1,16 @@
1
- # The one-reply shape
1
+ # Status
2
2
 
3
- This reference restates an invariant of this skill: how a status answer is shaped. The facts inside it come live from `node scripts/snapshot.mjs` and `node scripts/explain.mjs`; the machine-readable schema is `assets/status-reply.json`.
3
+ Open with takenAt, source and replica cursor/API reason. Then:
4
4
 
5
- ## The rule
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
- The person asked one question and gets one reply. If they would need a second surface, a second message, or a follow-up question from you to know where things stand, the reply is wrong. Every line names a ticket identifier. Nothing in the reply is a guess: a fact you could not read is named as unreadable, with where it lives.
12
+ Lines use identifier, contract stage, then one clause. Age uses updated_at/lease start and expected phase duration. Omit empty blocks.
8
13
 
9
- ## The five blocks, in this order
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.
10
15
 
11
- 1. **In flight.** Tickets a phase is running on right now, or that hold a live lease mid-ladder. Source: the snapshot's `running` block (fleet activity, the agent roster, lease attributions). One line per ticket: identifier, the phase running, how long it has run.
12
- 2. **Blocked, and on whom.** Tickets nothing is offered for. Source: the queue's excluded rows, then `explain` on each one the person cares about. Every line carries the reason in the person's words and who releases it: the human (an ask), a role, the cloud itself (a backoff, a park that self-releases), or a clock. "On whom" is never blank; if you cannot tell, say the reason the cloud gave and that the release is unknown to a key.
13
- 3. **Waiting on the human.** The open asks, ranked by what each one holds. Source: `waitingOnHuman` in the snapshot. Keep this to identifier, the question, and what it releases; the `what-needs-me` skill owns the detail and the settling.
14
- 4. **Closed.** What reached the done slot in the window the person asked about (or since your last reply). Source: `query issues` filtered by the team's done-slot stage name from the contract, or the change feed for a time window. When you did not read a window, say "since my last reply" and mean it.
15
- 5. **Next.** What the queue picks up next, in the cloud's order, with the phase each will run. Source: the snapshot's `queue` block. Do not reorder it to what you think should be next; the levers are in `references/reprioritising.md`.
16
-
17
- A sixth block, **cannot see**, appears only when it is non-empty: the facts your key cannot read (PR labels and reactions, which are not mirrored; an operator-only park release), each with the URL the CLI printed.
18
-
19
- A flow number is named in that block by name, not left out: cycle time, throughput, or how long pull requests have been open are not computed by anything a key reads today. Say they are not computed rather than counting ticket dates or open pull requests and calling it that.
20
-
21
- ## The header line
22
-
23
- The reply opens with one clause that says when and from where: the snapshot's `takenAt` and its source line. When the replica was stale or absent, the reply says the numbers came from the API; when it was fresh, it says the cursor. This is not decoration. A stale source that goes unmentioned is the way a wrong status reply happens.
24
-
25
- ## Writing the lines
26
-
27
- - Identifier first, then the stage as the contract spells it for that team, then one clause. `KEY-123 · <stage name> · implement running 14 min`.
28
- - Age in human units (minutes, hours, days), from `updated_at` or the lease's start, never a raw timestamp.
29
- - A reason is the translation from `references/why-is-it-stuck.md`, not the cloud's snake_case token, unless the token is one the table does not know, in which case quote it as the cloud spelled it.
30
- - No adjectives about health. "Stuck" has a definition (`references/reading-the-board.md`); use it only when it applies.
31
-
32
- ## What the reply never does
33
-
34
- - It never restates a stage name, threshold or label from memory. The snapshot's `tenant` block carries the live values; read them there each time.
35
- - It never answers an ask, proposes a default on the human's behalf inside the status reply, or moves anything. Routing a request is `references/routing-work.md`; a decision is the `what-needs-me` skill.
36
- - It never pads a short answer. When one ticket is in flight and nothing is blocked, the reply is three lines.
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.
@@ -0,0 +1,20 @@
1
+ # Phases
2
+
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
+
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
+
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 |
17
+
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.
19
+
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.
@@ -0,0 +1,13 @@
1
+ # Dispatch
2
+
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
+
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
+
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
+
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.
10
+
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.
12
+
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.
@@ -0,0 +1,21 @@
1
+ # Failures
2
+
3
+ Quote live show-my-map.mjs thresholds; these are defaults. Failure itself moves no card.
4
+
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
+
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
+
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 |
20
+
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.