@rallycry/conveyor-skills 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rallycry/conveyor-skills",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Shared Claude Code skills for Conveyor consumer repos, linked into .claude/skills via the conveyor-skills CLI",
5
5
  "keywords": [
6
6
  "claude",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: conveyor-local-loop
3
- description: Run this machine as a serial local claudespace — pick the session owner's highest-priority Open Conveyor card, claim it, execute its plan to the PR finish line, repeat. Handles single cards AND whole packs (an Open pack parent is driven end-to-end per conveyor-local-pack, then the loop moves on once the pack's final PR is open). One invocation = one iteration; run continuously with "/loop /conveyor-local-loop" (no interval) and it self-paces (~1-2 min between cards while the queue has work, ~25 min idle polls when empty). Use when the user says "/conveyor-local-loop", "start the local loop", "work my open cards locally", or wants planned cards executed with full local CPU/RAM instead of spawning claudespaces. For exactly one card use conveyor-local-task; for one pack and nothing else, conveyor-local-pack.
3
+ description: Run this machine as a serial local claudespace — pick the session owner's highest-priority Open Conveyor card, claim it, execute its plan to the PR finish line, repeat. Handles single cards AND whole packs (an Open pack parent is driven end-to-end per conveyor-local-pack, then the loop moves on once the pack's final PR is open). One invocation = one iteration; run continuously with "/loop /conveyor-local-loop" (no interval) and it self-paces (~1-2 min between cards while the queue has work; when the queue is empty it blocks on live board events via conveyor-wait and wakes seconds after a card becomes claimable, with a ~25 min fallback poll). Use when the user says "/conveyor-local-loop", "start the local loop", "work my open cards locally", or wants planned cards executed with full local CPU/RAM instead of spawning claudespaces. For exactly one card use conveyor-local-task; for one pack and nothing else, conveyor-local-pack.
4
4
  ---
5
5
 
6
6
  # Conveyor Local Loop
@@ -68,7 +68,7 @@ Each invocation does the FIRST of these that produces work, then paces:
68
68
  branch); request-changes or unanswered review comments → address now;
69
69
  green and quiet → leave alone.
70
70
  3. **Claim** the next card (below).
71
- 4. **Idle** — nothing claimable: pace long.
71
+ 4. **Idle** — nothing claimable: arm the board-event wake (below), then pace long.
72
72
 
73
73
  ## Claiming
74
74
 
@@ -163,6 +163,62 @@ section only defines how it embeds in the loop:
163
163
  other cards. The user's chat reply un-parks it, and the next Recover tier
164
164
  retakes the slot.
165
165
 
