@joshuafolkken/kit 1.1035.0 → 1.1050.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 (118) hide show
  1. package/.claude/skills/verify-ui/SKILL.md +1 -1
  2. package/.claude/skills/workflow-commands/SKILL.md +2 -2
  3. package/.claude/skills/workflow-commands/background-commands.md +1 -1
  4. package/.claude/skills/workflow-commands/backlogrun-child.md +2 -2
  5. package/.claude/skills/workflow-commands/backlogrun-lanes.md +1 -1
  6. package/.claude/skills/workflow-commands/backlogrun-park.md +6 -0
  7. package/.claude/skills/workflow-commands/backlogrun-progress.md +30 -36
  8. package/.claude/skills/workflow-commands/backlogrun-steps.md +16 -16
  9. package/.claude/skills/workflow-commands/chain-rule.md +2 -2
  10. package/.claude/skills/workflow-commands/followup-reference.md +2 -2
  11. package/.claude/skills/workflow-commands/issue-comments.md +1 -1
  12. package/.claude/skills/workflow-commands/observation-filing.md +41 -86
  13. package/.claude/skills/workflow-commands/pre-gate-cut.md +33 -36
  14. package/.claude/skills/workflow-commands/working-tree-hold.md +2 -2
  15. package/.github/workflows/auto-tag.yml +21 -0
  16. package/.github/workflows/publish.yml +9 -10
  17. package/dist/hooks/batch-guard.js +4 -4
  18. package/dist/hooks/{chunk-HU66PWWL.js → chunk-5BK3K7V4.js} +89 -41
  19. package/dist/hooks/{chunk-GLBDBJOK.js → chunk-7VPDUBRN.js} +49 -151
  20. package/dist/hooks/{chunk-GJT4BNVE.js → chunk-DMQN45FN.js} +3 -3
  21. package/dist/hooks/{chunk-D67KVGGY.js → chunk-EJDX2TOB.js} +13 -3
  22. package/dist/hooks/{chunk-KG6PZD72.js → chunk-GQ7KP45M.js} +2 -2
  23. package/dist/hooks/{chunk-Y27M6A7X.js → chunk-HJIISEAC.js} +4 -4
  24. package/dist/hooks/{chunk-XPLP27WA.js → chunk-NAS4C7GP.js} +4 -26
  25. package/dist/hooks/{chunk-ZXNE6NY3.js → chunk-NJQOBE6L.js} +2 -2
  26. package/dist/hooks/{chunk-EIFCAJRB.js → chunk-RLDX5SOC.js} +1184 -946
  27. package/dist/hooks/{chunk-HOYJU5RM.js → chunk-WQ4OSBSS.js} +10 -3
  28. package/dist/hooks/codex-hook-adapter.js +10 -10
  29. package/dist/hooks/duplicate-read-guard.js +5 -5
  30. package/dist/hooks/format-edited.js +15 -34
  31. package/dist/hooks/investigation-guard.js +5 -5
  32. package/dist/hooks/pretool-guard.js +23 -16
  33. package/dist/hooks/stop-guard.js +13 -188
  34. package/dist/josh.js +4 -106
  35. package/dist/version/index.js +381 -9
  36. package/package.json +6 -6
  37. package/prompts/collaboration-workflow/file-edits.md +6 -53
  38. package/prompts/collaboration-workflow/residency.md +1 -1
  39. package/prompts/collaboration-workflow/rule-delivery.md +4 -35
  40. package/prompts/collaboration-workflow/shell-body.md +7 -9
  41. package/prompts/collaboration-workflow/turn-batching.md +21 -37
  42. package/prompts/collaboration-workflow/wip-cap.md +15 -18
  43. package/prompts/sonar-hotspot-handling.md +1 -1
  44. package/scripts/adopt/adopt-toolkits.ts +2 -0
  45. package/scripts/auto-ok/auto-ok-cli.ts +9 -9
  46. package/scripts/backlog/backlog-next.ts +24 -8
  47. package/scripts/backlog/backlog-plan-cli.ts +5 -1
  48. package/scripts/backlog/backlog-pool.ts +31 -11
  49. package/scripts/backlog/backlog-rank.ts +106 -0
  50. package/scripts/backlog/backlog-waves.ts +42 -29
  51. package/scripts/build/build-hooks.ts +7 -2
  52. package/scripts/delegation/delegation-policy.ts +11 -0
  53. package/scripts/document/document-byte-budget.ts +5 -5
  54. package/scripts/document/entry-read-budget.ts +5 -4
  55. package/scripts/epic/epic-lane-offer.ts +11 -22
  56. package/scripts/epic/epic-rank.ts +37 -0
  57. package/scripts/epic/epic-solo.ts +29 -28
  58. package/scripts/git/git-command.ts +1 -1
  59. package/scripts/git/git-execa-error.ts +6 -1
  60. package/scripts/git/git-next-issues.ts +34 -5
  61. package/scripts/git/git-preflight.ts +22 -4
  62. package/scripts/git/git-push-transport.ts +12 -69
  63. package/scripts/git/git-spawn.ts +79 -3
  64. package/scripts/git/git-ssh-keepalive.ts +74 -0
  65. package/scripts/git/gone-branch.ts +3 -2
  66. package/scripts/git/issue-labels.ts +12 -0
  67. package/scripts/git/issue-rank.ts +89 -0
  68. package/scripts/hooks/format-edited-cli.ts +15 -0
  69. package/scripts/hooks/format-edited-file.ts +2 -9
  70. package/scripts/hooks/pretool-guard-cli.ts +21 -0
  71. package/scripts/hooks/pretool-guard.ts +14 -15
  72. package/scripts/init/start-exec.ts +7 -1
  73. package/scripts/init/start-plan.ts +18 -5
  74. package/scripts/init/start-setup-pr.ts +46 -19
  75. package/scripts/init/start-steps.ts +41 -9
  76. package/scripts/init/start.ts +40 -10
  77. package/scripts/issue/issue-cite.ts +19 -1
  78. package/scripts/josh/josh-command-map.ts +0 -102
  79. package/scripts/josh/josh-commands-development.ts +2 -2
  80. package/scripts/josh/josh-commands-project.ts +1 -1
  81. package/scripts/lane/lane-child-marker.ts +16 -2
  82. package/scripts/lane/lane-cli.ts +32 -14
  83. package/scripts/lane/lane-report.ts +10 -4
  84. package/scripts/propagate/propagate-plan.ts +185 -0
  85. package/scripts/propagate/propagate-run.ts +5 -1
  86. package/scripts/propagate/propagate-steps.ts +16 -1
  87. package/scripts/propagate/propagate-targets.ts +13 -2
  88. package/scripts/propagate/propagate.ts +60 -42
  89. package/scripts/registry-migration/migrate-logic.ts +1 -0
  90. package/scripts/release/github-release.ts +1 -1
  91. package/scripts/review/review-attest.ts +44 -0
  92. package/scripts/review/review-brief-cli.ts +49 -2
  93. package/scripts/review/review-brief.ts +46 -1
  94. package/scripts/review/review-stamps.ts +7 -0
  95. package/scripts/rules/implementation-cut.ts +1 -1
  96. package/scripts/rules/issue-fold.ts +1 -2
  97. package/scripts/rules/lane-carry-conflict.ts +1 -2
  98. package/scripts/rules/lane-park.ts +1 -2
  99. package/scripts/rules/pre-gate-cut.ts +2 -2
  100. package/scripts/run/run-headless.ts +22 -6
  101. package/scripts/run/run-parent-cut-hook.ts +144 -0
  102. package/scripts/run/run-progress-read.ts +2 -1
  103. package/scripts/run/run-progress.ts +21 -8
  104. package/scripts/run/run-ship-cli.ts +6 -74
  105. package/scripts/run/run-ship-preflight.ts +87 -0
  106. package/scripts/run/run-ship-review-steps.ts +5 -26
  107. package/scripts/run/run-ship-review.ts +9 -0
  108. package/scripts/run/run-ship-scoped.ts +44 -0
  109. package/scripts/run/run-ship-stage.ts +5 -1
  110. package/scripts/run/run-ship-steps.ts +105 -0
  111. package/scripts/run/run-ship.ts +2 -0
  112. package/scripts/run/run-wake-cli.ts +2 -2
  113. package/scripts/run/run-wake-describe.ts +19 -1
  114. package/scripts/run/run-watcher-hook.ts +1 -1
  115. package/scripts/time-runtime/time-bundle-call.ts +2 -2
  116. package/scripts/version/npm-registry.ts +97 -0
  117. package/scripts/version/version-commands.ts +5 -4
  118. package/scripts/version/version-remote.ts +26 -12
