@catalyst-cloud/cli 0.9.5 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +28 -29
  3. package/dist/args.js +19 -1
  4. package/dist/ask.js +30 -18
  5. package/dist/capabilities.js +5 -0
  6. package/dist/cli.js +24 -6
  7. package/dist/env/declaration-rules.js +163 -0
  8. package/dist/env/group.js +51 -0
  9. package/dist/env/inventory.js +102 -0
  10. package/dist/env/render.js +39 -0
  11. package/dist/env/scan-env-example.js +62 -0
  12. package/dist/env/scan-source.js +43 -0
  13. package/dist/env/scan-workflow.js +123 -0
  14. package/dist/env/scan-wrangler.js +120 -0
  15. package/dist/env/types.js +1 -0
  16. package/dist/env/walk.js +87 -0
  17. package/dist/env.js +76 -0
  18. package/dist/environment.js +1 -1
  19. package/dist/legacy.js +224 -0
  20. package/dist/project.js +129 -0
  21. package/dist/release.js +1 -1
  22. package/dist/repo.js +297 -0
  23. package/dist/runtime-verb.js +1 -1
  24. package/dist/secret.js +1 -1
  25. package/dist/skill-shape.js +21 -13
  26. package/dist/skills.js +44 -4
  27. package/dist/transport.js +26 -1
  28. package/package.json +7 -6
  29. package/skills/catalyst-github/SKILL.md +7 -7
  30. package/skills/catalyst-github/references/is-it-mergeable.md +8 -2
  31. package/skills/catalyst-github/references/what-a-pr-accumulates.md +3 -3
  32. package/skills/catalyst-github/scripts/is-it-mergeable.mjs +3 -3
  33. package/skills/catalyst-github/scripts/lib/cli.mjs +9 -7
  34. package/skills/catalyst-github/scripts/lib/credential.mjs +2 -2
  35. package/skills/catalyst-github/scripts/read-pr.mjs +2 -2
  36. package/skills/catalyst-linear/SKILL.md +17 -19
  37. package/skills/catalyst-linear/agents/openai.yaml +1 -1
  38. package/skills/catalyst-linear/agents/portability.yaml +1 -1
  39. package/skills/catalyst-linear/references/reading-a-ticket.md +9 -26
  40. package/skills/catalyst-linear/references/what-a-ticket-accumulates.md +2 -2
  41. package/skills/catalyst-linear/references/writing-to-linear.md +7 -9
  42. package/skills/catalyst-linear/scripts/comment.mjs +1 -1
  43. package/skills/catalyst-linear/scripts/create-ticket.mjs +1 -1
  44. package/skills/catalyst-linear/scripts/label.mjs +1 -1
  45. package/skills/catalyst-linear/scripts/lib/cli.mjs +9 -7
  46. package/skills/catalyst-linear/scripts/lib/credential.mjs +2 -2
  47. package/skills/catalyst-linear/scripts/move.mjs +1 -1
  48. package/skills/catalyst-linear/scripts/read-ticket.mjs +1 -1
  49. package/skills/catalyst-linear/scripts/search.mjs +1 -1
  50. package/skills/catalyst-onboard/SKILL.md +37 -57
  51. package/skills/catalyst-onboard/agents/openai.yaml +2 -2
  52. package/skills/catalyst-onboard/agents/portability.yaml +1 -1
  53. package/skills/catalyst-onboard/references/connecting-this-machine.md +35 -0
  54. package/skills/catalyst-onboard/references/declaring-a-repository.md +7 -17
  55. package/skills/catalyst-onboard/references/local-sync.md +19 -7
  56. package/skills/catalyst-onboard/references/reading-ready.md +79 -0
  57. package/skills/catalyst-onboard/references/replacing-a-credential.md +8 -33
  58. package/skills/catalyst-onboard/references/repository-agent-setup.md +23 -0
  59. package/skills/catalyst-onboard/references/skill-sources.md +13 -19
  60. package/skills/catalyst-onboard/references/the-one-path.md +18 -74
  61. package/skills/catalyst-onboard/references/what-a-phase-needs.md +21 -28
  62. package/skills/catalyst-onboard/references/what-the-browser-owns.md +20 -37
  63. package/skills/{catalyst-setup → catalyst-onboard}/scripts/check.mjs +10 -9
  64. package/skills/catalyst-onboard/scripts/lib/cli.mjs +6 -4
  65. package/skills/catalyst-onboard/scripts/lib/credential.mjs +2 -2
  66. package/skills/catalyst-onboard/scripts/where-am-i.mjs +60 -4
  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 +9 -12
  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 +31 -0
  96. package/skills/what-this-repo-needs/agents/openai.yaml +6 -0
  97. package/skills/what-this-repo-needs/agents/portability.yaml +4 -0
  98. package/skills/what-this-repo-needs/references/what-each-group-means.md +38 -0
  99. package/skills/what-this-repo-needs/scripts/check.mjs +64 -0
  100. package/skills/what-this-repo-needs/scripts/inventory.mjs +61 -0
  101. package/skills/{catalyst-setup → what-this-repo-needs}/scripts/lib/cli.mjs +35 -22
  102. package/skills/{catalyst-setup → what-this-repo-needs}/scripts/lib/credential.mjs +2 -2
  103. package/skills/whats-happening/SKILL.md +27 -21
  104. package/skills/whats-happening/agents/openai.yaml +1 -1
  105. package/skills/whats-happening/references/coding-accounts.md +24 -0
  106. package/skills/whats-happening/references/routing-work.md +11 -29
  107. package/skills/whats-happening/references/settings-and-where-they-live.md +20 -0
  108. package/skills/whats-happening/references/stages-and-mapping.md +25 -0
  109. package/skills/whats-happening/references/status-reply.md +21 -21
  110. package/skills/whats-happening/references/the-ladder.md +30 -0
  111. package/skills/whats-happening/references/what-runs-next.md +32 -0
  112. package/skills/whats-happening/references/when-a-phase-fails.md +27 -0
  113. package/skills/whats-happening/references/why-is-it-stuck.md +33 -40
  114. package/skills/whats-happening/scripts/explain.mjs +1 -1
  115. package/skills/whats-happening/scripts/lib/cli.mjs +7 -5
  116. package/skills/whats-happening/scripts/lib/credential.mjs +2 -2
  117. package/skills/{how-catalyst-works → whats-happening}/scripts/show-my-map.mjs +18 -32
  118. package/skills/whats-happening/scripts/snapshot.mjs +10 -6
  119. package/skills/catalyst-onboard/references/choosing-a-coding-account.md +0 -52
  120. package/skills/catalyst-onboard/references/who-fixes-what.md +0 -64
  121. package/skills/catalyst-setup/SKILL.md +0 -36
  122. package/skills/catalyst-setup/agents/openai.yaml +0 -6
  123. package/skills/catalyst-setup/agents/portability.yaml +0 -4
  124. package/skills/catalyst-setup/references/what-each-check-means.md +0 -88
  125. package/skills/catalyst-setup/scripts/replica-status.mjs +0 -46
  126. package/skills/connect-me/SKILL.md +0 -63
  127. package/skills/connect-me/agents/openai.yaml +0 -6
  128. package/skills/connect-me/agents/portability.yaml +0 -5
  129. package/skills/connect-me/references/keeping-the-replica-running.md +0 -88
  130. package/skills/connect-me/scripts/lib/cli.mjs +0 -185
  131. package/skills/connect-me/scripts/lib/credential.mjs +0 -29
  132. package/skills/connect-me/scripts/verify-connection.mjs +0 -68
  133. package/skills/how-catalyst-works/SKILL.md +0 -43
  134. package/skills/how-catalyst-works/agents/openai.yaml +0 -6
  135. package/skills/how-catalyst-works/agents/portability.yaml +0 -4
  136. package/skills/how-catalyst-works/references/coding-accounts.md +0 -51
  137. package/skills/how-catalyst-works/references/stages-and-mapping.md +0 -56
  138. package/skills/how-catalyst-works/references/the-ladder.md +0 -41
  139. package/skills/how-catalyst-works/references/what-catalyst-is.md +0 -30
  140. package/skills/how-catalyst-works/references/what-runs-next.md +0 -88
  141. package/skills/how-catalyst-works/references/when-a-phase-fails.md +0 -57
  142. package/skills/how-catalyst-works/scripts/explain-ticket.mjs +0 -41
  143. package/skills/how-catalyst-works/scripts/lib/cli.mjs +0 -164
  144. package/skills/how-catalyst-works/scripts/lib/credential.mjs +0 -29
  145. package/skills/how-catalyst-works/scripts/whats-running.mjs +0 -65
  146. package/skills/whats-happening/references/reading-the-board.md +0 -43
  147. package/skills/whats-happening/references/reprioritising.md +0 -37
