@joshuafolkken/kit 1.978.0 → 1.983.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 (69) hide show
  1. package/.claude/skills/epic-commands/SKILL.md +6 -5
  2. package/.claude/skills/workflow-commands/SKILL.md +9 -9
  3. package/.claude/skills/workflow-commands/background-commands.md +1 -1
  4. package/.claude/skills/workflow-commands/fullrun-steps.md +8 -8
  5. package/.claude/skills/workflow-commands/halfrun.md +4 -5
  6. package/.claude/skills/workflow-commands/issue-comments.md +1 -1
  7. package/.claude/skills/workflow-commands/issue-scout.md +21 -22
  8. package/.claude/skills/workflow-commands/kickoff.md +8 -9
  9. package/.claude/skills/workflow-commands/observation-filing.md +9 -10
  10. package/.claude/skills/workflow-commands/prerequisite.md +7 -6
  11. package/.claude/skills/workflow-commands/retrospective.md +5 -5
  12. package/.claude/skills/workflow-commands/rule-residency.md +2 -2
  13. package/.claude/skills/workflow-commands/split-assessment.md +4 -3
  14. package/.claude/skills/workflow-commands/target-repository.md +7 -6
  15. package/dist/hooks/batch-guard.js +4 -4
  16. package/dist/hooks/{chunk-ZPLXLJ7O.js → chunk-47SPMGOD.js} +16 -1
  17. package/dist/hooks/{chunk-BVMSPG3M.js → chunk-5JX6HXDX.js} +3 -3
  18. package/dist/hooks/{chunk-KQG4776P.js → chunk-APVOACVT.js} +1 -1
  19. package/dist/hooks/{chunk-2K52BRWV.js → chunk-ASUZGZFT.js} +2 -2
  20. package/dist/hooks/{chunk-CRGJTD6E.js → chunk-ERXMJJOV.js} +1 -1
  21. package/dist/hooks/{chunk-Q7LE77CO.js → chunk-IM3KM25Y.js} +31 -29
  22. package/dist/hooks/{chunk-BNGGEY3Z.js → chunk-LBXQHXMC.js} +129 -342
  23. package/dist/hooks/{chunk-NXL3SBXY.js → chunk-P3UX7SFN.js} +2 -2
  24. package/dist/hooks/{chunk-F6OM6SIG.js → chunk-RFPHKU7C.js} +12 -12
  25. package/dist/hooks/{chunk-ZYYSBNR6.js → chunk-ZT65LR3U.js} +4 -4
  26. package/dist/hooks/codex-hook-adapter.js +10 -10
  27. package/dist/hooks/duplicate-read-guard.js +5 -5
  28. package/dist/hooks/format-edited.js +2 -2
  29. package/dist/hooks/investigation-guard.js +5 -5
  30. package/dist/hooks/pretool-guard.js +9 -9
  31. package/dist/hooks/stop-guard.js +4 -4
  32. package/dist/josh.js +16 -1
  33. package/package.json +1 -1
  34. package/prompts/collaboration-workflow/epic-bundle.md +8 -8
  35. package/prompts/collaboration-workflow/issue-template.md +5 -5
  36. package/prompts/collaboration-workflow/rule-delivery.md +43 -30
  37. package/prompts/collaboration-workflow/upstream-interrupt.md +1 -1
  38. package/prompts/collaboration-workflow/wip-cap.md +3 -3
  39. package/prompts/review.md +11 -9
  40. package/scripts/delegation/delegation-policy.ts +9 -9
  41. package/scripts/document/document-byte-budget.ts +1 -1
  42. package/scripts/issue/issue-file-cli.ts +188 -0
  43. package/scripts/issue/issue-file.ts +192 -0
  44. package/scripts/issue/issue-lint-cli.ts +1 -1
  45. package/scripts/issue/issue-scout-cli.ts +41 -97
  46. package/scripts/issue/issue-scout-closed.ts +102 -0
  47. package/scripts/josh/__snapshots__/josh-command-map.test.ts.snap +9 -1
  48. package/scripts/josh/josh-command-map.ts +1 -0
  49. package/scripts/josh/josh-commands-issue.ts +11 -0
  50. package/scripts/josh/josh-commands-project.ts +5 -1
  51. package/scripts/propagate/propagate-run.ts +1 -0
  52. package/scripts/propagate/propagate-select.ts +72 -0
  53. package/scripts/propagate/propagate-targets.ts +5 -3
  54. package/scripts/propagate/propagate.ts +86 -24
  55. package/scripts/rules/bash-triggers.ts +19 -6
  56. package/scripts/rules/delivered-rules.ts +28 -32
  57. package/scripts/rules/direct-filing.ts +38 -0
  58. package/scripts/rules/filing-cap.ts +11 -8
  59. package/scripts/rules/issue-fold.ts +4 -4
  60. package/scripts/rules/oracle-consulted.ts +4 -4
  61. package/scripts/rules/oracle-firing.ts +13 -16
  62. package/scripts/rules/rule-body-guard.ts +6 -9
  63. package/scripts/rules/stop-rules.ts +3 -2
  64. package/scripts/test/pilot-files.ts +0 -1
  65. package/scripts/version/fresh-metadata-cache.ts +36 -0
  66. package/scripts/version/latest-update.ts +2 -1
  67. package/scripts/rules/issue-bug-label.ts +0 -85
  68. package/scripts/rules/issue-filing-args.ts +0 -50
  69. package/scripts/rules/issue-scout.ts +0 -64