@@ -15,7 +15,7 @@ green while spacing, layout and styling are visibly broken. This skill is the lo
15
15
  In order:
16
16
 
17
17
  1. The routes given as arguments (`/verify-ui / /blog`).
18
- 2. Otherwise, derive the candidates with `pnpm josh ui:routes` (alias `josh uir`): it reads the
18
+ 2. Otherwise, derive the candidates with `pnpm josh ui:routes`: it reads the
19
19
  change (the branch diff, or the staged diff with `--staged`) and lists the routes it touches,
20
20
  tracing a changed shared component to the routes that render it. From that list **pick the ones a
21
21
  reader would notice** — that narrowing is the judgement the command leaves to you.
@@ -92,8 +92,8 @@ procedure alone, and the rest of `backlogrun-park.md` is read only when it is re
92
92
  **A pointer written `` `X.md` → "Heading" `` is read as that section, never by opening `X.md` whole:**
93
93
 
94
94
  ```bash
95
- pnpm josh doc:section <file.md> "<heading>" # the section, verbatim ; alias: josh ds
96
- pnpm josh read:set [<keyword>] # what an entry reads, and what it costs ; alias: josh rs
95
+ pnpm josh doc:section <file.md> "<heading>" # the section, verbatim
96
+ pnpm josh read:set [<keyword>] # what an entry reads, and what it costs
97
97
  ```
98
98
 
99
99
  The section is fetched in the same turn, printed verbatim with its subsections; **a heading that does
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Background the gate and push
4
4
 