@@ -1,45 +1,43 @@
1
1
  ---
2
2
  name: run-this-project
3
3
  description: >-
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 tenant stream for the scope through the catalyst-skills 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
- disable-model-invocation: true
6
- allowed-tools: Bash(catalyst-skills:*) Bash(npx @catalyst-cloud/catalyst-skills:*)
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
+ allowed-tools: Bash(catalyst:*) Bash(npx -p @catalyst-cloud/cli catalyst:*)
7
6
  ---
8
- <!-- vendored-from: @catalyst-cloud/catalyst-skills@0.9.5 — written in this repository for customer tenants -->
7
+ <!-- vendored-from: @catalyst-cloud/catalyst-skills@0.13.1 — written in this repository for customer accounts -->
9
8
 
10
9
  # Run this project
11
10
 
12
- You are the steward: the single-threaded owner of ONE project or ticket set, from now until it closes. The person says "run this project for me" and hands you a scope. Catalyst does the phases; you make work ready and visible, react to what happens, unblock, and keep one status summary the person can read. You hold no authority over other stewards and you are not the desk; `whats-happening` is the desk.
11
+ You are the steward: the single-threaded owner of ONE project or ticket set until it closes. Catalyst runs the phases; you make work ready and visible, react to what happens, unblock, and keep one status summary the person can read. `whats-happening` is the desk; other stewards are peers.
13
12
 
14
13
  ## Run first
15
14
 
16
- Scripts are run, never read. Each prints its own `--help`.
15
+ Scripts are run, never read. Each prints `--help`, and exits 2 when this machine is not connected (`catalyst login`), 1 when its own check fails.
17
16
 
18
- 1. `node scripts/scope-status.mjs --project <id>` (or `--team <key>`): tickets by stage in the contract's order, what is running and queued in scope, and stalls against the local policy. Run it once to take the scope, and again after any resync.
19
- 2. `node scripts/watch-scope.mjs --project <id>`: the subscription. In Claude Code, arm a monitor on it and react to each printed line in the same turn. In a harness with no monitor, add `--exec <command>` so a reaction still runs per frame.
20
- 3. `node scripts/make-ready.mjs <ticket>` to dispatch; `--park` to stop; `--note <why>` to record it.
21
- 4. `catalyst-skills explain <ticket>` whenever a ticket is not moving: one paragraph naming the reason and what releases it.
22
-
23
- Every script exits 2 when this machine is not connected (run `catalyst-skills login`), 1 when its own check fails.
17
+ 1. `node scripts/scope-status.mjs --project <id>` (or `--team <key>`): tickets by stage, what is running and queued in scope, and stalls against the local policy. Run it to take the scope, and again after a resync.
18
+ 2. `node scripts/watch-scope.mjs --project <id>`: the subscription. In Claude Code, arm a monitor on it and react to each printed line in the same turn; elsewhere add `--exec <command>` so a reaction runs per frame.
19
+ 3. `node scripts/make-ready.mjs <ticket>` dispatches; `--park` stops; `--note <why>` records it.
20
+ 4. `catalyst explain <ticket>` whenever a ticket is not moving.
24
21
 
25
22
  ## Load on demand
26
23
 
27
24
  | when | read |
28
25
  | -- | -- |
29
- | arming the watch, deciding what a frame means, a reaction failed, a resync line printed | `references/reacting-to-events.md` |
30
- | dispatching or parking a ticket, judging whether a phase actually ran, writing a ticket for Catalyst | `references/making-work-ready.md` |
31
- | something is not moving, tuning the stall policy, deciding whether a human needs to hear about it | `references/stalls-and-escalation.md` |
32
- | the exclusion vocabulary in depth, the ladder, this team's stage map | the `how-catalyst-works` skill |
26
+ | arming the watch, reading a frame, a failed reaction, a resync | `references/reacting-to-events.md` |
27
+ | dispatching or parking, judging whether a phase ran, writing a ticket for Catalyst | `references/making-work-ready.md` |
28
+ | something is not moving, tuning the stall policy, whether a human needs to hear | `references/stalls-and-escalation.md` |
29
+ | what an exclusion reason means, the ladder, the stage map | the `whats-happening` skill |
33
30
  | raising or settling a decision | the `what-needs-me` skill |
34
- | a PR's checks, review and merge legs | the `catalyst-github` skill |
31
+ | a PR's checks, review and merge | the `catalyst-github` skill |
35
32
 
36
33
  ## Rules
37
34
 