166
+ ## Waking on board events
167
+
168
+ An empty queue is not a quiet board. Rather than sleeping blind for 25 minutes,
169
+ arm `conveyor-wait`: a CLI in `@rallycry/conveyor-mcp` that subscribes to the
170
+ project's live card stream and exits the moment a card ENTERS a claimable
171
+ state. A card created Open, a Cancelled card reopened, and a card reassigned to
172
+ you all count; an edit to a card that already matched does not.
173
+
174
+ Arm it on an idle iteration only (tier 4), and only when no wait from an earlier
175
+ iteration is still running:
176
+
177
+ ```bash
178
+ node_modules/.bin/conveyor-wait --scope mine,unclaimed --timeout 1740
179
+ ```
180
+
181
+ Launch it with Bash `run_in_background: true` and end the turn. Its completion
182
+ notification is the wake. The `ScheduleWakeup` you still arm is the fallback for
183
+ the case where the wait dies silently — use the pacing table's background-gate
184
+ row (1200–1800s), not a second, shorter timer.
185
+
186
+ - Prefer `node_modules/.bin/conveyor-wait`. If it is absent, use
187
+ `npx -y -p @rallycry/conveyor-mcp@latest conveyor-wait`. The `-p` form
188
+ matters: inside the conveyor monorepo a bare
189
+ `npx @rallycry/conveyor-mcp` misresolves.
190
+ - Narrow `--types` to whatever focus the user gave the loop invocation —
191
+ "focus on incidents" → `--types incident`. The default watches tasks,
192
+ incidents, and suggestions.
193
+ - `--scope mine,unclaimed` mirrors the claiming filter: cards assigned to the
194
+ session owner plus unassigned cards. Use `--scope all` only when the user
195
+ asked the loop to watch the whole board.
196
+ - `--statuses` defaults to `Open`, which is the claimable lane. Leave it alone
197
+ unless the user asked for something else.
198
+ - Credentials come from the environment, then any `.mcp.json` from the working
199
+ directory up, then `~/.claude.json`. An agent Bash shell does not inherit the
200
+ MCP server's environment, so that file fallback is what makes this work at
201
+ all. Exit 1 means the wait could not run: no credentials, a rejected token, or
202
+ a project it cannot read. Read the stderr line, report it once, fall back to
203
+ plain timed polling, and do not re-arm it every iteration.
204
+
205
+ **The result is advisory — the queue is still the source of truth.** The CLI
206
+ prints one line of JSON and exits 0 in every non-error case:
207
+
208
+ ```
209
+ {"reason":"event","card":{"id":…,"slug":…,"title":…,"type":…,"status":…,"assignedUserId":…}}
210
+ {"reason":"timeout"}
211
+ {"reason":"interrupted"}
212
+ ```
213
+
214
+ On wake, run a normal iteration and re-enumerate with
215
+ `mcp__conveyor__list_tasks`. By then the card may be claimed, cancelled, or
216
+ blocked by a dependency — never claim straight from the wait payload.
217
+
218
+ **Never arm a second wait.** On a wake where a wait process is still in flight
219
+ and the queue is still empty, re-arm the fallback `ScheduleWakeup` and end the
220
+ turn.
221
+
166
222
  ## Pacing (dynamic /loop only)
167
223
 
168
224
  Under `/loop` with no interval, end EVERY iteration with exactly one
@@ -170,9 +226,9 @@ Under `/loop` with no interval, end EVERY iteration with exactly one
170
226
 
171
227
  | State | Delay | Reason should say |
172
228
  |-------|-------|-------------------|
173
- | A background gate/agent is in flight — its completion notification is the real wake | 1200–1800s fallback | "fallback while <gate> runs — its notification wakes me sooner" |
229
+ | A background gate/agent/conveyor-wait is in flight — its completion notification is the real wake | 1200–1800s fallback | "fallback while <gate> runs — its notification wakes me sooner" |
174
230
  | ANY actionable work exists: claimable cards or packs, a pack child to implement/merge, a PR still to open, red/pending CI, review comments | 60–90s | queue depth / which item is next |
175
- | Queue enumerated as empty THIS iteration, all loop PRs green and quiet | 1200–1800s | queue empty, idle poll |
231
+ | Queue enumerated as empty THIS iteration, all loop PRs green and quiet | 1200–1800s | queue empty; conveyor-wait armed, so this is only the fallback |
176
232
  | Loop-fatal: MCP dead after 2 tries, dirty tree, broken repo | notify the user (PushNotification if available), then 1800s — or `stop: true` if continuing is unsafe | what is wrong |
177
233
 
178
234
  The long idle tier is EARNED, never defaulted: it requires having enumerated
@@ -68,8 +68,15 @@ run /conveyor-local-loop over the children instead.
68
68
  2. Confirm it is a parked feature-branch pack: has (or will have) children,
69
69
  status not InProgress/ReviewPR, no active agent session.
70
70
  3. Ensure the pack branch exists on origin: use the card's branch if set;
71
- else cut `ft/<parent-slug>` from `origin/dev`, push `-u`, and name it in
72
- the claim post so the record is on the card.
71
+ else cut `ft/<parent-slug>` from `origin/dev`, push `-u`, and IMMEDIATELY
72
+ record it on the card `mcp__conveyor__update_task` with
73
+ `githubBranch: <branch>` (the branch must already be pushed; the API
74
+ verifies the ref exists). This write is load-bearing, not bookkeeping:
75
+ identification mints a competing `conveyor/*` branch onto any branchless
76
+ card it processes, and every pack-child merge handler keys on the card's
77
+ recorded branch matching the PRs' real base — a drifted record strands
78
+ externally-merged children in ReviewPR. Name the branch in the claim post
79
+ too.
73
80
  4. No children yet? Break the work down first, exactly as a fresh cloud