5
- - **The clean path folds the region into one backgrounded `pnpm josh ship`** (gate → `git -y` →
5
+ - **The clean path folds the region into one backgrounded `pnpm josh ship`** (preflight → gate → `git -y` →
6
6
  foreground `followup` → `run:tail`; joshuafolkken/kit#2398). The calls below serve a due second round.
7
7
  - Background `pnpm josh gate` beside the review; join it before commit.
8
8
  - Issue `pnpm josh git -y` in the background; its completion resumes the run, so the turn never ends
@@ -164,7 +164,7 @@ unit was given** — this session's own unless the unit was handed a separate wo
164
164
  the recovery below is taken there too.
165
165
 
166
166
  ```bash
167
- pnpm josh run:liveness <N> --output <path> --process none # alias: josh rv
167
+ pnpm josh run:liveness <N> --output <path> --process none
168
168
  pnpm josh run:liveness <N> --output <path> --process alive
169
169
  pnpm josh run:liveness <N> --output <path> --process none --window 45 --repo <owner/repo>
170
170
  ```
@@ -290,7 +290,7 @@ separate command to ask first. Rationale: `docs/maintainers/backlogrun-child-rat
290
290
  preflight is part of the claim".
291
291
 
292
292
  ```bash
293
- answer=$(pnpm josh run:hold 926) # alias: josh rh ; one token on stdout, prose on stderr
293
+ answer=$(pnpm josh run:hold 926) # one token on stdout, prose on stderr
294
294
  ```
295
295
 
296
296
  | Answer | What it found | What to do |
@@ -137,7 +137,7 @@ runs `lane:open`, then — only when `--stash` is given, which is the first lane
137
137
  into the lane and re-installs against the lock it brought in, then `lane:dispatch`:
138
138
 
139
139
  ```bash
140
- pid=$(pnpm josh lane:launch "$n") || exit 1 # the child's pid on stdout, nothing else; alias: josh lnla
140
+ pid=$(pnpm josh lane:launch "$n") || exit 1 # the child's pid on stdout, nothing else
141
141
  pid=$(pnpm josh lane:launch "$n" --stash "backlogrun: josh latest before lanes") || exit 1 # the first lane only, and only if `josh latest` stashed
142
142
  ```
143
143
 
@@ -33,6 +33,12 @@ authorization, whether it came from a named epic or from the opted-in pool:
33
33
  is Tier A" carries the re-dispatch itself. A released child takes a lane exactly as any batch child
34
34
  does.
35
35
 
36
+ ## The parent does not investigate a lane failure itself
37
+
38
+ **A lane failure whose reason is not on its Issue is read by a unit** — `pnpm josh delegate
39
+ lane-failure-investigation` (joshuafolkken/kit#2947); the parent checks the cited lines and
40
+ `pnpm josh issue:state` before it parks, re-dispatches or files.
41
+
36
42
  ## `needs-human-review` — the one stop that is not a park
37
43
 
38
44
  A child carrying **`needs-human-review`** is degraded to a `halfrun`-shaped stop and **the whole run ends
@@ -50,11 +50,11 @@ for a whole interval (that exit says so on standard error). **Nothing in flight
50
50
  parked, a stop — run `pnpm josh run:progress --mark` in the same turn to restart the silence clock. The clock is silence, never a timer
51
51
  (`docs/josh-commands.md` → "`josh run:progress`").
52
52
 
53
- **Do not keep a progress clock of your own** — the hook refuses the arm rather than asking.
54
- `scripts/rules/early-heartbeat.ts` → `decide` refuses a sleep-only `Bash` call on three tests — a timer it already allowed is still live, the
55
- report it would produce would land before the interval is up, or the wait runs longer than the interval
56
- — so **a single correctly-spaced arm is allowed**. It is still not the way to report; the step above
57
- prints without arming anything, and `--wait` is not a wait timer.
53
+ **Do not keep a progress clock of your own** — the hook refuses the arm rather than asking
54
+ (`scripts/rules/early-heartbeat.ts` → `decide`), though **a single correctly-spaced arm is allowed**. It
55
+ is still not the way to report; the step above prints without arming anything, and `--wait` is not a
56
+ wait timer. Rationale: `docs/maintainers/backlogrun-progress-rationale.md` → "Why the heartbeat reads
57
+ as it does".
58
58
 
59
59
  **The default interval is twenty minutes, overridable — by the person, not the run.**
60
60
  `JOSH_PROGRESS_INTERVAL_MINUTES` moves both sides (the guard reads it through the watcher's reader);
@@ -65,14 +65,11 @@ moves the watcher alone** — it makes the watcher quieter than the floor, never
65
65
  **Every unscheduled progress statement is answered by `pnpm josh run:progress --once`** — presented in
66
66
  the same five field lines, the reply to an explicit ask and the note just after a run starts alike.
67
67
  **Never write a clock time the command did not print** (not an approximation, not a placeholder — where
68
- a field is missing, say so). **`--once` records the report**, so no `--mark` beside it. **A live timer
69
- is counted from the record the guard writes when it allows one**, never from the machine's `sleep`
70
- processes.
68
+ a field is missing, say so). **`--once` records the report**, so no `--mark` beside it.
71
69
 
72
70
  **Every report opens with the time the observation was taken** — not only how long it has been quiet: an
73
- absolute instant, `at YYYY-MM-DD HH:MM±HH:MM / YYYY-MM-DDTHH:MMZ`. **The date is part of it**, and **the local clock
74
- leads with UTC beside it and the offset that ties them**. **It is added, never substituted for the
75
- elapsed figure**, and **the presented line needs no stamp computed for it** — the command prints the
71
+ absolute instant, `at YYYY-MM-DD HH:MM±HH:MM / YYYY-MM-DDTHH:MMZ`. **It is added, never substituted for
72
+ the elapsed figure**, and **the presented line needs no stamp computed for it** — the command prints the
76
73
  `at` stamp and the `next` field.
77
74
 
78
75
  **The line carries observations, never "still running", and nothing in it is a verification result** —
@@ -87,8 +84,8 @@ promoted to interrupt, never demoted to requested.**
87
84
 
88
85
  **The report surface belongs to the run, not to the session** (joshuafolkken/kit#2207). The run's
89
86
  session-facing events — a plan posted, a child launched, a PR opened, a review round, a park, a cut, a
90
- stop, a merge — are appended to one ordered stream keyed to the run's identity (`pnpm josh run:event`),
91
- which survives the cut because it is the run's and not any one session's. **Every session is a writer;
87
+ stop, a merge — are appended to one ordered stream keyed to the run's identity (`pnpm josh run:event`).
88
+ **Every session is a writer;
92
89
  the reader is a script in a pane of the person's own, never a conversation** (#2492):
93
90
  `pnpm josh run:event --watch` prints each event the moment it lands, in the session language, and the
94
91
  `heartbeat` events say the run is alive when quiet. **No session relays the stream** — name the watch command once, at the first cut or when
@@ -106,8 +103,7 @@ remaining child blocked behind a parked one, the backlog drained of anything run
106
103
  streak tripped — is pushed to the interrupt tier: `pnpm josh run:carry --end --stopped "<reason>"` sends one ⏸️ confirmation
107
104
  as it ends the record, and because the record is gone by the second `--end` the same stop never notifies
108
105
  twice. A parked child is pushed by the child itself, which records the park and sends its own
109
- `confirmation` before it stops (`backlogrun-park.md`). **Nothing new carries either one** — both ride the
110
- existing notification types and the record the watcher already keeps. Rationale for the tiers:
106
+ `confirmation` before it stops (`backlogrun-park.md`). Rationale for the tiers:
111
107
  `docs/maintainers/backlogrun-progress-rationale.md` → "Why the signal tiers are split this way".
112
108
 
113
109
  **A heartbeat is emitted from the moment a run has started, even before any child carries
@@ -146,9 +142,8 @@ long.
146
142
  watcher's scope and placement: `docs/maintainers/backlogrun-progress-rationale.md` → "Why the watcher
147
143
  runs where it does".
148
144
 
149
- **A run that merges needs no teardown; a run that stops has to end the reporting itself.** The issue
150
- leaves the `in-progress` listing at the merge, so whatever is waiting prints nothing and `--hours` ends
151
- it. **A stop keeps that label on purpose** — so **no further `--wait` is started** after the stop
145
+ **A run that merges needs no teardown; a run that stops has to end the reporting itself.** **A stop
146
+ keeps the `in-progress` label on purpose** — so **no further `--wait` is started** after the stop
152
147
  notification, and any long-running watcher still in the background is stopped in the same turn. That
153
148
  covers `halfrun`'s stop before commit, a `needs-human-review` stop, a split or prerequisite stop, and
154
149
  a `backlogrun` named issue's failure stop.
@@ -167,9 +162,9 @@ answers=$(pnpm josh epic:next 858 909 --repo joshuafolkken/kit --lanes)
167
162
  # every named epic, merged into the same pool — "Several epics in one run" above
168
163
  ```
169
164
 
170
- **`--lanes` is the form to use.** A lane's branch is `<N>-lane`, which `pnpm josh git` commits from, so
171
- a child handed a lane runs the whole `fullrun` procedure inside it. Read a line per child, and treat a
172
- single non-numeric line as the verdict.
165
+ **`--lanes` is the form to use.** Read a line per child, and treat a single non-numeric line as the
166
+ verdict. Rationale: `docs/maintainers/backlogrun-progress-rationale.md` → "Why a named epic's children
167
+ run in lanes".
173
168
 
174
169
  1. Run the command above.
175
170
  2. **One or more numbers** — where the child runs in this session's own checkout, its `fullrun` claim
@@ -317,8 +312,8 @@ the next turn of this session costs more than the threshold in billed input.
317
312
 
318
313
  **135,000 is shared by the scheduler entry, scheduler hand-off and lane worker implementation cut.**
319
314
  The value is `CONTEXT_CUT_THRESHOLD` in `scripts/cost-runtime/context-cut-threshold.ts`; `cost --cut`,
320
- `run:merge` and `run_cut.IMPLEMENTATION_CONTEXT_THRESHOLD` all read it rather than carrying separate
321
- numbers. The output ceiling and the entry-read figure are a separate 150,000, not this threshold.
315
+ `run:merge`, `run_cut.IMPLEMENTATION_CONTEXT_THRESHOLD` and the parent hand-off guard all read it. The
316
+ output ceiling and the entry-read figure are a separate 150,000, not this threshold.
322
317
 
323
318
  ### The check is asked at every merge, and delegation does not excuse it
324
319
 
@@ -333,7 +328,7 @@ answer, and take `over`'s branch at that child.
333
328
 
334
329
  ### When to ask, and what to do
335
330
 
336
- **Ask once per child, immediately after its merge and `pnpm josh ms`** — never mid-child.
331
+ **Ask once per child, immediately after its merge and `pnpm josh ms`**; mid-child, a hook asks (#2947).
337
332
 
338
333
  ### A parent without a completion callback hands off at its first dispatch
339
334
 
@@ -443,10 +438,9 @@ survive the cut is re-dispatched, never adopted** — `pnpm josh lane:open <N>`
443
438
  progress comment is generated from it** (joshuafolkken/kit#2024) — children run, Issues filed,
444
439
  **consecutive failures**, and the time the run started. `pnpm josh run:merge` writes the merge into
445
440
  the record and mirrors the counters onto the epic comment at every child's merge. **The
446
- consecutive-failure count is the one that matters** — the stopped-unit section leans on it to notice
447
- the environment is at fault, and a merge resets it. **The record survives a session cut and a
448
- compaction alike.** Rationale: `docs/maintainers/backlogrun-progress-rationale.md` → "Why state lives
449
- in records, not the conversation".
441
+ consecutive-failure count is the one that matters**, and a merge resets it. Rationale:
442
+ `docs/maintainers/backlogrun-progress-rationale.md` → "Why state lives in records, not the
443
+ conversation".
450
444
 
451
445
  ### What carries over, and where it lives
452
446
 
@@ -463,16 +457,18 @@ in records, not the conversation".
463
457
 
464
458
  ## Waiting, and never waiting forever
465
459
 
466
- | Setting | Value | Why |
460
+ | Setting | Value | Meaning |
467
461
  | --- | --- | --- |
468
462
  | Polling interval | 60 s | **A floor between two asks, never a clock the parent sets.** It bounds a re-ask made while the parent is *already awake*; what wakes it is "The parent keeps no clock of its own" below. |
469
463
  | `backlogrun` idle-watch poll | 5 min | Not the interval above, and a floor in the same sense. |
470
464
  | Silent delegated unit | 30 min | Not the child's duration — the time its output has gone **unchanged**. Past it, run the traces above and book a stopped unit as a failure. |
471
- | Stale `in-progress` | 90 min | Longer than any single child has taken; past it, the other session is gone. |
465
+ | Stale `in-progress` | 90 min | Past it, the other session is gone. |
472
466
  | Publish wait | 10 min | `josh propagate`'s own budget. A failed publish never appears. |
473
- | Whole run | 8 h | An unattended run that has not finished overnight needs a person, not more waiting. |
467
+ | Whole run | 8 h | Past it, the run needs a person. |
474
468
 
475
- Each timeout **ends the wait and reports** — none is retried indefinitely. A stale child's label is
469
+ Each timeout **ends the wait and reports** — none is retried indefinitely. Rationale for the figures:
470
+ `docs/maintainers/backlogrun-progress-rationale.md` → "Why the parent waits on classification, not a
471
+ clock". A stale child's label is
476
472
  removed first, so the next poll can offer it. **A graph that has deadlocked on a cycle is not this loop's
477
473
  to untangle**: `epic:next` detects it and exits with an error.
478
474
 
@@ -487,9 +483,7 @@ source and `run:report` the final report.
487
483
  `docs/maintainers/backlogrun-progress-rationale.md` → "Why the parent waits on classification, not a
488
484
  clock".
489
485
 
490
- The driver checks lane completion every five seconds and makes a new backlog offer no sooner than one
491
- minute after the previous offer, except after collecting a child — waits that cost no AI turns. The
492
- watcher reports on its own interval, and a judgment session may take its exit as a prompt to act.
486
+ The watcher reports on its own interval, and a judgment session may take its exit as a prompt to act.
493
487
 
494
488
  #### The wake exists only while something is in flight
495
489
 
@@ -527,7 +521,7 @@ Per-child completion notifications are unchanged: `pnpm josh followup` sends one
527
521
  **start** notification when the run begins, and an epic **completion** summary at the end. **Do not
528
522
  compose that summary by hand — `pnpm josh run:report` generates it from this invocation's events**
529
523
  (joshuafolkken/kit#2249, scoped in #2393): it renders what merged, what parked and why, and what was cut,
530
- reusing `format_event`, closing with the release tail below. Its output is the Telegram body too — pass it to
524
+ closing with the release tail below. Its output is the Telegram body too — pass it to
531
525
  `pnpm josh notify --body-file`.
532
526
 
533
527
  **That same session asks `pnpm josh release:scope` once, after the last child has merged** — in the
@@ -131,7 +131,7 @@ single source.
131
131
  carried in a record rather than in the conversation:
132
132
 
133
133
  ```bash
134
- pnpm josh run:carry --begin "backlogrun --max 5 --idle 30" --owner "$PPID" # alias: josh rc
134
+ pnpm josh run:carry --begin "backlogrun --max 5 --idle 30" --owner "$PPID"
135
135
  pnpm josh run:carry --json # read it back in a resumed session
136
136
  ```
137
137
 
@@ -204,7 +204,7 @@ judgment starts an AI session, with the branch result and resume flags in its pr
204
204
  **Start it in the same turn as `--begin`, and stop it in the same turn as `--end`:**
205
205
 
206
206
  ```bash
207
- pnpm josh run:wake --start # alias: josh rw ; right after `run:carry --begin`
207
+ pnpm josh run:wake --start # right after `run:carry --begin`
208
208
  pnpm josh run:wake --stop # in the same turn as `run:carry --end`
209
209
  ```
210
210
 
@@ -267,7 +267,7 @@ run.
267
267
  **The plan is one command's output, not an assembly of several:**
268
268
 
269
269
  ```bash
270
- pnpm josh backlog:plan # alias: josh blp
270
+ pnpm josh backlog:plan
271
271
  ```
272
272
 
273
273
  **It renders the same classified pool `backlog:next` answers from**, so **the plan cannot promise an
@@ -282,9 +282,8 @@ order the run does not take**. Its four sections are:
282
282
  is distinguished from "not reached yet".
283
283
 
284
284
  **Report all four to the person, in the session language, before the first child starts.** Epic
285
- children are enumerated individually rather than summarized under their root. A `⚠` about a truncated
286
- listing is reported with them: the plan is then partial, and saying so is what keeps it from reading as
287
- complete.
285
+ children are enumerated individually rather than summarized under their root. Report a truncated-listing
286
+ `⚠` with them: the plan is then partial.
288
287
 
289
288
  ### Resolve what the plan can resolve, before starting
290
289
 
@@ -293,27 +292,28 @@ stop at a time.**
293
292
 
294
293
  - **Decide everything decidable from the issue itself.** Read the issue's body **and its comments**
295
294
  (`SKILL.md` → §2g), and where the answer is already there, record it as an Issue comment and
296
- **remove the label** — `CLAUDE.md` → "Decision autonomy" already makes that Tier A. **Read every one
297
- of them in one call** — `pnpm josh issue:read <N> <N> …`, the numbers the plan just listed under
298
- "Waiting on a person" — rather than a `gh api` pair per issue.
295
+ **remove the label** — `CLAUDE.md` → "Decision autonomy" already makes that Tier A. **Read them all in
296
+ one `pnpm josh issue:read <N> <N> …` call**, not a `gh api` pair per issue.
299
297
  - **Never measure in order to decide.** A question needing a benchmark, a profile, or a run of the
300
298
  thing itself is not settled here: it stays labelled and the plan says so.
301
- - **Label what you find.** An issue that turns out to need a person's judgement has `needs-decision`
302
- applied — the same label a parked child gets, applied the way `backlogrun-park.md` → "park and continue"
303
- applies it. **The next plan then classifies it by reading the label alone**, never by reading the
304
- body again.
299
+ - **Label what you find.** An issue needing a person's judgement gets `needs-decision`, applied as
300
+ `backlogrun-park.md` → "park and continue" does. **The next plan classifies it by the label alone**,
301
+ never the body.
305
302
  - **Order and isolate the pool in the same pass** (joshuafolkken/kit#2776), from the same
306
303
  `issue:read`: an issue that must land first (it builds what another reuses, or both edit one code
307
304
  path) becomes a native `blocked-by`; an issue the `wip-cap.md` → 「実行のしかた」 enumeration hits
308
305
  gets `run:solo`, **every other one `run:lane`**. Comment the reason; the offer commands enforce all
309
306
  three, answering `triage` while an issue has neither.
307
+ - **`priority:high` puts an issue first** (joshuafolkken/kit#2928; ranking: `docs/josh-commands.md` →
308
+ `josh backlog:next`). Apply it only on a cited ground — a stated deadline or urgency, or a person's
309
+ written policy — commenting the ground; **never remove it**.
310
310
  - **Report the order those labels produce — `pnpm josh backlog:plan --waves`** (joshuafolkken/kit#2778),
311
311
  `backlog:next` played forward wave by wave. Report it with the plan, never an order derived by hand.
312
312
  - **Then start the loop.** Whatever is still labelled is reported as parked and left standing; the
313
313
  run does not wait on it.
314
314
 
315
- **`needs-decision`, `run:solo` and `run:lane` are the workflow labels a run may apply, and none is
316
- `auto-ok` or `needs-human-review`.** Those two stay a person's alone (this file, `SKILL.md` → §2z); a
315
+ **`needs-decision`, `run:solo`, `run:lane` and `priority:high` are the workflow labels a run may
316
+ apply, and none is `auto-ok` or `needs-human-review`.** Those two stay a person's alone (this file, `SKILL.md` → §2z); a
317
317
  run parks with `needs-decision` and a person clears it.
318
318
 
319
319
  Rationale: `docs/maintainers/backlogrun-steps-rationale.md` → "Why the plan and the decision pass come first"
@@ -331,7 +331,7 @@ returns the verdict with the issues to start. It stays both halves' contract sou
331
331
  *means* changes here.
332
332
 
333
333
  ```bash
334
- offer=$(pnpm josh backlog:offer --started "$started" --active "$active") # alias: josh blo
334
+ offer=$(pnpm josh backlog:offer --started "$started" --active "$active")
335
335
  offer=$(pnpm josh backlog:offer --started "$started" --active "$active" --exclude 1630,1631) # after #1630, #1631 merged
336
336
  ```
337
337
 
@@ -35,8 +35,8 @@ Review results and successful pushes are never turn boundaries.
35
35
  **`pnpm josh followup` refuses the merge until the round is recorded**
36
36
  (`pnpm josh review:record --check --issue <N>`, joshuafolkken/kit#2343).
37
37
  5. **The clean path ships in one call** — with no second round due, background
38
- `pnpm josh ship "<title> #<N>" --body-file <evidence.md>`: gate → `git -y` → foreground `followup` → `run:tail`, stopping at the
39
- first failure (joshuafolkken/kit#2398). `--review` runs both rounds (#2489). **Else a due round 2
38
+ `pnpm josh ship "<title> #<N>" --body-file <evidence.md>`: PR preflight (#2946) → gate → `git -y` →
39
+ `followup` → `run:tail`, stopping at the first failure (#2398). `--review` runs both rounds (#2489). **Else a due round 2
40
40
  does not fit `ship`**: the PR opens between the rounds — background `pnpm josh git -y "<title> #<N>"`, round 2 beside CI, then
41
41
  `pnpm josh followup`.
42
42
 
@@ -84,7 +84,7 @@ pnpm josh notify --task-type failure --issue-url "<issue-url>" --body "<the reas
84
84
  **The matching itself is unchanged, and so is the reason it is mechanical.** The instruction the mechanical read replaced was skipped in two runs out of three on the day it was measured, and one of those two could not have succeeded by eye at all: `AI_COPY_DIRECTORIES` holds directories, so a distributed path such as `.claude/skills/workflow-commands/backlogrun.md` appears in no list textually.
85
85
 
86
86
  ```bash
87
- pnpm josh sync:scope # managed | clean, naming which list claimed each path; alias: josh sys
87
+ pnpm josh sync:scope # managed | clean, naming which list claimed each path
88
88
  ```
89
89
 
90
90
  - **There is no flag to pass and nothing to approve.** `--managed-config-ignore-reason` is gone with the stop it existed to get past.
@@ -99,7 +99,7 @@ pnpm josh sync:scope # managed | clean, naming which list claimed each path;
99
99
  **The answer: `pnpm josh release:scope`.**
100
100
 
101
101
  ```bash
102
- pnpm josh release:scope # → required | skip | unknown ; alias: josh res
102
+ pnpm josh release:scope # → required | skip | unknown
103
103
  pnpm josh release:scope --json # the same answer as one JSON object
104
104
  ```
105
105
 
@@ -12,7 +12,7 @@ delegated unit executing `fullrun`'s procedure, and the hook keys its once-per-r
12
12
  same turn as whatever else the run already needs:
13
13
 
14
14
  ```bash
15
- pnpm josh issue:read <N> [<N> ...] # body and comments, one call per batch; alias: josh ird
15
+ pnpm josh issue:read <N> [<N> ...] # body and comments, one call per batch
16
16
  gh api repos/{owner}/{repo}/issues/<N>/comments --jq '.[] | {user: .user.login, created_at, body}'
17
17
  ```
18
18
 
@@ -32,13 +32,7 @@ The detail below is read at the filing decision, and the marker suite pins the r
32
32
 
33
33
  ### The depth test — a discretionary filing cites the product work it blocked
34
34
 
35
- **A run that has just spent an hour inside the workflow tooling files findings about the workflow
36
- tooling** (joshuafolkken/kit#1698). Measured on the `backlogrun` of 2026-09-09: 5 Issues shipped and
37
- 15 filed, of which 13 were discretionary — and all 20 were about this package's own run
38
- orchestration or the tools that measure it, with not one change a consumer of the package would see.
39
- **A listing that measures itself has no natural stopping condition**, because every measurement
40
- creates something new to measure. So the condition comes from outside, and **depth is what supplies
41
- it — read off the subject rather than judged**:
35
+ **Depth is read off the subject rather than judged** (joshuafolkken/kit#1698):
42
36
 
43
37
  | Depth | The subject | Where it lives |
44
38
  | --- | --- | --- |
@@ -75,16 +69,14 @@ gh api repos/{owner}/{repo}/labels -f name=depth:2 -f color=c5def5 -f descriptio
75
69
  - **It is read off the subject, exactly as the table is** — so applying it is not a judgement and not
76
70
  a person's to make, which is what separates it from `auto-ok` and `needs-human-review`. Those two
77
71
  decide what a run may do; this one records what an Issue is about and withholds nothing.
78
- - **Applied at filing, not at completion.** A depth assigned when the work finishes is assigned by
79
- whoever happens to close it, and the share below is a question about the *open* backlog — an Issue
80
- that never carried the label was never in the numerator's reach.
72
+ - **Applied at filing, not at completion.**
81
73
  - **An Issue carrying more than one counts as the lowest depth present**, the one closest to the
82
- consumer. It is a fixed tie-break rather than a preference: without one the same backlog measured
83
- twice can answer twice, which is the whole defect joshuafolkken/kit#1729 was filed for.
74
+ consumer.
84
75
  - **An `epic` takes no depth label**, because it has no subject of its own to read one off — its
85
76
  children carry the subjects, and the share below excludes it from the denominator for that same
86
- reason. A depth label present on an Issue the count skips is exactly the ambiguity this section
87
- exists to remove.
77
+ reason.
78
+
79
+ Rationale: `docs/maintainers/observation-filing-rationale.md` → "Why the depth label is applied at filing".
88
80
 
89
81
  - **A discretionary observation at depth 1 or deeper is filed only where it can cite the depth-0 work
90
82
  it stopped or delayed** — named as an Issue number or a run, never as "this would slow runs down".
@@ -96,12 +88,8 @@ gh api repos/{owner}/{repo}/labels -f name=depth:2 -f color=c5def5 -f descriptio
96
88
  - **`route:tier-a` and `route:interrupt` do not take it either**, at any depth: a filing the run
97
89
  cannot proceed without is already citing its own blockage.
98
90
  - **A depth-2 filing — one whose subject is what measures a run — carries a further requirement, on
99
- top of the depth-0 citation above rather than in place of it** (joshuafolkken/kit#1975). The
100
- citation the depth-0 gate asks for is one a slow run can always produce, so it barely bites on a
101
- measurement Issue: "runs are slow" and "the diff is large" both name depth-0 work, while the number
102
- the Issue proposes to produce changes nothing — and a listing that measures itself has no natural
103
- stopping condition precisely there. So a discretionary depth-2 filing states two things the depth-0
104
- citation does not force:
91
+ top of the depth-0 citation above rather than in place of it** (joshuafolkken/kit#1975). A
92
+ discretionary depth-2 filing states two things the depth-0 citation does not force:
105
93
  - **The decision the number would change, named** — the Issue number holding the choice it is
106
94
  waiting on, or a decision a person is about to make. "Slow", "large" and "worth knowing" are not a
107
95
  decision.
@@ -115,15 +103,15 @@ gh api repos/{owner}/{repo}/labels -f name=depth:2 -f color=c5def5 -f descriptio
115
103
  depth-0 observation does not take it because it is the product, and a review round cap's branch-2
116
104
  filing (below) clears its own bar and never reaches this one.
117
105
 
106
+ Rationale: `docs/maintainers/observation-filing-rationale.md` → "Why depth gates a discretionary filing".
107
+
118
108
  **It governs this route only — the fourth row of §2d's table.** A review finding routed to branch 2
119
109
  of `prompts/review.md` → "Review round cap" is filed under that section's own bar — a confirmed
120
110
  defect reaching a runtime path, with a written failure scenario — and **does not take the depth
121
111
  test**: it has already cleared a bar this route has not, so gating it on a citation as well would
122
112
  drop the one kind of finding both documents agree is never dropped. **That bar is the reason, and the
123
- subject's depth is not** — the sentence here used to say that a defect in a `josh` command's behavior
124
- is depth 0 by construction, and joshuafolkken/kit#1694 and joshuafolkken/kit#1703 are both branch-2
125
- filings whose subject is the epic tooling, which the table above puts at depth 1
126
- (joshuafolkken/kit#1675).
113
+ subject's depth is not.** Rationale: `docs/maintainers/observation-filing-rationale.md` → "Why a
114
+ review branch-2 filing skips the depth test".
127
115
 
128
116
  **This is not the count cap that was rejected.** A cap is rationing — past the number the finding is
129
117
  lost, and nothing about it says which findings were worth having. This changes what counts as a
@@ -133,34 +121,26 @@ finding at all, so what it excludes is excluded for a reason a reader can check.
133
121
  a depth-2 Issue that *proposes* a measurement; a pull request that *adds* one — a new report column,
134
122
  section, scope or subcommand, a diagnostic step — states in its body the reader that consumes it: the
135
123
  Issue number that read the value to decide something, or the path of the rule that reads it. **A
136
- measurement with no reader is not added** — this is joshuafolkken/kit#2012's test, the one that
137
- retired every column no decision reads, moved to the moment a column is proposed so the retirement
138
- never has to be filed again. `route:tier-a` and `route:interrupt` carry over unchanged.
124
+ measurement with no reader is not added** (joshuafolkken/kit#2012). `route:tier-a` and
125
+ `route:interrupt` carry over unchanged.
139
126
 
140
127
  ### The depth-0 share — what is counted
141
128
 
142
- **joshuafolkken/kit#1698 set a measurable target: the share of open Issues at depth 0** — 3/23
143
- ≈ 13% on 2026-09-09 (joshuafolkken/kit#1729). Counted by eye it is not reproducible: done again on
144
- 2026-09-10 it produced 3/14 ≈ 21%, and the two figures **are not comparable**: they took different
145
- denominators, and neither said which. So the denominator is fixed here as a rule rather than left to
146
- the counter.
129
+ **The depth-0 share is the share of open Issues at depth 0** (joshuafolkken/kit#1698,
130
+ joshuafolkken/kit#1729).
147
131
 
148
132
  **The denominator is a rule, not a choice, and this is it:**
149
133
 
150
- - **Counted: every open Issue that does not carry `epic`.** An epic is a container for other Issues
151
- rather than a deliverable of its own — counting one counts its children twice, and an epic has no
152
- subject of its own to read a depth off.
134
+ - **Counted: every open Issue that does not carry `epic`.**
153
135
  - **`route:tier-a` and `route:interrupt` are counted like anything else.** The depth test above
154
- exempts them from its *citation* requirement; it never said they are not work. Excluded, a run
155
- could improve the share by choosing a filing route.
156
- - **An Issue with no depth label is in the denominator**, counted separately as `unlabelled`. Left
157
- out, the share would improve every time a filing skipped the label — the one direction a
158
- measurement must never be able to move on its own.
136
+ exempts them from its *citation* requirement; it never said they are not work.
137
+ - **An Issue with no depth label is in the denominator**, counted separately as `unlabelled`.
159
138
  - **The numerator is what is left**: open, non-epic Issues carrying `depth:0`.
160
139
 
161
- **Two readings of the same backlog give the same number**, which is what the hand counts could not
162
- do: the denominator is a rule rather than a choice, so nothing in the count is left to the counter's
163
- judgement.
140
+ **Two readings of the same backlog give the same number**: nothing in the count is left to the
141
+ counter's judgement.
142
+
143
+ Rationale: `docs/maintainers/observation-filing-rationale.md` → "Why the depth-0 denominator is fixed".
164
144
 
165
145
  **What the number is for is not decided here.** Changing what `backlog:next` offers on the strength
166
146
  of it, and setting a target value, are both deliberately out of scope until the current value has
@@ -168,12 +148,9 @@ been measured the same way more than once (joshuafolkken/kit#1729 → 範囲外)
168
148
 
169
149
  ### The ledger — where an observation that cannot cite a blockage goes
170
150
 
171
- **"Not filed" used to mean "gone", and that is what walked the depth test past itself.** The
172
- completion report was the only place such an observation could land, and a completion report is
173
- read once and then scrolls away — so the next run met the same thing as a first sighting, forever.
174
- joshuafolkken/kit#1726 is the worked case: its own body says the depth test would not have filed it,
175
- and it was filed anyway, because **discarding it was the only alternative on offer**
176
- (joshuafolkken/kit#1728).
151
+ **An observation the depth test turns away is recorded in the ledger, not discarded**
152
+ (joshuafolkken/kit#1728). Rationale: `docs/maintainers/observation-filing-rationale.md` → "Why the
153
+ ledger exists".
177
154
 
178
155
  - **The destination is the `docs/maintainers/observations/` directory in the repository the
179
156
  observation is about** — the same repository the Issue would have been filed into — **one file per
@@ -221,9 +198,8 @@ A sample, in the shape a real entry takes:
221
198
 
222
199
  **`k:example` is reserved for this sample and is never used by a real observation**, so the count
223
200
  below can be run over the whole ledger without the sample answering for one. **The grammar is defined
224
- here rather than in the ledger** because this skill is distributed to every repository that consumes
225
- the package and `docs/` is not — a rule that named a definition the reader never received would
226
- leave every consumer's ledger shaped by hand.
201
+ here rather than in the ledger** (`docs/maintainers/observation-filing-rationale.md` → "Why the
202
+ ledger exists").
227
203
 
228
204
  **The identity key is the whole of the repeat test — never a similarity judgement about the prose.**
229
205
  Choose the key from the phenomenon rather than from the run, then count what the ledger already holds
@@ -244,27 +220,17 @@ rather than by editing the one already written.
244
220
 
245
221
  **The depth gate is not withdrawn, and this is not a way around it.** An observation that *can* cite
246
222
  the depth-0 work it stopped is filed exactly as it was before — this route is only for the ones that
247
- could not, and whose sole previous destination was nothing (joshuafolkken/kit#1698's gate stands
248
- unchanged).
223
+ could not.
249
224
 
250
225
  ### The commit path — how an appended line reaches the default branch
251
226
 
252
- **An append nobody commits is an append nobody can count** (joshuafolkken/kit#1756). The ledger was
253
- given a destination and no route out of the working tree the line was written in, and **structurally
254
- nobody was going to commit one**: the parent session that appends never runs `pnpm josh git`, a child
255
- runs it inside a lane work tree that cannot see the parent's checkout, and in the primary checkout
256
- `git add -u` swept the line into whatever unrelated pull request that run was opening. Measured on
257
- the day the ledger shipped, `docs/observations.md` had exactly one commit — the one that created
258
- it — and seven lines had never left a working tree. **So the repeat count below was reading a file
259
- that is empty on every other machine**, and every sighting was a first one, which is the state
260
- joshuafolkken/kit#1728 created the ledger to end.
227
+ **An append nobody commits is an append nobody can count** (joshuafolkken/kit#1756). Rationale:
228
+ `docs/maintainers/observation-filing-rationale.md` → "Why the ledger has a commit path".
261
229
 
262
230
  - **A run's appended lines ride its own commit** (joshuafolkken/kit#2763). `pnpm josh git` stages
263
231
  `docs/maintainers/observations/` with the run's other changes, in the one staging step every entry
264
232
  point goes through (`scripts/git/git-staging.ts`), so the lines are reviewed and merged with the
265
- pull request of the run that recorded them, and the run's CI is the only wait they cost. Until
266
- #2763 the ledger was excluded there (joshuafolkken/kit#1756) and every run that appended a line
267
- paid a second branch, CI wait and merge after its own — 144 ledger-only pull requests in one month.
233
+ pull request of the run that recorded them, and the run's CI is the only wait they cost.
268
234
  **Record before the commit, not after the merge:** a finding recorded with `pnpm josh review:record`
269
235
  before `pnpm josh git -y` is carried; the time while CI runs is for the records that need no CI
270
236
  result — filing an observation Issue, drafting the completion report.
@@ -280,10 +246,7 @@ joshuafolkken/kit#1728 created the ledger to end.
280
246
  otherwise be lost with the branch. A run whose lines rode its commit pays nothing.
281
247
  - **A lane carries its own lines, in its own pull request** (joshuafolkken/kit#2919). Its writers
282
248
  append to its own tree's `<N>.md`, so the two steps above take them to the default branch exactly as
283
- they do for a run in the primary checkout. Lanes once wrote to the primary checkout's single file
284
- instead (joshuafolkken/kit#2419) and a `backlogrun` flushed them all at `run:carry --end`
285
- (joshuafolkken/kit#2492); another run's stash of that checkout took the lines before the flush saw
286
- them, so neither route remains. **Nothing is held in the primary checkout for later.**
249
+ they do for a run in the primary checkout. **Nothing is held in the primary checkout for later.**
287
250
  - **`pnpm josh observations:flush` is left for a line written outside any issue's run** — the
288
251
  date-named file a retrospective or a hand append on the default branch writes. It stages the ledger
289
252
  and nothing else, commits it on a branch of its own, opens a docs-only pull request, waits on the
@@ -300,10 +263,9 @@ joshuafolkken/kit#1728 created the ledger to end.
300
263
 
301
264
  ### The second sighting is what files it
302
265
 
303
- **A repeat is the citation.** joshuafolkken/kit#1698 asked a discretionary filing to be pulled by a
304
- blockage rather than pushed by a sighting; an observation recorded twice has been pulled — it came
305
- back on its own, which no single sighting can demonstrate. So the gate has a second way through, and
306
- it is counted rather than judged:
266
+ **A repeat is the citation**, so the gate has a second way through, and it is counted rather than
267
+ judged (rationale: `docs/maintainers/observation-filing-rationale.md` → "Why a second sighting
268
+ files"):
307
269
 
308
270
  - **On the count answering exactly `1`, the observation is filed**, at depth 1 or deeper, with no
309
271
  depth-0 citation — `1` and not "1 or more", because a higher count means the Issue was already
@@ -336,19 +298,12 @@ could bite later" line (`backlogrun-child.md` → "What the summary carries, and
336
298
  parent files what survives — under the depth test above, and inside the run's ceiling.
337
299
 
338
300
  **A delegated child does not append to the ledger either — the parent collapses the duplicates and
339
- appends what is left.** The ledger's whole value is that one key means one phenomenon, and a child
340
- holding one Issue's worth of context cannot tell its observation from the sibling lane's: eight
341
- children appending in parallel would write the same thing under eight keys, and every one of them
342
- would then read as a first sighting. The child's route is unchanged and is the only one it has —
301
+ appends what is left.** The child's route is unchanged and is the only one it has —
343
302
  the summary's "Observations that could bite later" line — and the parent chooses the key, checks the
344
- count and writes the line.
345
-
346
- **Two reasons, and a child can solve neither for itself.** It holds one Issue's worth of context, so
347
- **it cannot tell its observation from the one a sibling filed twenty minutes earlier** — the 15
348
- filings of 2026-09-09 were collapsed to 12 within that same day, which means they were collapsible
349
- at the moment they were made. And **the 10-per-run ceiling for this route is the parent's to
350
- count**: six children counting two or three filings each never reach it, which is why it did not
351
- fire once on the run that filed fifteen.
303
+ count and writes the line. **The 10-per-run ceiling for this route is the parent's to count.**
304
+
305
+ Rationale: `docs/maintainers/observation-filing-rationale.md` → "Why a delegated child neither files
306
+ nor appends".
352
307
 
353
308
  **This file is the single source of every procedure above**, and `SKILL.md` → §2i is the single
354
309
  source of the rule they carry out; nothing under `prompts/collaboration-workflow/` restates either