38
- - **React, never poll.** A loop that re-reads the API or the replica is a defect. The stream and the cursor file are the mechanism; a reaction that throws leaves the cursor so the frame is offered again.
39
- - **Dispatch is a card move.** The cloud takes work from the dispatch column and writes every later stage itself. Your two moves are into dispatch and into the backlog; never hand-move a card into a ladder stage.
40
- - **Evidence a phase ran is the outcome comment, the attached document and the agent session,** not the clock and not the card's column.
41
- - **Tenant facts come from the contract, live.** Never restate a stage name, label id, team id, threshold or template in prose; run `catalyst-skills contract --path <a.b.c>` when you need one.
42
- - **Escalate inward.** Instrument, then you, then the desk, then the human as an ask filed through `what-needs-me` with what it blocks. Decide the technical calls yourself; take the sane default and record it; a fleet or provider condition is one note, never one ask per ticket.
43
- - **Reply where the message arrived,** in-thread, tagged, as the app actor. Never post as the human, never answer someone else's ask. Bookkeeping records take the contract's marker (`catalyst-skills write comment --bookkeeping`).
44
- - **One status summary,** kept current after every reaction: in flight, blocked and on whom, closed, next, each line with a ticket id. Where a human decision is pending, the line carries the ask's id.
45
- - **Say what a key cannot see.** PR labels and reactions are not mirrored; the CLI says so by name and points at settings. A park or hold is released from the person's own login once its cause is fixed, through the `unstick` skill (`catalyst-skills release`). Execution history (`explain --history`) and coding-account status (`accounts`) ARE readable — read them rather than reconstructing them from comments.
35
+ - **React to the stream.** The watch and its cursor file are the mechanism, and a reaction that throws leaves the cursor so the frame is offered again. Re-reading the API or the replica in a loop is a defect.
36
+ - **Dispatch is a card move.** Your two moves are into dispatch and into the backlog; the cloud writes every ladder stage itself.
37
+ - **A phase ran when its outcome comment, attached document and agent session say so,** not when the clock or the column suggests it.
38
+ - **Account facts come from the contract, live** (`catalyst contract --path <a.b.c>`), never from prose.
39
+ - **Escalate inward:** instrument, you, the desk, then the human as an ask through `what-needs-me` naming what it blocks. Decide technical calls yourself and record the default; a fleet or provider condition is one note, never one ask per ticket.
40
+ - **Say what a write costs.** Every move and comment spends the contract's daily write budget as the app actor, and a move into dispatch starts paid work on a coding account. Read the verdict `make-ready.mjs` prints before the next move.
41
+ - **Reply where the message arrived,** in-thread, tagged, as the app actor. The human speaks for themselves, and each ask belongs to its own addressee. Bookkeeping records take the contract's marker (`catalyst write comment --bookkeeping`).
42
+ - **One status summary,** current after every reaction: in flight, blocked and on whom, closed, next, each line with a ticket id, and a pending decision's line with its ask id.
43
+ - **Releases belong to `unstick`.** Once the cause is fixed, the person's own login releases a park or most holds through the `unstick` skill (`catalyst release`); a round-threshold hold and a review that will not converge refuse it. PR labels and reactions are not mirrored; execution history (`explain --history`) and coding accounts (`catalyst accounts`) are readable.
@@ -3,4 +3,4 @@ interface:
3
3
  short_description: "Own one Catalyst project end to end: react to its events, make tickets ready, chase stalls, escalate inward"
4
4
  default_prompt: "Use $run-this-project to run project <id> for me until it closes."
5
5
  policy:
6
- allow_implicit_invocation: false
6
+ allow_implicit_invocation: true
@@ -1,5 +1,5 @@
1
1
  identity: { pack: catalyst-cloud-skills, skill: run-this-project }
2
2
  effects: [external-write]
3
3
  mutating: true
4
- invocation: explicit
4
+ invocation: implicit
5
5
  exposure: [catalog]
@@ -1,60 +1,43 @@
1
1
  # Making work ready
2
2
 
3
- This reference restates invariants of how Catalyst takes work. The tenant's own values (which Linear state is the dispatch column, which state is the backlog, the ask and release label ids, the round cap and the park threshold) are read live from `catalyst-skills contract`; the scripts here never name a stage.
4
-
5
- ## The steward's two moves
6
-
7
- Catalyst does not take work by being asked. It takes work by finding a card in the team's dispatch column and offering that card's next phase to a runner. So the steward's dispatch verb is a card move, and its stop verb is a card move:
3
+ Catalyst takes work by finding a card in the team's dispatch column and offering its next phase to a runner. So the steward's dispatch and stop verbs are both card moves:
8
4
 
9
5
  ```sh
10
- node scripts/make-ready.mjs ENG-41 # move into the dispatch column; the cloud offers the next phase
11
- node scripts/make-ready.mjs ENG-41 --park # move into the team's backlog-type state; nothing further is offered
6
+ node scripts/make-ready.mjs ENG-41 # into the dispatch column
7
+ node scripts/make-ready.mjs ENG-41 --park # into the team's backlog-type state
12
8
  node scripts/make-ready.mjs ENG-41 --park --note "waiting on the vendor's API change"
13
9
  ```
14
10
 
15
- Dispatch resolves the dispatch slot on the ticket's team from the contract. Parking resolves the team's first backlog-type state from its live workflow states, because the backlog is deliberately not one of the eleven slots. Those are the only two state moves you make. Every other stage move on a ticket in the ladder is the cloud's, written when a phase completes; moving a card forward by hand does not run a phase, it only confuses the advance table, and moving it backwards by hand does not undo one.
11
+ Dispatch resolves the team's dispatch slot from the contract; parking resolves the team's first backlog-type state from its live workflow, since the backlog is not a slot. Every other stage on a ticket in the ladder is the cloud's record of what ran: a hand move forward runs nothing, and a hand move back undoes nothing.
16
12
 
17
13
  ## What a dispatchable ticket carries
18
14
 
19
- Before the move, the ticket needs, in the record itself:
15
+ A phase agent reads the ticket, not your chat. Read it in full, then check it has:
20
16
 
21
- - A title that states the outcome. A phase agent reads the ticket, not your chat.
22
- - A description that says what done looks like: the behaviour, the constraints, the files or surfaces if you know them, acceptance criteria a validate phase can check.
23
- - The right team. The team key is the ticket prefix, and the team's stage map and labels are what the cloud will use.
24
- - A priority. Queue order inside a team is priority first, then creation time, then identifier, so an unset priority sorts last.
25
- - No live blocking relation. A ticket with an open blocker is excluded as `blocked` until the blocker closes.
26
- - No ask on it. A ticket that carries the ask label, or whose own text reads as a decision request (an ask-shaped title, lettered options, a "default if silent" line), is excluded as a question rather than work. If a real ticket trips the shape detector, a human applies the release label named in the contract's vocabulary; you can also rewrite the text so it reads as work.
27
- - Declared scope when the team enforces it: a ticket whose declared files overlap a ticket already in flight is held as `scope_overlap` for the implement phase.
17
+ - a title stating the outcome, and a description of what done looks like (behaviour, constraints, files or surfaces, acceptance criteria validate can check);
18
+ - the right team (the prefix; its stage map and labels are what the cloud uses) and a priority (unset sorts last);
19
+ - no live blocking relation, which excludes it as `blocked`;
20
+ - no ask: an ask label, or text that reads as a decision request, excludes it as a question. A human applies the contract's release label to a false positive; you can rewrite the text so it reads as work;
21
+ - declared scope when the team enforces it, and no file overlap with a ticket in flight (`scope_overlap`). Serialise two tickets that touch the same files.
28
22
 
29
- A ticket does not need a branch, a PR, or any artifact to be dispatched: the ladder creates those. A ticket that has never entered the ladder starts at intake when the tenant enables it, otherwise at research.
23
+ It needs no branch, PR or artifact; the ladder makes those, starting at intake when the account has it on, else research.
30
24
 