@@ -350,8 +350,9 @@ a publish that predates the change.
350
350
 
351
351
  ## `josh epic:bundle <N>` — does this new issue belong with one already filed?
352
352
 
353
- Run it right after an issue is filed: by `kickoff` / `fullrun` / `halfrun`, or by any Tier A filing
354
- mid-implementation, including inside a `backlogrun`. **It recommends; it writes nothing.**
353
+ It runs right after an issue is filed: by `kickoff` / `fullrun` / `halfrun`, or by any Tier A filing
354
+ mid-implementation, including inside a `backlogrun`. **`pnpm josh issue:file` runs it as its last step**;
355
+ run it by hand only when that step printed `⚠`. **It recommends; it writes nothing.**
355
356
 
356
357
  "Two or more always means an epic" only fires when one request is split on the spot. Two issues filed
357
358
  days apart that turn out to be the front and back of one job are executed separately, in whatever
@@ -454,9 +455,9 @@ decisions" section above says what to do instead.
454
455
  answers the same epic question for an issue that does not exist yet — this decision, called rather
455
456
  than restated — and beside it the one thing this one deliberately refuses: whether the work has
456
457
  already been filed, from a title comparison (joshuafolkken/kit#1252). **Both run**, and neither
457
- replaces the other: the scout is what a `new` entry point asks before `gh api … issues`, and
458
- `epic:bundle` is what it asks afterwards, from the real number and the relations recorded against it.
459
- Full behavior: `docs/josh-commands.md` → "`josh issue:scout`".
458
+ replaces the other: `pnpm josh issue:file` runs the scout before it creates the issue, and
459
+ `epic:bundle` afterwards, from the real number and the relations recorded against it.
460
+ Full behavior: `docs/josh-commands.md` → "`josh issue:file`".
460
461
 
461
462
  **When the relation carries an order, record it** in `blocked-by` and in the epic's `Dependencies` —
462
463
  on an addition as much as on a new epic. Without it the batch survives and the reason for it does
@@ -193,15 +193,15 @@ third of four mid-run discoveries, distinct from an upstream defect, a split (`s
193
193
  and an observation (§2i). The full table, the filing command, the `-u`/`stash:pop` steps and the
194
194
  10-per-run cap are `prerequisite.md`, its single source, read at that trigger. **When the prerequisite
195
195
  is the run's second filing, `pnpm josh issue:fold` runs first** (§2e), and `pnpm josh rule:guard`
196
- refuses the second `gh api … issues` call until it has.
196
+ refuses the second `pnpm josh issue:file` call until it has.
197
197
 
198
198
  ## 2e. Before filing a new Issue — `pnpm josh issue:scout`
199
199
 
200
- **Before every new Issue is filed, run `pnpm josh issue:scout <title>` and read its duplicate and epic
201
- answers.** This applies inside every workflow, including observations and review follow-ups. The
202
- guard refuses a filing without it. Read `issue-scout.md` at that point for the duplicate, closed-Issue
203
- and epic decisions; `issue-fold-existing.md` handles a compatible duplicate. `docs/josh-commands.md`
204
- → "`josh issue:scout`" defines the command's output.
200
+ **Every new Issue is filed with `pnpm josh issue:file`, which runs the `issue:scout` scan first — read
201
+ its duplicate and epic answers.** This applies inside every workflow, including observations and review
202
+ follow-ups. The guard refuses any other filing call. Read `issue-scout.md` at that point for the
203
+ duplicate, closed-Issue and epic decisions and for `--distinct`; `issue-fold-existing.md` handles a
204
+ compatible duplicate. `docs/josh-commands.md` → "`josh issue:file`" defines the command.
205
205
 
206
206
  ## 2f. The working-tree hold — one run per tree
207
207
 
@@ -239,14 +239,14 @@ parent-wake half at `backlogrun-progress.md` → "The parent keeps no clock of i
239
239
  **When a first-party observation is worth filing, file it without asking and continue the run.**
240
240
  Read `observation-filing.md` in full before filing: it decides the depth test, filing ceilings, labels,
241
241
  second-filing fold, ledger fallback and delegated-child handoff. Use `pnpm josh repo:party` to decide
242
- first-party status, then run `pnpm josh issue:scout` before filing (§2e). A third-party target remains
242
+ first-party status, then file with `pnpm josh issue:file` (§2e). A third-party target remains
243
243
  Tier C (`CLAUDE.md`).
244
244
 
245
245
  ## 2j. The end-of-run retrospective — read when `run:step` prints it
246
246
 
247
247
  **When `pnpm josh run:step` prints the retrospective step, read `retrospective.md` in full and run the
248
- digest it names once.** File up to two worthwhile improvements through `issue:scout` and
249
- `epic:bundle`, stack the rest in the observation ledger, and close the step with the command described
248
+ digest it names once.** File up to two worthwhile improvements through `issue:file` (scout and
249
+ `epic:bundle` included), stack the rest in the observation ledger, and close the step with the command described
250
250
  there. A dispatched lane child never runs the retrospective.
251
251
 
252
252
  ## 3. What stays resident, and what is read from here
@@ -110,7 +110,7 @@ with. Applied to the three waits a run actually has:
110
110
  | --------------- | ----------------- |
111
111
  | `pnpm josh gate` | a subagent running `/code-review` with the brief `pnpm josh review:brief` prints |
112
112
  | `pnpm josh git -y` | Write the completion notification body to a file for `--notify-message-file`, and settle the three-way disposition of any remaining non-High finding |
113
- | CI, after the push | The second review round where one is due, the branch-2 filing, and `pnpm josh epic:bundle <new>` (`prompts/review.md` → "Review round cap") |
113
+ | CI, after the push | The second review round where one is due, the branch-2 filing through `pnpm josh issue:file`, which runs `epic:bundle` itself (`prompts/review.md` → "Review round cap") |
114
114
  | `pnpm josh followup` | Nothing — it is foreground and holds the session. **The post-merge tail is what overlaps here, and it is taken before the call rather than beside it**: compose the epic progress counters first, and leave after the merge only the steps that read its result, plus `pnpm josh cost --cut` |
115
115
 
116
116
  **The turn never ends at the push.** The completion notification for `pnpm josh git -y` is what
@@ -7,7 +7,7 @@ the run is at, and the sections below carry that step in full.
7
7
 
8
8
  ## The `fullrun #N` step list
9
9
 
10
- Use `pnpm josh issue:lint` `labels:`; see `prompts/collaboration-workflow/issue-template.md`.
10
+ File Issues with `pnpm josh issue:file` (it applies the classification labels); see `prompts/collaboration-workflow/issue-template.md`.
11
11
 
12
12
  **Add `in-progress` the moment `run:hold` answered `hold`** (create if missing:
13
13
  `gh api repos/{owner}/{repo}/labels -f name=in-progress -f color=0075ca -f description="Work is
@@ -29,7 +29,7 @@ with the brief `pnpm josh review:brief` prints on `git diff main`, join the gate
29
29
  iterate to no high/medium findings, at most two reviews → **the clean path folds the ship region into
30
30
  one call**, `pnpm josh ship "<title> #<N>"` (gate → commit/push/PR → the CI-wait `followup` → the
31
31
  `run:tail` report bookkeeping, stopping at the first failed step; joshuafolkken/kit#2398), with any
32
- branch-2 filing and `pnpm josh epic:bundle` run before it → **when a second round is due `ship` does not
32
+ branch-2 filing (`pnpm josh issue:file`, which runs `epic:bundle` itself) run before it → **when a second round is due `ship` does not
33
33
  fit**: open the PR between the rounds with `pnpm josh git -y "<title> #<N>"`, run round 2 beside CI, then
34
34
  `pnpm josh followup` and `pnpm josh run:tail <N>`). Issue plan comments are written in the session language (`JOSH_SESSION_LANG`,
35
35
  default `ja`). Before implementing, run `git switch main && git pull`, then `pnpm josh latest:scope`
@@ -49,10 +49,10 @@ completion notification, then merges; if blockers are found it exits non-zero
49
49
  ## The `fullrun new` step list
50
50
 
51
51
  `kickoff new` + `fullrun #N` in one run. Steps: (1) Derive an English title, or use the provided one.
52
- **(1a) Run `pnpm josh issue:scout "<title>" [--body "<summary>"]` before creating the Issue** — a
53
- candidate that covers the same work stops the run rather than filing a second Issue (`SKILL.md` → §2e).
54
- (2) Create Issue: `gh api repos/{owner}/{repo}/issues -f title="<title>" -f 'labels[]=depth:<n>' -F
55
- body=@<body-file>` (per `prompts/collaboration-workflow/issue-template.md`). Capture `<N>`. (3) Add
52
+ (2) Create Issue: `pnpm josh issue:file "<title>" --body-file <body-file> --depth <n>` (per
53
+ `prompts/collaboration-workflow/issue-template.md`) — its duplicate scan runs first, and a candidate
54
+ that covers the same work stops the run rather than filing a second Issue (`SKILL.md` → §2e). Capture
55
+ `<N>`. (3) Add
56
56
  `in-progress` (as above). (4) Post the agreed plan in the session language: fill the body if blank,
57
57
  otherwise add a comment. (5) If the working tree already has staged or modified files,
58
58
  `git stash push -m "fullrun new: pre-existing changes"` first. (6) `git switch main && git pull`. (7)
@@ -65,8 +65,8 @@ round 1's fixes are in and before the commit. (10) Where the tree was edited aft
65
65
  started, re-run `pnpm josh gate` and join it. (11) `pnpm josh git -y "<title> #<N>"` — the pull request
66
66
  opens here, between the two rounds. (11a) Run the **second round** now beside the CI, where (9a)
67
67
  answered `required` (brief `pnpm josh review:brief --round 2`); a finding it fixes in place is pushed
68
- before its gate. (12) File whatever the review round cap routed to branch 2, run `pnpm josh epic:bundle
69
- <new>` on each, and where (9a) answered `skip` record the skip on the Issue. (13) **Where no second
68
+ before its gate. (12) File whatever the review round cap routed to branch 2 with `pnpm josh issue:file`
69
+ (it runs `epic:bundle` on each), and where (9a) answered `skip` record the skip on the Issue. (13) **Where no second
70
70
  round was due** (9a `skip`), fold steps (10)–(13) and the release bookkeeping into one call — `pnpm josh
71
71
  ship "<title> #<N>" --notify-message "..."` (gate → commit/push/PR → the CI-wait `followup` → `run:tail`,
72
72
  stopping at the first failed step; joshuafolkken/kit#2398); **where a second round ran**, the PR opened
@@ -1,6 +1,6 @@
1
1
  # `halfrun` — the manifest (implement + verify, stop before commit)
2
2
 
3
- When this run files a new Issue, run `pnpm josh issue:lint <body-file>` and apply every label in its `labels:` answer at creation; `prompts/collaboration-workflow/issue-template.md` is the single source for this classification. Keep the existing `depth` and `route` labels.
3
+ When this run files a new Issue, file it with `pnpm josh issue:file`, which lints the body and applies the classification labels it declares beside the `--depth` and `--route` labels; `prompts/collaboration-workflow/issue-template.md` is the single source for this classification.
4
4
 
5
5
  `halfrun` sits between `kickoff` (plan only) and `fullrun` (full execution with auto-merge). It
6
6
  implements the change and runs the full verification gate, then **stops before commit** — nothing is
@@ -56,10 +56,9 @@ back with fixes, treat each as a new round: implement, re-run `pnpm josh gate`,
56
56
  `confirmation` Telegram, stop again.
57
57
 
58
58
  `halfrun new` or `halfrun new "<title>"`: `kickoff new` + `halfrun #<N>` (no Issue exists yet). Steps
59
- mirror `fullrun new` (1)–(8): derive an English title (or use the provided one) → **run `pnpm josh
60
- issue:scout "<title>" [--body "<summary>"]` before creating the Issue** (`SKILL.md` → §2e) → create the
61
- Issue (`gh api repos/{owner}/{repo}/issues -f title="<title>" -f 'labels[]=depth:<n>' -F body=@<body-file>`,
62
- body per `prompts/collaboration-workflow/issue-template.md`) → add `in-progress` → post the agreed plan → stash
59
+ mirror `fullrun new` (1)–(8): derive an English title (or use the provided one) → create the Issue
60
+ (`pnpm josh issue:file "<title>" --body-file <body-file> --depth <n>`, body per
61
+ `prompts/collaboration-workflow/issue-template.md`; its duplicate scan is read per `SKILL.md` → §2e) → add `in-progress` → post the agreed plan → stash
63
62
  any pre-existing changes with `git stash push -m "halfrun new: pre-existing changes"`, popped by
64
63
  message with `pnpm josh stash:pop "halfrun new: pre-existing changes"`, never a positional `git stash pop` →
65
64
  `git switch main && git pull` → `pnpm josh latest:scope` → implement → run the gate (as above, `pnpm
@@ -104,6 +104,6 @@ never the comment text.
104
104
 
105
105
  **`pnpm josh rule:guard` refuses the body-only read** and hands over the reissue and the conflict rule
106
106
  at the moment they bind (`prompts/collaboration-workflow/rule-delivery.md`,
107
- `scripts/rules/delivered-rules.test.ts`). The refusal reaches Claude Code alone and fires once per run,
107
+ `scripts/rules/delivered-rules.test.ts`). The refusal reaches Claude Code alone and repeats until the comments are read,
108
108
  so **this file is the rule and the hook is what makes it hard to walk past** — a session that runs
109
109
  no hooks still owes the read.
@@ -1,12 +1,13 @@
1
1
  # Filing an Issue — `SKILL.md` §2e's procedure
2
2
 
3
- Read this file when an Issue title exists and before the `gh api … issues` call that files it. Every
4
- filing asks whether the work already exists and which epic owns it; one command answers both:
3
+ Read this file when an Issue title exists and before the `pnpm josh issue:file` call that files it.
4
+ Every filing asks whether the work already exists and which epic owns it; the command runs the
5
+ `issue:scout` scan on the title and body first and holds the filing until every printed candidate is
6
+ named in `--distinct`:
5
7
 
6
8
  ```bash
7
- pnpm josh issue:scout "<title>" # alias: josh isc
8
- pnpm josh issue:scout "<title>" --body "<one-line summary, citing #N where the work follows one>"
9
- pnpm josh issue:scout "<title>" --body-file <complete-draft.md>
9
+ pnpm josh issue:file "<title>" --body-file <complete-draft.md> --depth <n> [--route <route>]
10
+ pnpm josh issue:file "<title>" --body-file <complete-draft.md> --depth <n> --distinct 2801,2795
10
11
  ```
11
12
 
12
13
  - **`Duplicates:` is read, not skimmed.** Open each candidate and apply `issue-fold-existing.md`
@@ -14,32 +15,30 @@ pnpm josh issue:scout "<title>" --body-file <complete-draft.md>
14
15
  Telegram and "Please run `fullrun #<existing>` to execute this Issue." A compatible addition follows
15
16
  that file's fold path; a separate deliverable follows the ordinary filing path. A title match alone
16
17
  never authorizes an edit.
18
+ - **`--distinct` records that each candidate was read.** Reissue the call listing every candidate you
19
+ read and judged separate; never list one you have not read.
17
20
  - **A candidate marked `(closed)` is a different answer.** The scan covers what closed recently as
18
21
  well as what is open, because the work most likely to be filed twice is the work that just finished.
19
22
  A closed candidate that covers the same work means **the work is already done** — so there is nothing
20
23
  to run. Verify it against the merged code, then take the exit in `issue-comments.md` → "When the work
21
24
  turns out to be already merged". A closed candidate that does *not* cover the work is noted in one
22
- line and the filing carries on.
25
+ line, named in `--distinct`, and the filing carries on.
23
26
  - **`none` is an answer.** The command reports no candidate rather than the closest miss.
24
27
  - **`Epic:` front-loads the placement.** Its recommendation is `epic:bundle`'s, which makes
25
28
  `add_to_epic` / `create_epic` Tier A and `ask` a stop, in exactly the reading `SKILL.md` → §2a's
26
29
  `into <target>` suffix would have given by hand. Where the user typed `into <target>`, that naming wins.
27
- - **`Epic: not asked` is not `Epic: none`.** The epic half decides from the issue numbers the summary
28
- names, so a title-only call gives it nothing. **Pass `--body` whenever the work follows an existing
29
- Issue** — one line citing `#N` is enough, and naming the epic itself (`part of epic #<E>`) is
30
- answered with that epic.
31
- - **It does not replace `epic:bundle`, which still runs after the filing.** This one answers about an
32
- Issue that does not exist yet, from a title; that one answers about an Issue that does. Both calls
33
- happen — the scout before the `issues` call, `epic:bundle` after it.
34
- - **Every filing route runs it, not only a `new` entry point, and `pnpm josh rule:guard` refuses a
35
- filing the run has not scouted** (`prompts/collaboration-workflow/rule-delivery.md`) — the trigger is
36
- the `gh api … issues` call, never which keyword started the run, so `SKILL.md` → §2d's prerequisite,
37
- §2i's observation and the review round cap's branch-2 filing all go through it.
38
- - **A `#N` entry point does not run it *for the Issue it was handed*.** `fullrun #N` / `halfrun #N` /
30
+ - **`Epic: not asked` is not `Epic: none`.** The epic half decides from the issue numbers the body
31
+ names. **Cite `#N` in the body whenever the work follows an existing Issue** — one line is enough,
32
+ and naming the epic itself (`part of epic #<E>`) is answered with that epic.
33
+ - **`epic:bundle` then runs on the new Issue, in the same call.** Act on its printed answer; a `⚠`
34
+ means rerun `pnpm josh epic:bundle <N>` — the Issue exists, so never refile.
35
+ - **Every filing route goes through it** — §2d's prerequisite, §2i's observation and the review round
36
+ cap's branch-2 filing alike; the guard refuses any other filing call
37
+ (`prompts/collaboration-workflow/rule-delivery.md`).
38
+ - **A `#N` entry point does not file *the Issue it was handed*.** `fullrun #N` / `halfrun #N` /
39
39
  `kickoff #N` are given an Issue that already exists. That says nothing about an Issue such a run goes
40
40
  on to file later, which the bullet above covers.
41
- - **The split path files each child through the same step.** The epic itself is not scouted: it is
42
- created over children that were, and `epic:bundle` places it afterwards.
41
+ - **The split path files each child through the same command.** The epic is created with
42
+ `pnpm josh epic` over children that were scanned.
43
43
 
44
- Full behavior, the thresholds and why the duplicate half compares titles rather than bodies:
45
- `docs/josh-commands.md` → "`josh issue:scout`".
44
+ Full behavior: `docs/josh-commands.md` → "`josh issue:file`" and "`josh issue:scout`".
@@ -44,16 +44,15 @@ split is found.
44
44
  - `kickoff new` or `kickoff new "<title>"`: No Issue exists yet. Steps: (0) **Scope assessment** per
45
45
  `split-assessment.md`. If multiple → the **multi-issue split path**; if single → the **single-issue
46
46
  path**. **Single-issue path**: (1) Derive an English title from the conversation, or use the provided
47
- title. **(1a) Run `pnpm josh issue:scout "<title>" [--body "<summary>"]` before creating the Issue** —
48
- a candidate that covers the same work stops the run rather than filing a second Issue (`SKILL.md` →
49
- §2e). (2) Create Issue: `gh api repos/{owner}/{repo}/issues -f title="<title>" -f 'labels[]=depth:<n>'
50
- -F body=@<body-file>` (body per `prompts/collaboration-workflow/issue-template.md`). Capture `<N>`. (3)
47
+ title. (2) Create Issue: `pnpm josh issue:file "<title>" --body-file <body-file> --depth <n>` (body
48
+ per `prompts/collaboration-workflow/issue-template.md`) — its duplicate scan runs first, and a
49
+ candidate that covers the same work stops the run rather than filing a second Issue (`SKILL.md` →
50
+ §2e). Capture `<N>`. (3)
51
51
  Post the plan in the session language, using the same body/comment logic as `kickoff #<N>`. (4) Send
52
52
  Telegram notification. (5) **Stop** — do not implement. **Multi-issue split path**: (1) For each
53
- independent deliverable, derive a focused English title, **run `pnpm josh issue:scout "<sub-title>"`
54
- on it** (`SKILL.md` → §2e), and create a separate Issue with the `route:split` label: `gh api
55
- repos/{owner}/{repo}/issues -f title="<sub-title>" -f 'labels[]=route:split' -f 'labels[]=depth:<n>'
56
- -F body=@<body-file>`. Capture each Issue number. **When the split is filed into a repository other than
53
+ independent deliverable, derive a focused English title and create a separate Issue with the
54
+ `route:split` label (its duplicate scan is read per `SKILL.md` → §2e): `pnpm josh issue:file
55
+ "<sub-title>" --body-file <body-file> --depth <n> --route split`. Capture each Issue number. **When the split is filed into a repository other than
57
56
  the one this session is running in**, every child body gets the `## Origin` backlink described in the
58
57
  cross-package rule the AI documents keep resident, the epic body carries the same link as prose or a
59
58
  plain bullet (never as a checkbox row, which would disable its auto-close), and the originating Issue
@@ -81,4 +80,4 @@ split is found.
81
80
  creation call. (3) Send Telegram notification listing all created issues. (4) Present the command
82
81
  `backlogrun #<E> --only`. (5) **Stop** — do not implement.
83
82
 
84
- Before filing, run `pnpm josh issue:lint <body-file>` and apply every label in its `labels:` answer at creation, following `prompts/collaboration-workflow/issue-template.md` for classification.
83
+ `pnpm josh issue:file` lints the body and applies the classification labels it declares, following `prompts/collaboration-workflow/issue-template.md` for classification (`docs/josh-commands.md` → `josh issue:file`).
@@ -20,17 +20,16 @@ on is dropped rather than filed.
20
20
 
21
21
  **The filing ceilings still apply.** Count this filing in the ten-Issue limit for the run. An
22
22
  observation is discretionary, so above 30 open Issues in the target repository, close one first or do
23
- not file (`prompts/collaboration-workflow/wip-cap.md`). Before the `gh api … issues` call, run
24
- `pnpm josh issue:scout "<title>"` (`issue-scout.md`). When it is the second filing of the run, run
23
+ not file (`prompts/collaboration-workflow/wip-cap.md`). File it with `pnpm josh issue:file`
24
+ (`issue-scout.md`), which lints the body against `prompts/collaboration-workflow/issue-template.md`,
25
+ applies the classification labels it declares, runs the duplicate scan, and runs `epic:bundle` on the
26
+ new Issue so it is offered by its epic; an `auto-ok` epic adds it to the backlog pool
27
+ (`backlogrun-steps.md` → "What one invocation approves"). When it is the second filing of the run, run
25
28
  `pnpm josh issue:fold` first; the guard refuses that filing without the fold
26
- (`split-assessment.md` → "The same two questions decide the filing-time fold"). After filing, run
27
- `pnpm josh epic:bundle <new>` so the Issue is offered by its epic; an `auto-ok` epic adds it to the
28
- backlog pool (`backlogrun-steps.md` → "What one invocation approves").
29
+ (`split-assessment.md` → "The same two questions decide the filing-time fold").
29
30
 
30
31
  The detail below is read at the filing decision, and the marker suite pins the rules here.
31
32
 
32
- Before filing an observation, run `pnpm josh issue:lint <body-file>` and apply every label in its `labels:` answer at creation; `prompts/collaboration-workflow/issue-template.md` is the single source. Keep the depth label.
33
-
34
33
  ### The depth test — a discretionary filing cites the product work it blocked
35
34
 
36
35
  **A run that has just spent an hour inside the workflow tooling files findings about the workflow
@@ -53,11 +52,11 @@ it — read off the subject rather than judged**:
53
52
  single source**, and a label description that paraphrased it would be a second copy of the rule.
54
53
  **Every filing route applies one**, this route and the other three of §2d's table alike: a `new`
55
54
  entry point, a `route:tier-a` prerequisite, a `route:interrupt`, a split child and a review round
56
- cap's branch-2 filing all pass through a `gh api … issues` call, and the depth label goes in it
57
- beside whatever `route:` label that call already carries.
55
+ cap's branch-2 filing all pass through a `pnpm josh issue:file` call, and the depth goes in it as
56
+ `--depth <n>` beside whatever `--route` that call already carries.
58
57
 
59
58
  ```bash
60
- gh api repos/{owner}/{repo}/issues -f title="<title>" -f 'labels[]=depth:1' -F body=@<body-file>
59
+ pnpm josh issue:file "<title>" --body-file <body-file> --depth 1
61
60
  gh api repos/{owner}/{repo}/issues/<N>/labels -f 'labels[]=depth:1' # an Issue already filed
62
61
  ```
63
62
 
@@ -25,16 +25,17 @@ stays countable by filing route afterwards. **This paragraph belongs to the prer
25
25
  the table** — the label means a filing the run is *blocked by*, so the observation row carries no
26
26
  `route:` label of its own (§2i):
27
27
 
28
- Before that call, run `pnpm josh issue:lint <body-file>` and apply every label in its `labels:` answer at creation; `prompts/collaboration-workflow/issue-template.md` is the single source. Keep `route:tier-a` and `depth`.
29
-
30
28
  ```bash
31
- gh api repos/{owner}/{repo}/issues -f title="<title>" -f 'labels[]=route:tier-a' -f 'labels[]=depth:<n>' -F body=@<body-file>
29
+ pnpm josh issue:file "<title>" --body-file <body-file> --depth <n> --route tier-a
32
30
  ```
33
31
 
32
+ The command lints the body against `prompts/collaboration-workflow/issue-template.md`, applies the
33
+ classification labels it declares, and runs the duplicate scan and `epic:bundle` itself
34
+ (`docs/josh-commands.md` → `josh issue:file`).
35
+
34
36
  Every "file the prerequisite" below means that labelled filing, and it always happens **first**: the
35
- steps after it name a number that does not exist until it is. **`pnpm josh issue:scout "<title>"` goes
36
- in front of that call, exactly as it does for a `new` entry** (§2e): a filing made mid-run is the one
37
- most likely to duplicate something.
37
+ steps after it name a number that does not exist until it is. **Its duplicate scan is read exactly as
38
+ it is for a `new` entry** (§2e): a filing made mid-run is the one most likely to duplicate something.
38
39
 
39
40
  **Each entry point's own branch stays in that entry's file:**
40
41
 
@@ -53,11 +53,11 @@ ceiling on what may be recorded. **File nothing when nothing passes** — a run
53
53
  improvement worth carrying files zero Issues, and that is what makes the "file → drain → file again"
54
54
  loop converge.
55
55
 
56
- **Exclude what is already filed or already done, through the existing scout** (`SKILL.md` → §2e). Run
57
- `pnpm josh issue:scout "<title>"` before each `gh api … issues` call: an **open** candidate covering the
58
- same work means do not file it, and a `(closed)` candidate covering it means the work is already merged.
59
- Neither exclusion is a new mechanism. After filing, `pnpm josh epic:bundle <new>` places each Issue, as
60
- after any filing.
56
+ **Exclude what is already filed or already done, through the existing scout** (`SKILL.md` → §2e). File
57
+ each with `pnpm josh issue:file`, which runs the scout before creating anything: an **open** candidate
58
+ covering the same work means do not file it, and a `(closed)` candidate covering it means the work is
59
+ already merged. Neither exclusion is a new mechanism. The same call runs `epic:bundle` on each new
60
+ Issue, as after any filing.
61
61
 
62
62
  ## `auto-ok`, and closing the step
63
63
 
@@ -165,8 +165,8 @@ again (joshuafolkken/kit#1525).
165
165
  - **The Issue's comments** — `pnpm josh rule:guard` refuses the `Bash` call that reads an Issue's
166
166
  body without them (`gh issue view <N>`, or a `GET` of a path ending `…/issues/<N>`) and hands over
167
167
  the reissue that carries them plus the rule for a comment that contradicts the body. It is the one
168
- row whose trigger `batch:guard` also considers, so it stands aside on that guard's turn and fires
169
- on the reissue. §2g is the procedure and stays here, because a session that runs no hooks still
168
+ row whose trigger `batch:guard` also considers, yet it refuses on that guard's turn too, since it
169
+ repeats until the comments are read. §2g is the procedure and stays here, because a session that runs no hooks still
170
170
  owes the read (`prompts/collaboration-workflow/rule-delivery.md`,
171
171
  `scripts/rules/delivered-rules.test.ts`).
172
172
  - **The prohibition on putting a body inside shell double quotes** — `pnpm josh rule:guard` refuses
@@ -31,7 +31,7 @@ same conjunction**: separability, and whether the whole clearly exceeds one gate
31
31
  `pnpm josh split:assess`, called not recomputed, and `separate` needs both halves exactly as `split`
32
32
  does. **There is no second criterion.** §2i's observation, the review round cap's branch 2 and §2d's
33
33
  prerequisite each route a second filing through it, delivered by `pnpm josh rule:guard` at the run's
34
- second `gh api … issues` call, never the first.
34
+ second `pnpm josh issue:file` call, never the first.
35
35
 
36
36
  ## Why the default is not to split
37
37
 
@@ -88,8 +88,9 @@ the whole point of one definition is that where the split was noticed cannot cha
88
88
  The epic is the non-closing home for the split rationale. A comment on the first child is buried the
89
89
  moment that child merges and closes.
90
90
 
91
- **Each split child is filed with the `route:split` label**, so the backlog's composition stays
92
- countable by filing route rather than by grepping issue bodies.
91
+ **Each split child is filed with the `route:split` label** —
92
+ `pnpm josh issue:file "<sub-title>" --body-file <body-file> --depth <n> --route split` — so the
93
+ backlog's composition stays countable by filing route rather than by grepping issue bodies.
93
94
 
94
95
  ## Promote, or create a new epic
95
96
 
@@ -37,12 +37,13 @@ backlogrun joshuafolkken/kit#858 --only
37
37
  explicit instruction that rule requires. **Send a `confirmation` Telegram and stop** — nothing has
38
38
  been produced yet, so there is no finding to record and no draft to prepare.
39
39
  - **No prefix leaves the behavior exactly as it was** — the target is the session's repository.
40
- - **`kickoff` needs no checkout**: name the target repository in the path of every `gh api` call and
41
- never clone. The one exception is the split path's epic, since `pnpm josh epic` only writes the
42
- repository it runs in — run it in that repository's checkout, or fall back to `gh api
43
- repos/<owner/repo>/labels …` followed by `gh api repos/<owner/repo>/issues -f title="<epic-title>" -f
44
- 'labels[]=epic' -F body=@<body-file>`, and report that `epic:check` could not be run. The promote arm has
45
- no such fallback: with no checkout there, file the children and stop.
40
+ - **`kickoff` needs no checkout**: name the target repository with `--repo <owner/repo>` on every
41
+ `pnpm josh issue:file` call and in the path of every `gh api` call, and never clone. The one exception
42
+ is the split path's epic, since `pnpm josh epic` only writes the repository it runs in — run it in
43
+ that repository's checkout. With no checkout there, file the children, report that the epic could
44
+ not be created, and stop — a hand-built `gh api …/issues` filing of the epic is refused by the
45
+ `direct-filing` guard, and `pnpm josh issue:file` lints an epic body against the Issue template. The
46
+ promote arm stops the same way.
46
47
  - **The implementing entries require a checkout and never create one — when the target is another
47
48
  repository.** A prefix naming the session's own repository changes nothing (`fullrun kit#412` in the
48
49
  kit checkout behaves exactly as `fullrun #412`). Otherwise resolve the checkout from `pnpm josh
@@ -9,10 +9,10 @@ import {
9
9
  load_environment_file,
10
10
  notice_refusal_path,
11
11
  refusal_path
12
- } from "./chunk-NXL3SBXY.js";
13
- import "./chunk-2K52BRWV.js";
14
- import "./chunk-KQG4776P.js";
15
- import "./chunk-ZPLXLJ7O.js";
12
+ } from "./chunk-P3UX7SFN.js";
13
+ import "./chunk-ASUZGZFT.js";
14
+ import "./chunk-APVOACVT.js";
15
+ import "./chunk-47SPMGOD.js";
16
16
  import "./chunk-WPALEIRX.js";
17
17
  import "./chunk-RKUAD3I6.js";
18
18
  export {
@@ -290,6 +290,16 @@ var ISSUE_COMMANDS = {
290
290
  description: "Post one comment to an issue from a file, so no shell expands the body",
291
291
  category: "AI tools",
292
292
  reference: ["<issue> --body <text> | --body-file <path>", "automation", ["network"]]
293
+ },
294
+ "issue:file": {
295
+ script: "scripts/issue/issue-file-cli.ts",
296
+ description: "File an Issue with every filing step: lint, Origin, duplicate scout, labels, then epic:bundle",
297
+ category: "AI tools",
298
+ reference: [
299
+ "<title> --body-file <path> --depth <0|1|2> [--route <route>] [--label <name>] [--repo <owner/repo>] [--distinct <N,\u2026>]",
300
+ "automation",
301
+ ["network"]
302
+ ]
293
303
  }
294
304
  };
295
305
 
@@ -1068,7 +1078,11 @@ var PROJECT_COMMANDS = {
1068
1078
  script: "scripts/propagate/propagate.ts",
1069
1079
  description: "Carry the published release into every consumer repository next to this one",
1070
1080
  category: "Project",
1071
- reference: ["[--dry-run] [--skip-publish-wait]", "maintainer", ["files", "network"]]
1081
+ reference: [
1082
+ "[--dry-run] [--skip-publish-wait] [--target <repo>]",
1083
+ "maintainer",
1084
+ ["files", "network"]
1085
+ ]
1072
1086
  },
1073
1087
  adopt: {
1074
1088
  script: "scripts/adopt/adopt.ts",
@@ -1306,6 +1320,7 @@ var ALIASES = {
1306
1320
  ird: "issue:read",
1307
1321
  ist: "issue:state",
1308
1322
  isc: "issue:scout",
1323
+ ifl: "issue:file",
1309
1324
  isf: "issue:fold",
1310
1325
  isfe: "issue:fold-existing",
1311
1326
  dfr: "defect:rate",
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  investigation_reads
3
- } from "./chunk-F6OM6SIG.js";
3
+ } from "./chunk-RFPHKU7C.js";
4
4
  import {
5
5
  lane_guard_policy
6
- } from "./chunk-2K52BRWV.js";
6
+ } from "./chunk-ASUZGZFT.js";
7
7
  import {
8
8
  hook_decision
9
- } from "./chunk-KQG4776P.js";
9
+ } from "./chunk-APVOACVT.js";
10
10
 
11
11
  // scripts/delegation/investigation-guard.ts
12
12
  import { text } from "node:stream/consumers";
@@ -3,7 +3,7 @@ import {
3
3
  stamp_file,
4
4
  time_density_hook,
5
5
  time_hook_transcript
6
- } from "./chunk-ZPLXLJ7O.js";
6
+ } from "./chunk-47SPMGOD.js";
7
7
  import {
8
8
  josh_environment_file
9
9
  } from "./chunk-WPALEIRX.js";
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  lane_child_marker
3
- } from "./chunk-KQG4776P.js";
3
+ } from "./chunk-APVOACVT.js";
4
4
  import {
5
5
  time_bundle_call,
6
6
  time_format,
7
7
  time_round_trips,
8
8
  time_spans,
9
9
  time_transcript_line
10
- } from "./chunk-ZPLXLJ7O.js";
10
+ } from "./chunk-47SPMGOD.js";
11
11
 
12
12
  // scripts/lane/lane-guard-policy.ts
13
13
  var DEFAULT_MODE = "refuse";
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  ESLINT_EDIT_CACHE_FLAGS,
7
7
  time_density_hook
8
- } from "./chunk-ZPLXLJ7O.js";
8
+ } from "./chunk-47SPMGOD.js";
9
9
 
10
10
  // scripts/hooks/format-edited-file.ts
11
11
  import { existsSync as existsSync2 } from "node:fs";