74
81
  parent would: explore the codebase, save the parent-level plan on the card
75
82
  (`mcp__conveyor__update_task`), then `mcp__conveyor__create_subtask` each
@@ -138,7 +145,13 @@ that applies:
138
145
  can NEVER auto-merge a zero-check pack-branch PR — if the merge queues
139
146
  without landing, merge locally instead (`git checkout <pack> && git pull
140
147
  && git merge --no-ff <child-branch> && git push`; GitHub then marks the PR
141
- merged). Either way confirm the child advanced to ReviewDev.
148
+ merged). Either way CONFIRM the child advanced to ReviewDev
149
+ (`mcp__conveyor__get_task`; allow ~1 min for the merge webhook). Still
150
+ ReviewPR after a local-merge fallback is an escalation, not a shrug — it
151
+ means the parent card's `githubBranch` has drifted from the real pack
152
+ branch: fix the parent record (`mcp__conveyor__update_task` with
153
+ `githubBranch: <pack>`), advance the child by hand (`update_task` →
154
+ ReviewDev), and post the drift to parent chat.
142
155
  3. **Sync dev into the pack branch** — the local stand-in for the server-side
143
156
  base sync: `git checkout <pack> && git pull && git fetch origin dev && git
144
157
  merge origin/dev --no-edit && git push`. Merge, never rebase: the pack
@@ -29,8 +29,9 @@ patterns/design choices, **5 SP** only for hard work. Split anything larger.
29
29
  ## Packs (parent + child tasks)
30
30
 
31
31
  A **pack** is Conveyor's bundle shape: a parent card with child cards.
32
- `create_subtask(parentTaskId, ...)` is the **only** way to parent a card —
33
- `create_task`/`update_task` have no parent field. Each child is a full card
32
+ `create_subtask(parentTaskId, ...)` creates a NEW child; to move an EXISTING
33
+ card under a parent (or out of one) use `set_task_parent`. `create_task` /
34
+ `update_task` have no parent field. Each child is a full card
34
35
  (own chat, plan, story points). Split into a pack only when the work is
35
36
  genuinely multiple independently buildable pieces (8-SP-tier); otherwise keep
36
37
  one card.
@@ -56,7 +56,9 @@ and let Conveyor's own automation do the linking.
56
56
  `conveyor-plan` skill.
57
57
  - **One card per deliverable/PR** (mirror packs below are the documented
58
58
  exception). Multi-PR work becomes a pack: children via
59
- `mcp__conveyor__create_subtask` (the ONLY way to parent a card) with
59
+ `mcp__conveyor__create_subtask` (new children) or
60
+ `mcp__conveyor__set_task_parent` (adopt an existing card into the pack, or
61
+ detach one with `parentTaskId: null`), with
60
62
  `mcp__conveyor__add_dependency` edges. Orchestration packs run children as
61
63
  their own builds/PRs; mirror packs (children created with
62
64
  `followParentStatus: true` on `create_subtask`) document already-done work
@@ -106,7 +108,9 @@ labels. Each tag carries a `description` (≤255 — the summary), an `overview`
106
108
  environment for an Open card (that agent run is the card's "build" —
107
109
  `mcp__conveyor__get_build_status` reports it). To execute cards on the
108
110
  local machine instead, use the `conveyor-local-loop` skill. Don't do both —
109
- a started task's agent will duplicate local work.
111
+ a started task's agent will duplicate local work. That loop idles on
112
+ `conveyor-wait`, a CLI in `@rallycry/conveyor-mcp` that blocks until a card
113
+ becomes claimable, so an idle loop wakes on a board event instead of a timer.
110
114
  - **Reserved-branch trap**: a card with an assigned agent may have a reserved
111
115
  `githubBranch`. Check `get_task` before pushing: if set, push to THAT
112
116
  branch; a PR from any other branch gets auto-closed and unlinked.