31
25
  ## After the move
32
26
 
33
- `make-ready.mjs` asks the eligibility explainer as soon as the move lands and prints the verdict. Read it as follows:
34
-
35
- - `offered` or `eligible` with a queue position: done; a runner will pick it up in the next dispatch pass, ordered by priority, then age, then identifier, with tickets already mid-ladder ahead of fresh ones.
36
- - An ordering that is stale or never published: the cloud re-derives the team's queue within a pass of the move; ask again in a minute with `catalyst-skills explain <ticket>`.
37
- - Any other exclusion reason: the paragraph names it and what releases it. The reasons and what unblocks each are in `how-catalyst-works` and in `whats-happening`'s "why is it stuck" reference.
27
+ `make-ready.mjs` prints the explainer's verdict. A queue position means a runner will pick it up in order. A stale or unpublished ordering is re-derived within a pass; ask again in a minute with `catalyst explain <ticket>`. Any other reason is in the `whats-happening` skill's `references/why-is-it-stuck.md`.
38
28
 
39
29
  ## Evidence a phase ran
40
30
 
41
- Do not infer progress from time passing. A phase leaves three kinds of evidence on the ticket, and a card move alone is not one of them:
42
-
43
- 1. **The outcome comment.** The cloud posts a card per phase: a completed phase names the phase, the attempt, and its artifact; a failed phase names the phase, the attempt, and the failure class, and may carry a park or hold block. A remediate round posts its own attempt card with the round number and the class it is repairing. These arrive as comment frames on the watch.
44
- 2. **The attachment and document.** Each artifact-bearing phase (research, plan, implement, validate, pr, remediate) is projected to a Linear document titled with the ticket, the phase, the attempt and the date, attached to the ticket, with a short link comment. Research and plan on a ticket with a project also appear as a project link.
45
- 3. **The agent session.** The ticket's agent session carries the ladder as its plan, with the phases before the current one completed, the current one in progress, and the rest pending; its activities are the phase start, the gate, artifacts written, the PR opened, and the report.
46
-
47
- The card's stage is the fourth, weakest signal: a completed phase moves the card to the stage the advance table names, a failed phase writes no stage at all, and Done is written only when the pull request actually merges, by the merge webhook, never by a phase. A card sitting in a stage tells you which phase last finished, not whether the next one is running; `scripts/scope-status.mjs` shows running and leased phases beside the stage for exactly that reason.
31
+ Time passing proves nothing. A phase leaves three kinds of evidence on the ticket:
48
32
 
49
- ## Parking, and what it does not do
33
+ 1. **The outcome comment.** Per phase: the phase, the attempt, and its artifact, or on failure the failure class and any park or hold block. A remediate round posts its own card with the round number. These arrive as comment frames.
34
+ 2. **The document.** Each artifact-bearing phase attaches a Linear document with a short link comment.
35
+ 3. **The agent session.** Its plan is the ladder, with the current phase in progress; its activities are the phase start, the gate, the artifacts, the PR, and the report.
50
36
 
51
- Parking is the lever that stops the cloud offering more rounds on a ticket: moved out of the dispatch column and the ladder's stages, the ticket is excluded at the next offer. It does not kill a phase that is already running under a lease; that container finishes its phase, posts its outcome, and the next offer finds the card parked. If you park a ticket the cloud has itself parked (three consecutive failures, or the remediate round cap), record why in a bookkeeping note. Releasing a cloud park is not a card move: once its cause is fixed, the `unstick` skill releases it with `catalyst-skills release <ticket>`, and only a refusal that names a person's action becomes an ask.
37
+ The card's stage is the weakest signal: a completed phase moves it, a failed one writes nothing, and Done is written only when the pull request merges. `scope-status.mjs` shows running and leased phases beside each stage for that reason.
52
38
 
53
- Un-parking is the same dispatch move again. The counted attempts and rounds do not reset when a card comes back; the contract's thresholds say how many remain.
39
+ ## Parking
54
40
 
55
- ## What you never do to make work ready
41
+ Parking stops the cloud offering further rounds: the card is excluded at the next offer. A phase already running under a lease finishes and posts its outcome first. Un-parking is the dispatch move again, and counted attempts and rounds carry over. A cloud park (three consecutive failures, or the round cap) is not a card move: once its cause is fixed, the `unstick` skill releases it with `catalyst release <ticket>`, and only a refusal that names a person's action becomes an ask. When you park a ticket the cloud already parked, record why in a bookkeeping note.
56
42
 
57
- - Never move a card into a research, plan, implement, validate, PR, done or canceled stage by hand to "skip ahead". The cloud reads those stages as the record of what ran.
58
- - Never remove an ask label or apply the release label yourself; a human decides whether a ticket is a question.
59
- - Never dispatch two tickets that touch the same files at once; serialise them or let the second one wait as `scope_overlap`.
60
- - Never dispatch a ticket you have not read in full.
43
+ Ask labels and the release label are a human's call; leave them as you find them.
@@ -1,76 +1,53 @@
1
1
  # Reacting to events
2
2
 
3
- This reference restates invariants of the Catalyst Cloud stream and the `watch` verb. Nothing here varies per tenant; the tenant facts a reaction needs (stage ids, label ids, the ask team) come from `catalyst-skills contract` at the moment you need them.
4
-
5
- ## The mechanism
6
-
7
- A steward never polls. It subscribes once to the tenant stream through the SDK's live client and reacts to each change as it arrives. The verb is `catalyst-skills watch`, and this skill's `scripts/watch-scope.mjs` is that verb with the scope checked up front:
3
+ A steward subscribes once to the account's event stream and reacts to each change as it arrives. The verb is `catalyst watch`; `scripts/watch-scope.mjs` is that verb with the scope checked up front:
8
4
 
9
5
  ```sh
10
- node scripts/watch-scope.mjs --project <id> # every ticket in the project
11
- node scripts/watch-scope.mjs --team <key> # every ticket on the team
6
+ node scripts/watch-scope.mjs --project <id>
7
+ node scripts/watch-scope.mjs --team <key>
12
8
  node scripts/watch-scope.mjs --ticket ENG-41 --ticket ENG-42
9
+ node scripts/watch-scope.mjs --project <id> --exec 'node my-reaction.mjs' # a harness with no monitor
13
10
  ```
14
11
 
15
- The stream itself is tenant-wide; scope is filtered on this machine from each frame's entity and row, and a row that only carries a ticket reference (a comment, a session, a pull request) is resolved to its project through the ticket's own record, cached for the life of the watch. The cost of an ignored frame is one JSON parse, so a wide scope is fine.
16
-
17
- **In Claude Code**, arm a monitor on the command above. Each line it prints is one applied change inside the scope, delivered into your session as an event. React to it in the same turn: read what changed, decide, act, and only then let the turn end.
18
-
19
- **In Codex, OpenCode, or any harness without a monitor**, pass `--exec`:
20
-
21
- ```sh
22
- node scripts/watch-scope.mjs --project <id> --exec 'node my-reaction.mjs'
23
- ```
24
-
25
- The command runs once per frame with the frame on stdin. A non-zero exit is a failed reaction (see the cursor rule). Nothing polls in either shape.
12
+ The stream is account-wide and scope is filtered on this machine, resolving comments, sessions and pull requests to their ticket's project; an ignored frame costs one JSON parse, so a wide scope is fine. In Claude Code, a monitor on the command delivers each printed line into your session. With `--exec`, the command runs once per frame with the frame on stdin, and a non-zero exit is a failed reaction.
26
13
 
27
14
  ## The frame
28
15
 
29
- One JSON object per line, exactly what the SDK delivers:
16
+ One JSON object per line, as the SDK delivers it:
30
17
 
31
18
  ```json
32
- {"type":"change","accountId":"<tenant>","seq":4182,"entity":"comments","entityId":"<id>","op":"upsert","row":{...}}
19
+ {"type":"change","accountId":"<account>","seq":4182,"entity":"comments","entityId":"<id>","op":"upsert","row":{...}}
33
20
  ```
34
21
 
35
- `seq` is the tenant-wide position. `entity` is one of the mirror's feed tables. `op` is `upsert` or `delete`. `row` is the mirrored row when the op is an upsert; a delete carries the id only. A frame for another tenant is refused by the CLI and never printed.
22
+ `seq` is the account-wide position, `entity` a feed table, `op` is `upsert` (with the row) or `delete` (the id only).
36
23
 
37
24
  ## Entities that matter to a scope
38
25
 
39
26
  | entity | what a change means | first reaction |
40
27
  | -- | -- | -- |
41
- | `issues` | a card moved, was retitled, re-prioritised, assigned, or created | if it moved into a stage the cloud owns, note the advance; if it moved out of the ladder by hand, ask why before touching it |
42
- | `comments` | someone or something wrote on a ticket | a human comment in your scope is answered in-thread by you, tagged; a cloud outcome card (phase complete, phase failed, remediate attempt, board health, merge wait) is your execution signal, read it |
43
- | `issue_labels`, `labels` | a label was added or removed | an ask label means a question, not work; a hold label means the cloud wants a human; the release label means a human cleared a false positive |
44
- | `relations` | a blocks relation appeared or went away | a new blocker on your ticket is a dependency to chase; a blocker closing may make a card dispatchable again |
45
- | `pull_requests`, `pr_events`, `pushes` | the branch and PR state changed | a PR going ready-for-review or merged is a milestone; a force-push after a resolved review thread is worth a look |
46
- | `check_runs`, `check_suites`, `commit_statuses` | CI moved | red on a required check after the queue label wakes an automatic remediation; you watch, you do not re-run it |
47
- | `reviews`, `pr_review_threads`, `pr_review_comments` | the reviewer spoke | unresolved threads block the merge; a clean pass is a reaction or a terse comment, not a review object |
48
- | `agent_sessions`, `agent_activities` | a phase started, wrote an artifact, opened a PR, reported | the plan on the session is the ladder itself; the current phase is the one in progress |
49
- | `fleet_activity`, `fleet_host_liveness` | a runner picked up or dropped a phase | a phase running is not a stall, whatever the clock says |
50
- | `fleet_anomalies` | the cloud raised a fleet-level alert | one alert covers every ticket it touches; never escalate it per ticket |
51
- | `workflow_states`, `team_workflow_mapping` | the tenant's stage map changed | refresh the contract (`catalyst-skills contract --refresh`) before the next state move |
52
- | `projects`, `cycles`, `initiatives` | your scope's container changed | update the status summary |
53
-
54
- Entities not listed still arrive when they are in scope; ignore what you do not need.
28
+ | `issues` | a card moved, was edited, re-prioritised, assigned or created | a move into a cloud-owned stage is an advance; a hand move out of the ladder, ask why before touching it |
29
+ | `comments` | someone or something wrote on a ticket | answer a human comment in-thread, tagged; read a cloud outcome card (phase complete or failed, remediate attempt, board health, merge wait) as your execution signal |
30
+ | `issue_labels`, `labels` | a label changed | an ask label means a question; a hold label means the cloud wants a human; the release label means a human cleared a false positive |
31
+ | `relations` | a blocker appeared or went away | chase a new blocker; a closed one may make a card dispatchable |
32
+ | `pull_requests`, `pr_events`, `pushes` | the branch or PR changed | ready-for-review and merged are milestones; a force-push after a resolved thread is worth a look |
33
+ | `check_runs`, `check_suites`, `commit_statuses` | CI moved | a red required check after the queue label wakes an automatic remediation; watch it |
34
+ | `reviews`, `pr_review_threads`, `pr_review_comments` | the reviewer spoke | unresolved threads block the merge; a clean pass is a reaction or a terse comment |
35
+ | `agent_sessions`, `agent_activities` | a phase started, wrote, opened a PR, reported | the session's plan is the ladder |
36
+ | `fleet_activity`, `fleet_host_liveness` | a runner picked up or dropped a phase | a running phase is not a stall |
37
+ | `fleet_anomalies` | a fleet-level alert | one alert covers every ticket it touches |
38
+ | `workflow_states`, `team_workflow_mapping` | the stage map changed | `catalyst contract --refresh` before the next move |
39
+ | `projects`, `cycles`, `initiatives` | the scope's container changed | update the summary |
55
40
 
56
41
  ## The same-turn rule
57
42
 
58
- A frame is reacted to in the turn it arrives, not batched for a later pass. The reaction is whatever the table above says plus anything the situation obviously needs, and it ends with the one status summary for the scope being current. If a reaction needs a human decision, file the ask through `what-needs-me` before proceeding on the default, in that same turn.
59
-
60
- ## The cursor rule
61
-
62
- The cursor file (`~/.config/catalyst-cloud/watch-cursor.json`, stamped with the tenant) advances only after the reaction returns. A reaction that throws, or an `--exec` command that exits non-zero, leaves the cursor at the last good frame; the CLI closes the socket and the SDK's reconnect replays from that cursor, so the failed frame is offered again. Delivery is therefore at-least-once: make reactions safe to repeat (check before you write, prefer idempotent writes such as a label add over a fresh comment).
63
-
64
- Two consequences. First, a crash mid-reaction replays, never loses. Second, a reaction that keeps failing keeps the watch pinned on one frame; fix the reaction rather than skipping the frame, or restart with `--from head` and re-read the scope with `scripts/scope-status.mjs` to catch up on what you missed.
65
-
66
- ## What to do on resync
43
+ React to a frame in the turn it arrives, and end the turn with the status summary current. A reaction that needs a human decision files the ask through `what-needs-me` in that same turn, before proceeding on the default.
67
44
 
68
- When the tenant tells the stream it can no longer replay from your cursor, the CLI prints one line on standard error, `[watch] resync: cursor moved to head <n>`, and continues from the head. No rows are copied. Anything that happened between your old cursor and the head is not replayed, so a resync is your cue to run `scripts/scope-status.mjs` once and reconcile the summary against the live state.
45
+ ## The cursor
69
46
 
70
- ## Starting a watch on an existing project
47
+ The cursor file (`~/.config/catalyst-cloud/watch-cursor.json`) advances only after a reaction returns. A reaction that throws, or an `--exec` that exits non-zero, leaves it at the last good frame, and the reconnect replays from there. Delivery is at-least-once, so make reactions safe to repeat: check before writing, and prefer idempotent writes such as a label add. A reaction that keeps failing pins the watch on one frame; fix the reaction, or restart with `--from head` and re-read the scope with `scripts/scope-status.mjs`.
71
48
 
72
- Start with `--from head` when you are picking up a project that has been running without a steward; the backlog of old frames is not worth replaying, and `scope-status.mjs` gives you the present state in one call. Start from the saved cursor (the default) when you are resuming your own watch after a break, so nothing that happened in between is lost.
49
+ A resync prints `[watch] resync: cursor moved to head <n>` on standard error and continues from the head without replaying the gap: run `scripts/scope-status.mjs` once and reconcile. Start with `--from head` when taking over a project that ran without a steward; resume from the saved cursor (the default) after your own break.
73
50
 
74
51
  ## The honest limit
75
52
 
76
- The stream carries the mirror's entity changes. It does not carry the relay ledger's phase failures, parks, remediate rounds or backoff timers as first-class frames. Between frames you learn those from the outcome comments the cloud posts on the ticket, which do arrive as `comments` frames: a phase-failed card names the phase, the attempt and the failure class; a remediate-attempt card names the round; a board-health comment names a stall the cloud itself noticed. For the current verdict on any ticket, ask the explainer: `catalyst-skills explain <ticket>` turns the exclusion reason and the last failure into one paragraph. `catalyst-skills explain --history <ticket>` prints the per-phase attempt ledger, the remediation rounds against the cap, and any park with what releases it.
53
+ The stream carries the mirror's entity changes, not the relay ledger's failures, parks, rounds or backoff timers as frames. Those arrive as the cloud's outcome comments, and `catalyst explain <ticket>` gives the current verdict; `--history` adds the attempts, rounds against the cap, and any park with what releases it.
@@ -1,63 +1,41 @@
1
1
  # Stalls and escalation
2
2
 
3
- The stall thresholds here are **local policy**, set once by the human who owns the tenant and read by `scripts/scope-status.mjs`. They are not cloud values and the cloud does not enforce them; the cloud's own enforcement numbers (retry backoff, the park threshold, the remediate round cap, the write budget) are on the contract and printed by `how-catalyst-works`. The chase order and the escalation rule below are invariants.
3
+ The stall thresholds are **local judgment**, set once by the project's owner and read by `scripts/scope-status.mjs`. The cloud publishes no stall policy and enforces none of these numbers; what it does about a failing ticket is in the contract's `thresholds`.
4
4
 
5
5
  ## The policy file
6
6
 
7
- `assets/stall-policy.json` ships the defaults: minutes a ticket may sit in each slot with no update and nothing running or leased on it before it counts as stalled. To change them, copy that file to `~/.config/catalyst-cloud/stall-policy.json` and edit it there; the script prefers the local copy and prints which file it used. Pass `--stall-policy <file>` to use another.
8
-
9
- Two slots deserve thought when tuning. The dispatch slot's threshold is how long a card may wait to be picked up before you ask why nothing took it; on a busy tenant with a full queue that is capacity, not a stall, and the answer is to wait or re-prioritise. The PR slot's threshold is how long a card may wait for merge evidence; reviews and CI take real time, so set it generously.
7
+ `assets/stall-policy.json` ships the defaults: minutes a ticket may sit in each slot, with no update and nothing running or leased, before it counts as stalled. To change them, copy it to `~/.config/catalyst-cloud/stall-policy.json` and edit the copy; the script prefers it and prints which file it used (`--stall-policy <file>` picks another). On a busy account a waiting dispatch card is capacity, not a stall, and reviews and CI take real time, so set the dispatch and PR thresholds generously.
10
8
 
11
9
  ## What counts as stuck
12
10
 
13
- A ticket is stuck when all of these hold at once: it is in an active slot (not done, not canceled), nothing is running or leased on it, its last update is older than the slot's threshold, and the eligibility explainer does not name a reason that is simply waiting out a clock. `scope-status.mjs` checks the first three and hands you the fourth as a command to run.
14
-
15
- A running phase is never a stall, however long it has run; the cloud's own timeout will fail it and the outcome card will say so. A ticket in retry backoff is waiting out a rung of two, five or fifteen minutes and is not a stall either.
11
+ All at once: an active slot, nothing running or leased, a last update older than the slot's threshold, and an explainer reason that is not a clock. `scope-status.mjs` checks the first three and hands you the fourth as a command. A running phase is never a stall; its own timeout fails it and the outcome card says so.
16
12
 
17
13
  ## The chase order
18
14
 
19
- Run `catalyst-skills explain <ticket>` first, and let its reason pick the row:
20
-
21
- | the explainer says | what it means | your move |
22
- | -- | -- | -- |
23
- | offered, with a position | the queue has it; a runner is the bottleneck | wait; if every ticket waits, it is capacity, see below |
24
- | lease held, intake lease held | a container has it | not a stall; wait for the outcome card |
25
- | retry backoff | a pre-branch or infrastructure failure is retrying in place | wait out the rung; three in a row parks it, and then it is a real stall |
26
- | blocked | a live blocks relation | chase the blocker: is it dispatchable, is it an ask nobody answered, is it done but still open |
27
- | ask ticket, ask shape suspected | the ticket is a question | route it to `what-needs-me`; if it is really work, a human applies the release label |
28
- | not at dispatch stage | somebody moved the card, or it never entered | read the card's history; re-dispatch with `make-ready.mjs` if it should run |
29
- | phase parked, cooling down, remediate parked | the cloud parked it after repeated failure or the round cap | read the last outcome card for the class; once its cause is fixed, the `unstick` skill releases it (`catalyst-skills release <ticket> --because <what changed>`); if the fix is a decision, file an ask |
30
- | no change hold | a remediate round changed nothing | a human comment on the ticket, or a new push to the branch, releases it; say what should change |
31
- | validate class spent, stale failure episode | the repair budget for this failure is used, or the ladder moved on | read the outcome cards; usually a decision about the approach, so an ask |
32
- | waiting on | a merge-gate failure with no automatic repair | read the merge-wait comment and the PR's three legs through `catalyst-github` |
33
- | branch missing, branch gone, no branch to remediate | the branch the phase needs does not exist | a hand-deleted branch is a human question; a never-created one means implement has not run, so check the earlier phases |
34
- | environment check required, running, failed, expired, hash mismatch | the repository's environment gate | a repository setting; the tenant admin resolves it in settings, one ask for the repository, not per ticket |
35
- | scope overlap | another in-flight ticket owns the files | wait for it, or re-order by priority |
36
- | routing unavailable, no eligible slot, runner image breaker, repo paused | a fleet or provider condition | one fleet note, never per ticket; see below |
37
- | pr merged, pipeline complete, ticket terminal | it is finished | close the loop in the summary; if the card is not Done a minute after the merge, that is a finding, not a chore |
38
-
39
- Where the explainer names a reason not in this table, it prints the raw reason; read it as spelled and consult `how-catalyst-works`.
40
-
41
- ## Capacity and fleet conditions are one note, not many asks
15
+ Run `catalyst explain <ticket>` and look the reason up in the `whats-happening` skill's `references/why-is-it-stuck.md`. For you as the owner:
42
16
 
43
- When several tickets in scope are offered and nothing picks them up, or the explainer names a routing, slot, provider or image condition, the cause is shared: coding-account headroom, a provider outage, a paused repository, a poisoned runner image. Write one line in the status summary naming the condition and the tickets it holds. Do not file an ask per ticket. `catalyst-skills accounts` reads coding-account status (state, usage windows, walls, quarantine); enrolling, pausing or removing an account is the settings page, not you.
17
+ - **It releases itself:** wait for the outcome card.
18
+ - **The person, with their own login, acts:** do it when the move is yours (re-dispatch, a comment that clears a no-change or validate-budget hold, a question routed to `what-needs-me`), and file an ask when it is theirs.
19
+ - **A park or hold a release clears:** once its cause is fixed, the `unstick` skill releases it (`catalyst release <ticket> --because <what changed>`). A round-threshold hold and a review that will not converge refuse that release; the table says what clears each.
20
+ - **An owner or admin, in settings, or an operator:** one ask per repository or setting.
21
+ - **Finished:** close the loop in the summary.
44
22
 
45
- ## Escalate inward, never outward
23
+ Quote a reason the table does not know as the explainer spelled it.
46
24
 
47
- The order is instrument, then you (the steward), then the desk (`whats-happening`), then the human, and the human only ever sees an ask. An instrument or a script that pages a human directly is a defect. So is a stall report that reaches the human as a bare label, a board row, or a chat aside with no ask behind it.
25
+ ## Shared causes are one note
48
26
 
49
- Before anything reaches the human, answer three questions:
27
+ When several tickets are offered and nothing takes them, or the explainer names a routing, slot, provider or image condition, the cause is shared (coding-account headroom, a provider outage, a paused repository, a bad runner image). Write one summary line naming the condition and the tickets it holds. `catalyst accounts` reads coding-account status; enrolling or pausing one is the settings page.
50
28
 
51
- 1. **Can I decide this myself?** Which approach, retry or abandon, rebase or re-cut, re-order two tickets: yours. Decide, record the decision in a bookkeeping note on the ticket, and move on.
52
- 2. **Does this need to block at all?** If a sane default exists, take it, record it, and file the ask anyway so the human can overrule; the work does not wait.
53
- 3. **Who else can move this?** Another steward, the desk, a repository owner. Pulling in a peer is preferred over pulling in the human.
29
+ ## Escalate inward
54
30
 
55
- Only a genuine product, priority or approval decision, or an action only a human can physically take (close a person's own pull request, read a review that will not converge, resolve a repository setting, apply the release label, answer a merge policy question), survives to become an ask.
31
+ The order is instrument, you, the desk (`whats-happening`), then the human, who only ever sees an ask. Before anything reaches the human:
56
32
 
57
- ## When a stall becomes an ask
33
+ 1. **Can I decide this myself?** Approach, retry or abandon, rebase or re-cut, ordering: yours. Decide, record it in a bookkeeping note, move on.
34
+ 2. **Does it need to block?** With a sane default, take it, record it, and file the ask anyway so the human can overrule.
35
+ 3. **Who else can move it?** A peer steward, the desk or a repository owner comes before the human.
58
36
 
59
- File it through `what-needs-me`, never by hand and never as the human. The ask carries the question as its title, the options, the default that fires if silent, and what it blocks, with the stalled ticket named in the blocks list so the human's inbox ranks it by what it holds. Search for an existing ask about the same decision first and attach the new ticket to it rather than filing a second one; two asks for one decision split its urgency and sink both. Once filed, proceed on the default and say so in the ticket.
37
+ What survives is a product, priority or approval decision, or an action only a human can take: close their own pull request, read a review that will not converge, change a repository setting, apply the release label, answer a merge-policy question.
60
38
 
61
- ## Reply where the message arrived
39
+ ## Filing the ask
62
40
 
63
- A human comment inside your scope is answered by you, in that thread, tagged, as the app actor. A question only a human can decide becomes an ask; you do not answer it, and you never post as the human. A bookkeeping record (a state move, a decision you took, a chain summary) carries the contract's bookkeeping marker as a prefix so it wakes nothing; the `--bookkeeping` flag on `catalyst-skills write comment` adds it.
41
+ File it through `what-needs-me`, as the app actor: the question as its title, the options, the default if silent, and the stalled ticket in its blocks list so the inbox ranks it by what it holds. Search for an existing ask on the same decision first and attach to it, because two asks split one decision's urgency. Then proceed on the default and say so on the ticket.
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- // lib/cli.mjs — the one way a skill script reaches Catalyst Cloud: by spawning the catalyst-skills
2
+ // lib/cli.mjs — the one way a skill script reaches Catalyst Cloud: by spawning the catalyst
3
3
  // CLI. The CLI holds the SDK and the key; this file holds neither. It reads
4
4
  // ~/.config/catalyst-cloud/customer.json (under CATALYST_SKILLS_HOME when set, else HOME) for the
5
- // CLI path that login recorded and falls back to `npx @catalyst-cloud/catalyst-skills`.
5
+ // CLI path that login recorded and falls back to `npx -p @catalyst-cloud/cli catalyst`.
6
6
  //
7
7
  // Exit codes every script built on this file shares: 2 = this machine is not connected, 1 = the
8
8
  // script's own check failed, 0 = fine.
@@ -12,7 +12,9 @@ import { join } from "node:path";
12
12
  import { fileURLToPath } from "node:url";
13
13
  import { CONNECT_COMMAND, hasCredential } from "./credential.mjs";
14
14
 
15
- export const PACKAGE_NAME = "@catalyst-cloud/catalyst-skills";
15
+ export const PACKAGE_NAME = "@catalyst-cloud/cli";
16
+ /** The package ships two commands, so npx needs the one to run named: `npx -p <package> catalyst`. */
17
+ export const NPX_ARGS = ["-p", PACKAGE_NAME, "catalyst"];
16
18
  export const NOT_CONFIGURED_EXIT = 2;
17
19
  export const CHECK_FAILED_EXIT = 1;
18
20
 
@@ -55,7 +57,7 @@ export function cliCommand(cfg = loadCustomerConfig()) {
55
57
  return { command: process.execPath, prefix: [cfg.cliPath], via: `node ${cfg.cliPath}` };
56
58
  }
57
59
  const npx = process.platform === "win32" ? "npx.cmd" : "npx";
58
- return { command: npx, prefix: [PACKAGE_NAME], via: `npx ${PACKAGE_NAME}` };
60
+ return { command: npx, prefix: NPX_ARGS, via: `npx -p ${PACKAGE_NAME} catalyst` };
59
61
  }
60
62
 
61
63
  /**
@@ -176,7 +178,7 @@ export function wantsHelp(argv) {
176
178
 
177
179
  const HELP = `lib/cli.mjs — shared helper; not a command.
178
180
 
179
- Resolves the catalyst-skills CLI (the path login recorded in ${configPath()}, else npx ${PACKAGE_NAME})
181
+ Resolves the catalyst CLI (the path login recorded in ${configPath()}, else npx -p ${PACKAGE_NAME} catalyst)
180
182
  and runs one verb for the script that imports it. Run any sibling script with --help instead.`;
181
183
 
182
184
  if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
@@ -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,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // watch-scope.mjs — subscribe to the tenant stream filtered to one scope and pass every in-scope
3
- // frame through, one JSON line each. This is `catalyst-skills watch` with the scope flags checked
3
+ // frame through, one JSON line each. This is `catalyst watch` with the scope flags checked
4
4
  // up front; the CLI owns the socket, the cursor file, the replay and the reconnects.
5
5
  import { CHECK_FAILED_EXIT, execCli, parseFlags, requireConfigured, wantsHelp } from "./lib/cli.mjs";
6
6
 
@@ -1,32 +1,31 @@
1
1
  ---
2
2
  name: unstick
3
3
  description: >-
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-skills 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
- disable-model-invocation: true
6
- allowed-tools: Bash(catalyst-skills:*) Bash(npx @catalyst-cloud/catalyst-skills:*)
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
+ allowed-tools: Bash(catalyst:*) Bash(npx -p @catalyst-cloud/cli catalyst:*)
7
6
  ---
8
- <!-- vendored-from: @catalyst-cloud/catalyst-skills@0.9.5 — written in this repository for customer tenants -->
7
+ <!-- vendored-from: @catalyst-cloud/catalyst-skills@0.13.1 — written in this repository for customer accounts -->
9
8
 
10
9
  # Unstick
11
10
 
12
- You get one stuck ticket, or one set of tickets stuck for the same reason, moving again. The cloud parks or holds a ticket when retrying would only repeat a failure: after repeated failures, when the repair-round cap is spent, when a repair changed nothing, when the same validate failure recurred. Each of those is a governor. Once its cause is fixed, the person's own key releases it; nothing here needs an operator.
11
+ You get one stuck ticket, or one set of tickets stuck for the same reason, moving again. The cloud parks or holds a ticket when retrying would only repeat a failure: after repeated failures, when the repair-round cap is spent, when a repair changed nothing, when the same validate failure recurred. Each of those is a governor. Once its cause is fixed, the person's own key releases most of them. Two refuse that release: a round-threshold hold (a push the fleet did not make, or an answer to its ask, grants one more cycle) and a review that will not converge (a human comment on the ticket resumes it).
13
12
 
14
13
  ## Run first
15
14
 
16
- Scripts are run, never read. Each prints `--help`; exit 2 means this machine is not connected (run `catalyst-skills login`).
15
+ Scripts are run, never read. Each prints `--help`; exit 2 means this machine is not connected (run `catalyst login`).
17
16
 
18
- - `node scripts/unstick.mjs <ticket>` — one JSON document: the eligibility explanation, the execution history (every governor holding the ticket with what releases it, and past releases), and a dry-run release showing what a release would clear and refuse. Changes nothing.
19
- - `node scripts/unstick.mjs <ticket> --because "<what changed>"` — the same, then the real release. Add `--retry-unchanged` only when you can say what changed outside what the cloud can see.
20
- - `node scripts/unstick.mjs --class <failure-class> --team <key> [--because "<what changed>"]` — the same for every ticket on one team parked under one failure class (at most 25 per call).
17
+ - `node scripts/unstick.mjs <ticket>`: one JSON document: the eligibility explanation, the execution history (every governor holding the ticket with what releases it, and past releases), and a dry-run release showing what a release would clear and refuse. Changes nothing.
18
+ - `node scripts/unstick.mjs <ticket> --because "<what changed>"`: the same, then the real release. Add `--retry-unchanged` only when you can say what changed outside what the cloud can see.
19
+ - `node scripts/unstick.mjs --class <failure-class> --team <key> [--because "<what changed>"]`: the same for every ticket on one team parked under one failure class (at most 25 per call).
21
20
 
22
- The verbs underneath are `catalyst-skills explain <ticket>`, `catalyst-skills explain <ticket> --history` and `catalyst-skills release <ticket> --because <text> [--retry-unchanged] [--dry-run]`.
21
+ The verbs underneath are `catalyst explain <ticket>`, `catalyst explain <ticket> --history` and `catalyst release <ticket> --because <text> [--retry-unchanged] [--dry-run]`.
23
22
 
24
23
  ## Load on demand
25
24
 
26
25
  | when | read |
27
26
  | -- | -- |
28
27
  | deciding whether to release, what a refusal means, when to ask a person | `references/playbook.md` |
29
- | what a reason in the explanation means | the `whats-happening` skill's why-is-it-stuck reference, or `how-catalyst-works` |
28
+ | what a reason in the explanation means, or what clears each kind of hold | the `whats-happening` skill: its why-is-it-stuck and when-a-phase-fails references |
30
29
  | a refusal needs a decision or a person's action | the `what-needs-me` skill |
31
30
  | a refusal names a person's pull request or its review | the `catalyst-github` skill |
32
31
 
@@ -38,4 +37,5 @@ The verbs underneath are `catalyst-skills explain <ticket>`, `catalyst-skills ex
38
37
  - **One release per cause.** If the history shows a release for the same failure and nothing has changed since, a second release buys the same failure. Raise an ask instead.
39
38
  - **A refusal names its fix.** Do the fix when it is yours to do; everything else is one ask through `what-needs-me`, attached to an existing ask for the same decision. Never close or merge a person's pull request, and never answer an ask as the person.
40
39
  - **A shared cause is one note.** Several tickets parked by one outage or one bad image are one class release and one line in your reply, never one ask per ticket.
41
- - **Their tenant, as them.** Every read and write goes through the CLI and the person's own login. You never name another tenant.
40
+ - **What a release costs.** A release is a write: it is recorded against the person's name with your `--because`, shown to everyone who reads the ticket's history, and it spends a round of work the cloud will run again. The dry run is free; run it first.
41
+ - **Their account, as them.** Every read and write goes through the CLI and the person's own login. You never name another account.
@@ -3,4 +3,4 @@ interface:
3
3
  short_description: "Find out why a Catalyst ticket is parked or held and release it once its cause is fixed; asks only for what needs a person"
4
4
  default_prompt: "Use $unstick to find out why <ticket> is stuck and get it moving again."
5
5
  policy:
6
- allow_implicit_invocation: false
6
+ allow_implicit_invocation: true
@@ -1,5 +1,5 @@
1
1
  identity: { pack: catalyst-cloud-skills, skill: unstick }
2
2
  effects: [external-write]
3
3
  mutating: true
4
- invocation: explicit
4
+ invocation: implicit
5
5
  exposure: [catalog]