jackherd 1.6.0 → 1.7.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 (152) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/INSTALL.md +176 -0
  3. package/README.md +260 -315
  4. package/assets/branding/README.md +7 -3
  5. package/assets/branding/jackherd-logo-dark-1024.png +0 -0
  6. package/assets/branding/jackherd-logo-dark-512.png +0 -0
  7. package/assets/branding/jackherd-logo-dark.svg +1 -1
  8. package/assets/icons/bark-dark.svg +1 -0
  9. package/assets/icons/bark.svg +1 -0
  10. package/assets/icons/bowl-dark.svg +1 -0
  11. package/assets/icons/bowl.svg +1 -0
  12. package/assets/icons/decide-dark.svg +1 -0
  13. package/assets/icons/decide.svg +1 -0
  14. package/assets/icons/ear-dark.svg +1 -0
  15. package/assets/icons/ear.svg +1 -0
  16. package/assets/icons/lanes-dark.svg +1 -0
  17. package/assets/icons/lanes.svg +1 -0
  18. package/assets/icons/plan-dark.svg +1 -0
  19. package/assets/icons/plan.svg +1 -0
  20. package/assets/icons/space.svg +1 -0
  21. package/dist/{chunk-QJSXHHQ3.js → chunk-OBUWTQ6Z.js} +25 -0
  22. package/dist/config.d.ts +14 -3
  23. package/dist/config.js +111 -10
  24. package/dist/plan-format.d.ts +180 -77
  25. package/dist/plan-format.js +292 -93
  26. package/docs/lanes-dark.svg +50 -0
  27. package/docs/lanes.svg +50 -1
  28. package/docs/skills-dark.svg +65 -0
  29. package/docs/skills.svg +65 -1
  30. package/docs/workflow-dark.svg +138 -0
  31. package/docs/workflow.svg +135 -169
  32. package/herdr-plugin/herdr-plugin.toml +6 -6
  33. package/herdr-plugin/open-plans.ts +1 -1
  34. package/herdr-plugin/restore-plans.ts +7 -7
  35. package/install.sh +1 -1
  36. package/kit/hooks/hooks/approval-gate/decision.ts +61 -0
  37. package/kit/hooks/hooks/approval-gate/herdr-panes.ts +24 -0
  38. package/kit/hooks/hooks/approval-gate/index.ts +69 -0
  39. package/kit/hooks/hooks/approval-gate/lane.ts +14 -0
  40. package/kit/hooks/hooks/approval-gate/request.ts +111 -0
  41. package/kit/hooks/hooks/approval-gate/run.ts +94 -0
  42. package/kit/hooks/hooks/approval-gate/settings.ts +26 -0
  43. package/kit/hooks/hooks/approval-gate/store.ts +70 -0
  44. package/kit/hooks/hooks/approval-gate/transcripts.ts +40 -0
  45. package/kit/hooks/hooks/merge-guard/approval.ts +11 -74
  46. package/kit/hooks/hooks/merge-guard/run.ts +2 -1
  47. package/kit/hooks/hooks/model-gate/agent-definition.ts +13 -0
  48. package/kit/hooks/hooks/model-gate/index.ts +58 -0
  49. package/kit/hooks/hooks/model-gate/run.ts +63 -0
  50. package/kit/hooks/hooks/model-log/index.ts +60 -0
  51. package/kit/hooks/hooks/model-log/run.ts +57 -0
  52. package/kit/hooks/hooks/model-log/store.ts +40 -0
  53. package/kit/hooks/hooks/model-log/transcript.ts +37 -0
  54. package/kit/hooks/hooks/shared/checkout.ts +22 -0
  55. package/kit/hooks/hooks/shared/command.ts +6 -0
  56. package/kit/hooks/hooks/shared/config.ts +21 -0
  57. package/kit/hooks/hooks/shared/dialog-answer.ts +5 -0
  58. package/kit/hooks/hooks/shared/dialog-answers.ts +74 -0
  59. package/kit/hooks/hooks/shared/files.ts +19 -0
  60. package/kit/hooks/hooks/shared/fresh.ts +4 -0
  61. package/kit/hooks/hooks/shared/json.ts +4 -0
  62. package/kit/hooks/hooks/shared/model-family.ts +48 -0
  63. package/kit/hooks/hooks/shared/plan-model-table.ts +41 -0
  64. package/kit/hooks/hooks/shared/private-directory.ts +29 -0
  65. package/kit/hooks/hooks/shared/repository-directory.ts +14 -0
  66. package/kit/hooks/hooks/shared/subagent-phase.ts +99 -0
  67. package/kit/hooks/hooks.json +25 -0
  68. package/kit/workflow/skills/follow/SKILL.md +4 -3
  69. package/kit/workflow/skills/implement/SKILL.md +6 -6
  70. package/kit/workflow/skills/orchestrate/SKILL.md +113 -30
  71. package/kit/workflow/skills/plan/SKILL.md +5 -5
  72. package/kit/workflow/skills/start/SKILL.md +2 -2
  73. package/package.json +4 -1
  74. package/schemas/jackherd.schema.json +43 -5
  75. package/src/check/command.ts +31 -4
  76. package/src/check/deferral-arrows.ts +1 -1
  77. package/src/check/parallel-report.ts +23 -0
  78. package/src/check/plan-structure-check.ts +120 -53
  79. package/src/cli.ts +8 -2
  80. package/src/config/nested-quantifier.ts +73 -0
  81. package/src/config/repository-directory.ts +11 -0
  82. package/src/config/schema.ts +63 -8
  83. package/src/plan-format/board-prose.ts +36 -0
  84. package/src/plan-format/dependencies.ts +227 -0
  85. package/src/plan-format/documentation-gate.ts +16 -0
  86. package/src/plan-format/index.ts +23 -1
  87. package/src/plan-format/lanes.ts +35 -1
  88. package/src/plan-format/model-column.ts +52 -0
  89. package/src/plan-format/phases.ts +16 -1
  90. package/src/plan-format/plan-structure.ts +10 -28
  91. package/src/plan-format/progress.ts +7 -29
  92. package/src/plans/command.ts +3 -3
  93. package/src/plans/current-phase.ts +71 -0
  94. package/src/plans/ensure-panes.ts +2 -2
  95. package/src/plans/herd-command.ts +4 -0
  96. package/src/plans/lane-discovery.ts +14 -2
  97. package/src/plans/lane-tickets.ts +69 -0
  98. package/src/plans/layout.ts +182 -88
  99. package/src/plans/live.ts +5 -1
  100. package/src/plans/phase-models-read.ts +37 -0
  101. package/src/plans/phase-models.ts +70 -0
  102. package/src/plans/plan-panes.ts +8 -7
  103. package/src/plans/pull-requests.ts +78 -4
  104. package/src/plans/selection.ts +1 -40
  105. package/src/plans/settings.ts +9 -3
  106. package/src/plans/shown-with-more.ts +5 -0
  107. package/src/plans/snapshot.ts +82 -8
  108. package/src/plans/sprint-html.ts +2 -2
  109. package/src/plans/supervisor.ts +5 -4
  110. package/src/plans/symbols.ts +9 -6
  111. package/src/plans/texts.ts +30 -13
  112. package/src/plans/view.ts +1 -0
  113. package/src/sync/herdr-plugin.ts +1 -1
  114. package/src/sync/next-steps.ts +1 -1
  115. package/src/sync/render.ts +2 -1
  116. package/src/sync/setup-questions.ts +2 -2
  117. package/src/terminal/text.ts +4 -0
  118. package/src/terminal/types.ts +1 -1
  119. package/src/vocabulary/index.ts +39 -0
  120. package/src/watch/approvals.ts +96 -0
  121. package/src/watch/command.ts +154 -50
  122. package/src/watch/failed-tests.ts +52 -0
  123. package/src/watch/failure-read.ts +56 -0
  124. package/src/watch/failures.ts +107 -0
  125. package/src/watch/feedback-item.ts +21 -0
  126. package/src/watch/feedback-read.ts +2 -1
  127. package/src/watch/feedback.ts +37 -28
  128. package/src/watch/gh-process.ts +53 -0
  129. package/src/watch/gh.ts +10 -20
  130. package/src/watch/heartbeat-progress.ts +1 -1
  131. package/src/watch/lane-model.ts +54 -0
  132. package/src/watch/lane-parallel.ts +46 -0
  133. package/src/watch/lane-progress.ts +28 -4
  134. package/src/watch/lane-report.ts +62 -9
  135. package/src/watch/lane-sources.ts +1 -1
  136. package/src/watch/no-finding.ts +47 -0
  137. package/src/watch/plan-badges-read.ts +19 -7
  138. package/src/watch/plan-badges.ts +59 -7
  139. package/src/watch/plan-views.ts +5 -5
  140. package/src/watch/previews.ts +3 -9
  141. package/src/watch/pull-requests.ts +12 -2
  142. package/src/watch/recorded-reads.ts +25 -0
  143. package/src/watch/source-fields.ts +4 -0
  144. package/src/watch/source-tickets.ts +99 -0
  145. package/src/watch/sources.ts +62 -15
  146. package/src/watch/texts.ts +21 -1
  147. package/src/watch/watch-defaults.ts +8 -0
  148. package/src/watch/watch-events.ts +64 -4
  149. package/src/watch/watcher-lock.ts +1 -1
  150. package/src/watch/workflow-runs.ts +5 -7
  151. package/docs/lanes.mmd +0 -9
  152. package/docs/skills.mmd +0 -10
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  <p>
2
2
  <picture>
3
- <source media="(prefers-color-scheme: dark)" srcset="https://unpkg.com/jackherd@1.0.0/assets/branding/jackherd-logo-dark.svg">
4
- <img alt="jackherd: a black and white Shih Tzu in a turquoise bandana, three lanes running from him to three agent nodes" src="https://unpkg.com/jackherd@1.0.0/assets/branding/jackherd-logo.svg" width="340">
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://unpkg.com/jackherd@1.7.0/assets/branding/jackherd-logo-dark.svg">
4
+ <img alt="jackherd: a black and white Shih Tzu in a turquoise bandana, three lanes running from him to three agent nodes" src="https://unpkg.com/jackherd@1.7.0/assets/branding/jackherd-logo.svg" width="340">
5
5
  </picture>
6
6
  <br>
7
7
  </p>
@@ -11,25 +11,32 @@
11
11
  **Plan. Delegate. Ship.** Your agents do the work. Jack keeps them together.
12
12
 
13
13
  Large tasks outgrow one chat, the context fills up, parallel sessions edit the same files, and
14
- you lose track of who waits on you. Jack:
14
+ you lose track of who waits on you. Jack:<br><img width="1" height="8" alt="" src="https://unpkg.com/jackherd@1.7.0/assets/icons/space.svg">
15
15
 
16
- - 📄 **Keeps the plan in your repository.** Your agent writes it as Markdown, phases with a model each, and ticks it off as it builds.
17
- - ⚡ **Herds the lanes.** Each lane works in its own git worktree, so sessions never share a checkout.
18
- - ❓ **Brings you only the decisions.** A coordinating session answers what the plan settles, vets review feedback on its pull requests, asks you the rest as a choice, and asks you before every commit and push.
19
- - 💬 **Barks when something moves.** One live view of every lane: state, progress, pull request, checks, with the preview link and new feedback as badges; `/follow` brings in tickets, issues and status pages outside GitHub.
20
- - 🧠 **Watches the context.** It measures each agent session's fill and, before it is full, offers a fresh chat that takes over the state.
16
+ <p><picture><source media="(prefers-color-scheme: dark)" srcset="https://unpkg.com/jackherd@1.7.0/assets/icons/plan-dark.svg"><img align="left" width="28" height="48" alt="" src="https://unpkg.com/jackherd@1.7.0/assets/icons/plan.svg"></picture><b>Keeps the plan in your repository.</b><br>Your agent writes it as Markdown, phases with a model each, and ticks it off as it builds.<br clear="left"></p>
21
17
 
22
- Built for Claude Code today; other coding agents are planned.
18
+ <p><picture><source media="(prefers-color-scheme: dark)" srcset="https://unpkg.com/jackherd@1.7.0/assets/icons/lanes-dark.svg"><img align="left" width="28" height="48" alt="" src="https://unpkg.com/jackherd@1.7.0/assets/icons/lanes.svg"></picture><b>Herds the lanes.</b><br>Each lane works in its own git worktree, so sessions never share a checkout.<br clear="left"></p>
23
19
 
24
- jackherd runs its lanes and plan view in [herdr](https://herdr.dev).
20
+ <p><picture><source media="(prefers-color-scheme: dark)" srcset="https://unpkg.com/jackherd@1.7.0/assets/icons/decide-dark.svg"><img align="left" width="28" height="72" alt="" src="https://unpkg.com/jackherd@1.7.0/assets/icons/decide.svg"></picture><b>Brings you only the decisions.</b><br>A coordinating session answers what the plan settles, vets review feedback on its pull requests, asks you the rest as a choice, and asks you before every commit, push and merge.<br clear="left"></p>
25
21
 
26
- <img src="https://unpkg.com/jackherd@1.0.0/docs/workflow.svg" width="720" alt="jackherd in herdr: a coordinator and its lanes, a blocked lane's question answered as a choice, and the plan view beside them.">
22
+ <p><picture><source media="(prefers-color-scheme: dark)" srcset="https://unpkg.com/jackherd@1.7.0/assets/icons/bark-dark.svg"><img align="left" width="28" height="72" alt="" src="https://unpkg.com/jackherd@1.7.0/assets/icons/bark.svg"></picture><b>Barks when something moves.</b><br>One live view of every lane: state, progress, pull request, checks, with the preview link and new feedback as badges.<br clear="left"></p>
27
23
 
28
- <sub>Schematic of one herdr window; the plan view pane is drawn by jackherd itself from example data.</sub>
24
+ <p><picture><source media="(prefers-color-scheme: dark)" srcset="https://unpkg.com/jackherd@1.7.0/assets/icons/ear-dark.svg"><img align="left" width="28" height="72" alt="" src="https://unpkg.com/jackherd@1.7.0/assets/icons/ear.svg"></picture><b>Keeps an ear on what lives outside GitHub.</b><br><code>/jh-follow PROJ-123</code>, and Jack listens to the ticket, the issue or the status page; when someone answers there, he barks.<br clear="left"></p>
29
25
 
30
- ## Quickstart
26
+ <p><picture><source media="(prefers-color-scheme: dark)" srcset="https://unpkg.com/jackherd@1.7.0/assets/icons/bowl-dark.svg"><img align="left" width="28" height="72" alt="" src="https://unpkg.com/jackherd@1.7.0/assets/icons/bowl.svg"></picture><b>Watches the context.</b><br>It measures each agent session's fill and, before it is full, offers a fresh chat that takes over the state.<br clear="left"></p>
27
+
28
+ Claude Code writes the code. jackherd is the skills, hooks and CLI around it that plan the work, coordinate the sessions and carry decisions, reviews and context from one chat to the next. It brings no platform of its own: plans, boards and their decisions are Markdown in your repository and go through pull requests like code, so your team reviews them where it reviews code. With a project install, `jh init` gives everyone who clones the repository the same skills and hooks. [herdr](https://herdr.dev) is the terminal that holds the parallel sessions: without it, planning, building and reviews work as before; parallel lanes need it. Built for Claude Code today; other coding agents are planned.
29
+
30
+ You stay in the loop: what the plan settles, the coordinator answers itself and tells you in one line; every other decision waits for you, and so do commits, pushes and merges: one approval per pull request, and the coordinator merges only where you allowed it, by picking self-merge for that pull request or in your project's rules ([what waits for you](#user-content-what-happens-on-its-own-and-what-waits-for-you)).
31
+
32
+ <picture>
33
+ <source media="(prefers-color-scheme: dark)" srcset="https://unpkg.com/jackherd@1.7.0/docs/workflow-dark.svg">
34
+ <img src="https://unpkg.com/jackherd@1.7.0/docs/workflow.svg" width="720" alt="jackherd in herdr, in five steps: a lane works, hits an open question, the coordinator asks you as a choice, you pick, and the lane works on while the herd counts its progress.">
35
+ </picture>
36
+
37
+ <sub>Schematic of one herdr window; the herd pane is drawn by jackherd itself from example data.</sub>
31
38
 
32
- Plans and boards are Markdown files in your repository, nothing is hidden. [herdr](https://herdr.dev), a terminal multiplexer for AI coding agents, is needed only for parallel lanes.
39
+ ## Quickstart
33
40
 
34
41
  1. **Install** (Linux and macOS):
35
42
 
@@ -37,7 +44,13 @@ Plans and boards are Markdown files in your repository, nothing is hidden. [herd
37
44
  curl -fsSL https://unpkg.com/jackherd/install.sh | sh
38
45
  ```
39
46
 
40
- It installs jackherd and asks a few setup questions, including whether to use herdr (and offers to install it if it is missing); your repositories stay untouched. → [What the installer changes](#user-content-the-installer)
47
+ It installs jackherd and asks a few setup questions, including whether to use herdr (and offers to install it if it is missing); your repositories stay untouched. → [INSTALL.md: what the installer changes, project or global, updating](https://unpkg.com/jackherd/INSTALL.md)
48
+
49
+ Already in a coding agent? Paste this instead:
50
+
51
+ ```text
52
+ Install jackherd by following https://unpkg.com/jackherd/INSTALL.md. Ask me the setup questions it lists; herdr is optional.
53
+ ```
41
54
  2. **Start Claude Code in a repository and run:**
42
55
 
43
56
  ```text
@@ -68,15 +81,15 @@ Plans and boards are Markdown files in your repository, nothing is hidden. [herd
68
81
  ```
69
82
 
70
83
  It builds one phase; ask for several phases and the independent ones run in parallel as subagents in the same checkout.
71
- 5. **Follow progress.** `/jh-orchestrate` opens the plan view in a herdr pane beside the coordinator and one beside each lane. Anywhere else, once a board exists:
84
+ 5. **Follow progress.** `/jh-orchestrate` opens the herd, a live view of the board's lanes, in a herdr pane beside the coordinator and one beside each lane. Anywhere else, once a board exists:
72
85
 
73
86
  ```bash
74
- jh plans
87
+ jh herd
75
88
  ```
76
89
 
77
- With herdr, the plan view also shows each session's context fill. Once a lane or the coordinator reaches its threshold, it offers you a fresh chat at a quiet moment and hands its state over in a file ([Hand-over to a fresh chat](#user-content-hand-over-to-a-fresh-chat)).
90
+ With herdr, the herd also shows each session's context fill. Once a lane or the coordinator reaches its threshold, jackherd offers you a fresh chat at a quiet moment and hands its state over in a file ([Hand-over to a fresh chat](#user-content-hand-over-to-a-fresh-chat)).
78
91
 
79
- → [Orchestration](#user-content-orchestration-with-herdr), [Plan view](#user-content-plan-view-and-context)
92
+ → [Orchestration](#user-content-orchestration-with-herdr), [Herd](#user-content-herd-and-context)
80
93
 
81
94
  Installing by hand (the CLI runs on Bun 1.3+), with Bun:
82
95
 
@@ -98,20 +111,23 @@ jh init --global
98
111
 
99
112
  ## With and without herdr
100
113
 
101
- Planning, building and reviewing work without herdr. herdr adds parallel lanes and the agents' state in the plan view. The table names the skills without prefix; with the global install they start with `jh-` (`/jh-plan`).
114
+ Planning, building and reviewing work without herdr. herdr adds parallel lanes and the agents' state in the herd.
102
115
 
103
116
  | | Without herdr | With herdr |
104
117
  | --- | --- | --- |
105
- | `/grill`, `/plan`, `/implement`, `/pre-commit` and the review skills | yes | yes |
118
+ | `/jh-grill`, `/jh-plan`, `/jh-implement`, `/jh-pre-commit` and the review skills | yes | yes |
106
119
  | Independent phases in parallel | as subagents in one checkout | as lanes, one worktree and session each |
107
- | `/orchestrate` (the coordinator) | – | yes |
108
- | `jh plans` | board and plan progress | plus the lanes' state, pull requests and checks, context fill |
120
+ | `/jh-orchestrate` (the coordinator) | – | yes |
121
+ | `jh herd` | board and plan progress | plus the lanes' state, pull requests and checks, context fill |
122
+ | `/jh-follow` (tickets, issues, status pages) | set up a source and dry-run it | the watcher reports changes to the coordinator; tickets show as badges in the herd |
109
123
 
110
- Pull requests and checks in the plan view need `gh`.
124
+ Pull requests and checks in the herd need `gh`.
111
125
 
112
126
  ## Global or per project
113
127
 
114
- The global install prefixes every skill with `jh-`, leaves repositories alone and keeps its config in `~/.jackherd/`. To share the kit with your team instead, run `bunx jackherd init` in the repository. Skills then land in `.claude/` without prefix (`/plan`), with the kit's hooks, and `jh sync` updates them without overwriting your edits; the project's config lives in `.jackherd/`. → [Installation](#user-content-installation-and-updates)
128
+ The global install prefixes every skill with `jh-`, leaves repositories alone and keeps its config in `~/.jackherd/`; it brings no hooks, so the commit, push and merge approvals rest on the skills alone.
129
+
130
+ To share the kit with your team instead, run `jh init` in the repository. Skills, rules and the kit's hooks (the merge guard among them) then land in `.claude/`, the same for everyone who clones it, and `jh sync` updates them without overwriting your edits (a changed file gets the new version beside it as `<file>.kit-new`); the project's config lives in `.jackherd/`. In a project install the skills drop the prefix by default: `/plan` instead of `/jh-plan`. → [Installation](https://unpkg.com/jackherd/INSTALL.md)
115
131
 
116
132
  ## Documentation
117
133
 
@@ -122,174 +138,7 @@ Each section opens on a click; a link into one opens it.
122
138
 
123
139
  ### Installation and updates
124
140
 
125
- - [Requirements](#user-content-requirements)
126
- - [The installer](#user-content-the-installer)
127
- - [Setup questions](#user-content-setup-questions)
128
- - [Project or global](#user-content-project-or-global)
129
- - [Project install](#user-content-project-install)
130
- - [Global install](#user-content-global-install)
131
- - [Detected per repository](#user-content-detected-per-repository)
132
- - [Updating](#user-content-updating)
133
- - [Keeping the global kit current](#user-content-keeping-the-global-kit-current)
134
- - [Removing the global install](#user-content-removing-the-global-install)
135
-
136
- #### Requirements
137
-
138
- - [Bun](https://bun.sh) 1.3 or later, and Claude Code.
139
- - Optional: [herdr](https://herdr.dev) for parallel lanes (`/orchestrate`, the watcher, agent states and context fill in the plan view), and `gh` for pull requests and checks in the plan view and the watcher.
140
-
141
- #### The installer
142
-
143
- ```bash
144
- curl -fsSL https://unpkg.com/jackherd/install.sh | sh
145
- ```
146
-
147
- To read the script before it runs, open [install.sh](https://unpkg.com/jackherd/install.sh), the file the command above runs, or download it with `curl -fsSL <that address> -o install.sh` and start it with `sh install.sh` after reading. The address without a version leads to the newest release; for a fixed one use `https://unpkg.com/jackherd@<version>/install.sh`.
148
-
149
- For Linux and macOS, without root: the script refuses to run as root. It announces each step on one line before it runs:
150
-
151
- 1. If no Bun is found (on the `PATH` or in `~/.bun/bin`), it runs Bun's official installer from `bun.com/install`, which needs `curl`, `unzip` and `bash`; a Bun older than 1.3 stops the script with a hint to run `bun upgrade`. That installer puts Bun into `~/.bun` and names the shell file it changed; the script itself edits none.
152
- 2. `bun add -g --ignore-scripts jackherd@<version>`, the version the script ships with. `curl … | JACKHERD_VERSION=1.2.3 sh` picks another release.
153
- 3. `jh init --global` on your terminal, so the [setup questions](#user-content-setup-questions) work under `curl … | sh`. Without a terminal it runs `init --global --yes` and says so.
154
-
155
- The same by hand: `bun add -g jackherd` or `npm install -g jackherd`, then `jh init --global`. The CLI runs on Bun in both cases.
156
-
157
- #### Setup questions
158
-
159
- When `init` creates a new config, it asks:
160
-
161
- - the language the skills answer you in, and the language plans and boards are written in (English or German; it sets their headings),
162
- - whether to use herdr as the terminal adapter. If herdr is missing on Linux or macOS, it first offers herdr's official installer, shows the command and runs it only after a yes.
163
-
164
- `--yes`, `--no` or a run without a terminal ask nothing and install nothing: replies and plans in English, herdr as the adapter only if herdr is found, and one line names what was taken. An existing config is never changed by `init`; edit `responseLanguage`, `planLanguage` and `terminal.adapter` in it, then run `sync`. At the end `init` prints the next steps: the start skill, `/plan` and what herdr or `gh` still need.
165
-
166
- #### Project or global
167
-
168
- | | Project install | Global install |
169
- | --- | --- | --- |
170
- | Use it when | the team shares the kit through the repository | the repository must stay untouched, not even untracked files |
171
- | Lives in | the project's `.claude/` | `~/.claude/` |
172
- | Skill names | `/plan`, `/implement`, `/orchestrate`, … | `/jh-plan`, `/jh-implement`, `/jh-orchestrate`, … |
173
- | Hooks | `git-guard`, `watch-guard`, `merge-guard`, `ask-hint`, `format-on-edit` | none; `init --global` offers only a `SessionStart` update notice |
174
- | Config | `.jackherd/config.json` | `~/.jackherd/config.json`, used where a repository has none |
175
- | Update | `jh sync` | `jh update` |
176
-
177
- A project config always wins over the global one. Both can exist side by side: in a project with its own kit, the project's skills are the ones in use.
178
-
179
- #### Project install
180
-
181
- ```bash
182
- bunx jackherd init # writes the kit into .claude/ and creates .jackherd/config.json
183
- bunx jackherd sync # later: updates the kit files
184
- ```
185
-
186
- `init` writes what it [detected](#user-content-detected-per-repository) into the new config, so the project sees it. It asks whether to enter the [status line](#user-content-status-line) in `.claude/settings.json`; `--yes` or `--no` answer every question without asking.
187
-
188
- **Name clashes.** A project that already has a skill or agent of a kit name (`implement`, `plan`, …): `init` names the clash and offers the prefix `jh-`, so the kit's copies sit beside yours and call each other, not yours. Any project can set `skillPrefix` in `.jackherd/config.json`; `sync` then renames, and removes the unprefixed kit files you never edited, with the directories they leave empty. A directory that holds a file of yours stays, and `sync` names it.
189
-
190
- **Your edits survive.** `sync` leaves files you have edited alone. When the kit changed one of them too, its version lands beside yours as `<file>.kit-new`: merge it, or take the kit version with `sync --accept <path>`. A kit file you deleted stays deleted. Project-specific additions go into `.claude/project/<skill>.md` (read first by the skill of that name) or a rule beside `.claude/rules/kit/`, so the kit files stay updatable.
191
-
192
- **herdr plugin.** Run inside herdr (`HERDR_ENV=1`), `init` and `sync` link the kit's herdr plugin when herdr does not list `crossdelta.jackherd` yet, and link it again when herdr's link points at another package or herdr cannot read its manifest (a deleted checkout); one line names the old and the new path. An installed package (global, `bunx`, a project's dependency) replaces only a link herdr cannot read, so a checkout that develops the kit keeps its link across `jh update`. From a lane's worktree they never link, since that path goes away with the lane; a broken link is named there instead. It adds a plans pane, an action that opens it, and the startup hook that brings back the plans views. If herdr refuses the link, the command prints herdr's message and carries on. The link belongs to herdr, not to the project; `herdr plugin unlink crossdelta.jackherd` removes it.
193
-
194
- #### Global install
195
-
196
- On a new machine these two commands are the whole setup:
197
-
198
- ```bash
199
- bun add -g jackherd
200
- jh init --global # writes the kit into ~/.claude, creates ~/.jackherd/config.json, asks about the hook
201
- ```
202
-
203
- `init --global` asks once whether to add a `SessionStart` hook that [keeps the global kit current](#user-content-keeping-the-global-kit-current), and whether to enter the status line; `--yes` or `--no` answer without asking. Nothing in the config needs editing: each repository's package manager and base branch are [detected](#user-content-detected-per-repository) where the kit runs. Run `jh sync --global` again after editing the config.
204
-
205
- **Why the prefix.** Claude Code lets a personal skill in `~/.claude/skills` win over a project skill of the same name, so a global install renames everything with `skillPrefix` (`init --global` sets `jh-`; `sync --global` refuses to run without one): `/jh-implement`, `/jh-pre-commit`, the agent `jh-spec-review`, with every reference inside the files renamed to match. Each description starts with `Global jackherd copy. In a project that has its own implement skill, use that one instead.`, so in a project with its own kit the project's skills stay the ones in use.
206
-
207
- **What lands where:** `~/.claude/skills/jh-*/` and `~/.claude/agents/jh-*.md`, which Claude Code reads, and under `~/.jackherd/` the config, the lock, the rules in `rules/` (where Claude Code does not load them in every project; the skills read them when they need them) and the status line as `statusline.sh`. Hooks are not installed globally, and `sync --global` never reads or writes `~/.claude/settings.json`; only `init --global` does, after asking. Other files in `~/.claude` are left alone; a file of your own at a kit path becomes a conflict with a `.kit-new` beside it, as in a project.
208
-
209
- `check`, `plans`, `context` and `watch` read `~/.jackherd/config.json` when the repository has no `.jackherd/config.json`. `check` then runs from the repository's top level. Reviewer names in `check.reviewerRoutes` carry the prefix, since `/jh-pre-commit` dispatches exactly the names it prints.
210
-
211
- Checked with a packed tarball and a throwaway `HOME` (shortened to `<home>`), in a throwaway Yarn 4 repository with `yarn.lock`, `origin/master` and no config of its own:
212
-
213
- ```text
214
- $ jh init --global --yes
215
- Created <home>/.jackherd/config.json with defaults.
216
- Installed into ~/.claude; the paths below are relative to <home>.
217
- jh sync: 30 created
218
- Added the SessionStart hook to ~/.claude/settings.json.
219
- Added the status line to ~/.claude/settings.json.
220
-
221
- $ jh check --skip-slow
222
- Changed files (8, 0 staged):
223
- .editorconfig
224
- .gitattributes
225
- .gitignore
226
- .yarnrc.yml
227
- README.md
228
- package.json
229
- src/probe.ts
230
- yarn.lock
231
-
232
- Package roots: none
233
- Reviewers: none
234
-
235
- ✅ Staged build artifacts (git status --porcelain --untracked-files=all, 0ms)
236
- ✅ Lint & unused imports (yarn biome check --no-errors-on-unmatched (8 files), 368ms)
237
- ⏭️ Types & tests (--skip-slow, 0ms)
238
- skipped on request
239
-
240
- ✅ 2 passed, 0 failed, 1 skipped
241
- ```
242
-
243
- #### Detected per repository
244
-
245
- What a config leaves out of `commands`, `lanes.lockFile`, `check.lintFilesCommand` and `baseBranch`, the kit reads from the repository it runs in, each time:
246
-
247
- - **Package manager** from the lock file in the repository root: `bun.lock` → `bun test`, `bun install`, `bunx @biomejs/biome …`; `yarn.lock` → `yarn test`, `yarn tsc --noEmit`, `yarn biome …`; `pnpm-lock.yaml` → `pnpm test`, `pnpm exec …`; `package-lock.json` → `npm test`, `npx …`. The lock file becomes `lanes.lockFile`. Lock files of two managers decide nothing: the Bun defaults hold, with one line saying so.
248
- - **Base branch** from the branches on `origin`: `main` or `master`, when exactly one of them exists. With both or neither, `main` holds, with one line saying so; `origin/HEAD` is not asked, since it can point at a branch long deleted.
249
-
250
- Detection only reads the lock files and `refs/remotes/origin/*` as the last fetch left them; it never fetches. A value you set always wins, key by key. `jh config` prints what applies in the repository you are in.
251
-
252
- The global skills cannot carry one repository's values, so `sync --global` writes them as `<test>`, `<install>`, `<lockFile>`, `<baseBranch>` and so on, and every global skill starts with a sentence that sends the model to `jh config` for them; a project install keeps the real values in its files. `init --global` writes none of these keys, so one global config serves a Yarn repository on `master` and a Bun repository on `main` alike. A global config from 0.10 or 0.11 spells out the Bun defaults and `main`, which count as set: delete `commands`, `baseBranch` and `lanes.lockFile` from it to get detection.
253
-
254
- #### Updating
255
-
256
- `jh update` asks npm for the newest release and, when there is one, installs exactly that version, from your home directory and without install scripts, with the package manager that installed the kit globally (bun, npm, pnpm or yarn, read from where the package lies), then syncs `~/.claude` and, inside a project, the project with the freshly installed code. It prints the old and the new version. A kit that is a project dependency or a source checkout is not a global install, and `update` says so and changes nothing; there, update the dependency and run `jh sync`.
257
-
258
- A running `plans` view restarts itself with the new code, and a running `watch` prints `=== kit updated <old> → <new>` and ends, so the coordinator reads its skill again and starts the stream again.
259
-
260
- #### Keeping the global kit current
261
-
262
- `jh sync --global --if-changed` is meant to run at the start of every session. It syncs `~/.claude` only when the installed package is not the version the global lock was written by, so after `bun add -g jackherd@<version>` the next session brings the skills up to date. Once a day it asks npm for the newest release and, when there is one, prints a single line of this form:
263
-
264
- ```text
265
- jh 1.2.0 is on npm, 1.1.0 is installed. Ask the user with AskUserQuestion whether to run `jh update` now (update now / not now), and run it only after a yes.
266
- ```
267
-
268
- It never installs anything itself: the session asks you, and `jh update` runs only after your yes. With nothing to do it prints nothing and exits 0; without a global install it syncs nothing. The time of the last npm question is kept in `~/.jackherd/update-check.json`. If npm does not answer (3 seconds), the question is asked again after an hour, not after a day, and nothing is printed meanwhile.
269
-
270
- The hook runs when a session starts, resumes, is cleared or is compacted (`startup|resume|clear|compact`), so a hand-over by `/clear` sees the line too; the daily timestamp makes the extra runs free. A session that runs for days is covered by [the watcher](#user-content-the-watcher), which looks at npm once a day on the same timestamp. `jh sync --global` moves a hook that still reads `startup` only, exactly as an older install wrote it, to the new matcher; a hook of your own, or one with another command or extra keys, stays as it is.
271
-
272
- `init --global` asks once whether to add this hook to `~/.claude/settings.json`, appends it as a group of its own beside your other hooks, and does nothing when it is there already. A file it cannot read or merge into, or a symlink, stays as it is; the entry to add by hand:
273
-
274
- ```json
275
- {
276
- "hooks": {
277
- "SessionStart": [
278
- { "matcher": "startup|resume|clear|compact", "hooks": [{ "type": "command", "command": "jh sync --global --if-changed" }] }
279
- ]
280
- }
281
- }
282
- ```
283
-
284
- Claude Code adds a `SessionStart` hook's output to the session's context, so the update line reaches Claude, not only the terminal; a failing hook does not block the session.
285
-
286
- #### Removing the global install
287
-
288
- ```bash
289
- rm -rf ~/.claude/skills/jh-* ~/.claude/agents/jh-*.md ~/.jackherd
290
- ```
291
-
292
- Remove `~/.jackherd/config.json` with it if you no longer need the config, and the `SessionStart` hook and status line entries from `~/.claude/settings.json` if `init --global` added them.
141
+ The installer, the setup questions, project or global install, updating and removing are in [INSTALL.md](https://unpkg.com/jackherd/INSTALL.md), with the steps for a coding agent that installs jackherd for you.
293
142
 
294
143
  </details>
295
144
 
@@ -298,7 +147,7 @@ Remove `~/.jackherd/config.json` with it if you no longer need the config, and t
298
147
 
299
148
  ### Planning: plans, models and boards
300
149
 
301
- Names on this page are those of a project install. A global install puts `jh-` before every skill and agent: `/jh-plan`, `/jh-implement`, `/jh-orchestrate`, the agent `jh-spec-review`.
150
+ Skills on this page are written as the quickstart installs them, with the `jh-` prefix of the global install (`/jh-plan`, `/jh-implement`, `/jh-orchestrate`); agents carry it too (`jh-spec-review`). A project install drops it by default (`skillPrefix` in `.jackherd/config.json` sets one).
302
151
 
303
152
  - [Terms](#user-content-terms)
304
153
  - [The skills and what they hand on](#user-content-the-skills-and-what-they-hand-on)
@@ -309,47 +158,51 @@ Names on this page are those of a project install. A global install puts `jh-` b
309
158
 
310
159
  #### Terms
311
160
 
312
- - **Plan:** a Markdown file with phases (`### Phase 1: …`) and checkbox tasks. `/plan` writes it, `/implement` builds one phase and ticks its tasks.
313
- - **Board:** a Markdown file with a lanes table that says who works on which phases of which plan, and what each lane starts after. `/plan` proposes its rows; by default it is `docs/plans/board-<name>/board.md`.
161
+ - **Plan:** a Markdown file with phases (`### Phase 1: …`) and checkbox tasks. `/jh-plan` writes it, `/jh-implement` builds one phase and ticks its tasks.
162
+ - **Board:** a Markdown file with a lanes table that says who works on which phases of which plan, and what each lane starts after. `/jh-plan` proposes its rows; by default it is `docs/plans/board-<name>/board.md`.
314
163
  - **Lane:** one agent session in its own git worktree, working on the phases its row names.
315
- - **Coordinator:** one more session, in the main checkout, running `/orchestrate`: it starts the lanes, answers or relays their questions, asks you for approvals and keeps the merge order.
164
+ - **Coordinator:** one more session, in the main checkout, running `/jh-orchestrate`: it starts the lanes, answers or relays their questions, asks you for approvals and keeps the merge order.
316
165
 
317
166
  #### The skills and what they hand on
318
167
 
319
- ![/grill hands decision rows to /plan; /plan feeds /orchestrate or a single /implement; /implement ends in /pre-commit, which runs /review and spec-review and the reviewers routed by path; /diagnose hands a red command to /implement.](https://unpkg.com/jackherd@1.0.0/docs/skills.svg)
168
+ <picture>
169
+ <source media="(prefers-color-scheme: dark)" srcset="https://unpkg.com/jackherd@1.7.0/docs/skills-dark.svg">
170
+ <img src="https://unpkg.com/jackherd@1.7.0/docs/skills.svg" alt="/jh-grill hands decision rows to /jh-plan; /jh-plan feeds /jh-orchestrate or a single /jh-implement; /jh-implement ends in /jh-pre-commit, which runs /jh-review, /jh-spec-review and the reviewers routed by path; /jh-diagnose hands a red command to /jh-implement.">
171
+ </picture>
320
172
 
321
- - **`/start`** is the first command after the install. It checks the config, herdr and `gh` with read-only commands, explains plan → board → `/orchestrate` or `/implement` in a few lines and offers to begin with `/plan`. It changes no file.
322
- - **`/grill`** questions a loose idea in rounds until every decision is settled, before there is a plan. It writes no document; it hands over decision rows that go into the plan's decisions table unchanged, and names what it left open.
323
- - **`/plan`** writes the plan file from one template ([what it contains](#user-content-what-a-plan-contains)). Its dependency table and its model per phase are what `/orchestrate` reads to tell which phase is ready to start, which lanes would collide, and which model a lane runs on; `/implement` reads the same table to start phases in parallel without `/orchestrate`. At the end `/plan` proposes the board's rows and asks whether they go into the newest board, a new one it names with you, or nowhere yet. If the decisions table would hold its own guesses, `/plan` stops and recommends `/grill` instead.
324
- - **`/orchestrate`** runs the lanes of a board in herdr from the main checkout ([Orchestration](#user-content-orchestration-with-herdr)). Each lane builds its phases with `/implement`.
325
- - **`/implement`** builds one phase: explore, build, test, look at it in the running app when a user sees the change, tick the plan's tasks as they finish. It hands a phase recommended for another model to a subagent on that model, starts independent phases as parallel subagents in one checkout, and ends in `/pre-commit`.
326
- - **`/pre-commit`** runs `jh check` and quotes its numbers, then `/review` for the judgement calls and the `spec-review` agent against the plan, plus the reviewers `check.reviewerRoutes` routes the changed paths to (`/uncle-bob`, `/security-audit`, `/devops`) and, for files a package publishes, `public-content`. It proposes the commit message and asks before committing.
327
- - **`/follow`** is beside the chain too: for a ticket, an issue or a status page outside GitHub it sets up a watcher source from a [recipe](#user-content-recipes), dry-runs it and writes it to `watch.sources` after you agreed ([Source reports](#user-content-the-watcher)).
328
- - **`/diagnose`** is beside the chain: for a bug, a flaky failure or a regression it first builds a command that goes red on it, then hands the fix to `/implement`.
173
+ - **`/jh-start`** is the first command after the install. It checks the config, herdr and `gh` with read-only commands, explains plan → board → `/jh-orchestrate` or `/jh-implement` in a few lines and offers to begin with `/jh-plan`. It changes no file.
174
+ - **`/jh-grill`** questions a loose idea in rounds until every decision is settled, before there is a plan. It writes no document; it hands over decision rows that go into the plan's decisions table unchanged, and names what it left open.
175
+ - **`/jh-plan`** writes the plan file from one template ([what it contains](#user-content-what-a-plan-contains)). Its dependency table and its model per phase are what `/jh-orchestrate` reads to tell which phase is ready to start, which lanes would collide, and which model a lane runs on; `/jh-implement` reads the same table to start phases in parallel without `/jh-orchestrate`. At the end `/jh-plan` proposes the board's rows and asks whether they go into the newest board, a new one it names with you, or nowhere yet. If the decisions table would hold its own guesses, `/jh-plan` stops and recommends `/jh-grill` instead.
176
+ - **`/jh-orchestrate`** runs the lanes of a board in herdr from the main checkout ([Orchestration](#user-content-orchestration-with-herdr)). Each lane builds its phases with `/jh-implement`.
177
+ - **`/jh-implement`** builds one phase: explore, build, test, look at it in the running app when a user sees the change, tick the plan's tasks as they finish. It hands a phase recommended for another model to a subagent on that model, starts independent phases as parallel subagents in one checkout, and ends in `/jh-pre-commit`.
178
+ - **`/jh-pre-commit`** runs `jh check` and quotes its numbers, then `/jh-review` for the judgement calls and the `spec-review` agent against the plan, plus the reviewers `check.reviewerRoutes` routes the changed paths to (`/jh-uncle-bob`, `/jh-security-audit`, `/jh-devops`) and, for files a package publishes, `public-content`. It proposes the commit message and asks before committing.
179
+ - **`/jh-follow`** is beside the chain too: for a ticket, an issue or a status page outside GitHub it sets up a watcher source from a [recipe](#user-content-recipes), dry-runs it and writes it to `watch.sources` after you agreed ([Following outside GitHub](#user-content-following-outside-github)).
180
+ - **`/jh-diagnose`** is beside the chain: for a bug, a flaky failure or a regression it first builds a command that goes red on it, then hands the fix to `/jh-implement`.
329
181
 
330
182
  #### What a plan contains
331
183
 
332
- `/plan` writes every plan from one template. Each part is there because a skill reads it:
184
+ `/jh-plan` writes every plan from one template. Each part is there because a skill reads it:
333
185
 
334
- - **Header (date, status, scope):** what the plan touches and how far it is; the board page of `plans` (key `s`) shows each plan with its title and status.
335
- - **Decisions:** each decision with its rationale, including who decided and when; `/plan` does not invent them, and `/orchestrate` writes a decision of yours into the plan the moment you make it.
186
+ - **Header (date, status, scope):** what the plan touches and how far it is; the board page of the herd (key `s`) shows each plan with its title and status.
187
+ - **Decisions:** each decision with its rationale, including who decided and when; `/jh-plan` does not invent them, and `/jh-orchestrate` writes a decision of yours into the plan the moment you make it.
336
188
  - **Model recommendations per phase:** the model for each phase with the reason ([below](#user-content-model-recommendations)).
337
- - **Dependencies and parallelization:** per phase what it depends on, the paths it writes and its serial markers (a migration, say). `/implement` starts phases with no shared path at the same time, and `/orchestrate` checks each lane's `Writes` set against the running lanes before starting it.
338
- - **Phases with checkboxes:** the tasks `/implement` ticks as it finishes them, which is what `plans` counts.
189
+ - **Dependencies and parallelization:** per phase what it depends on, the paths it writes and its serial markers (a migration, say). `jh check --parallel <plan>` lists the phases that can start together: every dependency ticked off, no shared path (a directory overlaps everything below it), no shared serial marker; a `User: …` entry counts as an open gate. `/jh-implement` starts them at the same time, the watcher proposes them to the coordinator (`=== parallel <lane> P<a> ∥ P<b>`), and `/jh-orchestrate` checks each lane's `Writes` set against the running lanes before starting it. The table cannot see two phases that change the same content or the same release file (changelog, version bump); that stays a judgement. `jh check` warns about a phase of a changed plan that has no row.
190
+ - **Phases with checkboxes:** the tasks `/jh-implement` ticks as it finishes them, which is what the herd counts.
339
191
  - **Review gate per phase:** pre-scan, tests, the reviewers to run, documentation. A phase is finished only when its gate is ticked, and a gate item naming a skill is ticked only after the skill ran. A phase that needs none says why (`**No review gate:** <reason>`); `jh check` refuses a new phase with neither.
340
192
  - **Tests:** which test files are needed and why, or the reason none are.
341
193
  - **Documentation and architecture docs:** what gets documented after the last phase, ending with the architecture documentation derived from the finished code.
342
194
 
343
- The section headings stay verbatim (in the plan language the config sets), because the plan parser, `/implement` and `spec-review` find them by name.
195
+ The section headings stay verbatim (in the plan language the config sets), because the plan parser, `/jh-implement` and `spec-review` find them by name.
344
196
 
345
197
  #### Model recommendations
346
198
 
347
- Each phase gets one row, judged by **error cost × complexity**. The project's implementation model (`models.implement`) is the default of every row. A phase moves up to the planning model (`models.plan`) when its rationale names a concrete error cost: a breakable invariant, possible data loss, security or tenant isolation, a migration without a way back, distributed state across systems. "Complex" or "many files" alone keeps the default. Review gates with `/security-audit` always get the strongest model.
199
+ Each phase gets one row, judged by **error cost × complexity**. The project's implementation model (`models.implement`) is the default of every row. A phase moves up to the planning model (`models.plan`) when its rationale names a concrete error cost: a breakable invariant, possible data loss, security or tenant isolation, a migration without a way back, distributed state across systems. "Complex" or "many files" alone keeps the default. Review gates with `/jh-security-audit` always get the strongest model.
348
200
 
349
201
  The recommendation is applied, not just noted:
350
202
 
351
- - `/implement` compares the phase's model with the one it runs on and, when they differ in either direction, hands the phase to a subagent on the recommended model.
352
- - `/orchestrate` starts each lane's agent with the full model ID from the board row and checks the banner before any work happens; an alias would resolve through `ANTHROPIC_DEFAULT_*_MODEL` and can land on another model.
203
+ - `/jh-implement` compares the phase's model with the one it runs on and, when they differ in either direction, hands the phase to a subagent on the recommended model.
204
+ - `/jh-orchestrate` starts each lane's agent with the full model ID from the board row and checks the banner before any work happens; an alias would resolve through `ANTHROPIC_DEFAULT_*_MODEL` and can land on another model.
205
+ - In a project install the hook `model-gate` checks it once more when `/jh-implement` hands a phase to a subagent: it reads the phase (`Phase P<n>`) and the plan path from the prompt and compares the subagent's model (from the call, else from the agent's definition) with that phase's row. A weaker model is stopped with the one to use, a stronger one passes with a note, and whatever the hook cannot tell (no phase, no row, no model) passes silently. When the subagent ends, `model-log` records the model it actually ran on in `.jackherd/models/`, and the herd shows it at the phase as `Opus ✓`, or `Sonnet ≠ Opus` in amber when it differs.
353
206
 
354
207
  The defaults a fresh `init` writes are `claude-opus-5-5` for `plan` and `orchestrate`, and `claude-sonnet-5-5` for `implement`, `review` and `explore`. Change them under `models` in the config.
355
208
 
@@ -403,7 +256,7 @@ Customers scroll the whole catalog to find a product. Support gets the same ques
403
256
  **Review gate Phase 1:**
404
257
 
405
258
  - [ ] Tests written
406
- - [ ] `/uncle-bob` — Clean Architecture review
259
+ - [ ] `/jh-uncle-bob` — Clean Architecture review
407
260
 
408
261
  ### Phase 2: Search box
409
262
 
@@ -413,7 +266,7 @@ Customers scroll the whole catalog to find a product. Support gets the same ques
413
266
  **Review gate Phase 2:**
414
267
 
415
268
  - [ ] Tests written
416
- - [ ] `/uncle-bob` — Clean Architecture review
269
+ - [ ] `/jh-uncle-bob` — Clean Architecture review
417
270
 
418
271
  ### Phase 3: Docs
419
272
 
@@ -424,13 +277,13 @@ Customers scroll the whole catalog to find a product. Support gets the same ques
424
277
 
425
278
  #### Boards
426
279
 
427
- A board gathers the lanes one coordinator runs; it mixes plans and has no end date of its own. `/plan` proposes the rows from the dependency and model tables:
280
+ A board gathers the lanes one coordinator runs; it mixes plans and has no end date of its own. `/jh-plan` proposes the rows from the dependency and model tables:
428
281
 
429
282
  - **Own lane:** a phase that shares no written path and no serial marker with a phase of another lane.
430
283
  - **Continuation (`↳`):** a phase that shares a written path or a serial marker with an earlier phase, or depends on it, runs in the same worktree after it.
431
284
  - **Starts after:** from the phase's dependencies (`P1 merged`, or an external gate such as `User: mockups`); a phase without one starts at once.
432
285
  - **Model:** the full model ID from the model table, never an alias.
433
- - **Plan:** a Markdown link to the plan, relative to the board's directory. The plan view finds a lane's plan only through that link.
286
+ - **Plan:** a Markdown link to the plan, relative to the board's directory. The herd finds a lane's plan only through that link.
434
287
 
435
288
  ```markdown
436
289
  <!-- docs/plans/board-01/board.md -->
@@ -445,7 +298,7 @@ A board gathers the lanes one coordinator runs; it mixes plans and has no end da
445
298
  | ↳ `search-ui` | – | [Product search](../2026-10-12-search.md) | P3 Docs | P2 merged | claude-sonnet-5-5 |
446
299
  ```
447
300
 
448
- The columns are read by position. The table heading is `## Lanes` (`## Spuren` with `planLanguage: de`). Nothing is written without your answer: `/plan` writes the rows into the newest board or a new `docs/plans/board-<name>/board.md`, and then names the next command, `/orchestrate <board path>`. Plan and board go into one commit under one approval: yours through `/pre-commit`, or the coordinator's documentation PR when `/orchestrate` finds them missing on the base branch ([Orchestration](#user-content-starting)). No merge is needed before `/orchestrate`.
301
+ The columns are read by position. The table heading is `## Lanes` (`## Spuren` with `planLanguage: de`). Nothing is written without your answer: `/jh-plan` writes the rows into the newest board or a new `docs/plans/board-<name>/board.md`, and then names the next command, `/jh-orchestrate <board path>`. Plan and board go into one commit under one approval: yours through `/jh-pre-commit`, or the coordinator's documentation PR when `/jh-orchestrate` finds them missing on the base branch ([Orchestration](#user-content-starting)). No merge is needed before `/jh-orchestrate`.
449
302
 
450
303
  Where boards live and what the project calls them is the `board` block of the config:
451
304
 
@@ -453,9 +306,9 @@ Where boards live and what the project calls them is the `board` block of the co
453
306
  { "board": { "pattern": "board-*", "file": "board.md", "term": "board" } }
454
307
  ```
455
308
 
456
- - `pattern`: the directories under `planDirectory` that hold a board; `plans` and `watch` take the newest one unless given a path.
309
+ - `pattern`: the directories under `planDirectory` that hold a board; `jh herd` and `jh watch` take the newest one unless given a path.
457
310
  - `file`: the board document in each of them.
458
- - `term`: the word `plans`, its HTML page and `watch` print for it (`board page opened: …`).
311
+ - `term`: the word the herd, its HTML page and `watch` use for it (`board page opened: …`).
459
312
 
460
313
  Up to 0.12 the key was `sprintPattern` with a fixed `sprint.md`. 0.13 refuses that key and names its replacement; a project that keeps its sprint documents sets `"board": { "pattern": "sprint-*", "file": "sprint.md", "term": "sprint" }` and renames nothing. `watch --sprint` is now `watch --board`.
461
314
 
@@ -466,7 +319,7 @@ Up to 0.12 the key was `sprintPattern` with a fixed `sprint.md`. 0.13 refuses th
466
319
 
467
320
  ### Orchestration with herdr
468
321
 
469
- For work that splits into independent parts, one agent session per part runs in its own git worktree, and Jack sits between them, keeping every lane on its path. One more session coordinates them. [herdr](https://herdr.dev) is the terminal multiplexer that holds the panes and reports each agent's state; `/orchestrate` (global: `/jh-orchestrate`) is the skill the coordinating session runs.
322
+ For work that splits into independent parts, one agent session per part runs in its own git worktree, and Jack sits between them, keeping every lane on its path. One more session coordinates them. [herdr](https://herdr.dev) is the terminal multiplexer that holds the panes and reports each agent's state; `/jh-orchestrate` (`/orchestrate` in a project install) is the skill the coordinating session runs.
470
323
 
471
324
  - [What runs where](#user-content-what-runs-where)
472
325
  - [Starting](#user-content-starting)
@@ -478,17 +331,20 @@ For work that splits into independent parts, one agent session per part runs in
478
331
 
479
332
  #### What runs where
480
333
 
481
- ![The coordinator prompts two lanes and asks you for decisions and approvals; the lanes send questions back as text; jh watch reads lane state, PRs and checks and wakes the coordinator.](https://unpkg.com/jackherd@1.0.0/docs/lanes.svg)
334
+ <picture>
335
+ <source media="(prefers-color-scheme: dark)" srcset="https://unpkg.com/jackherd@1.7.0/docs/lanes-dark.svg">
336
+ <img src="https://unpkg.com/jackherd@1.7.0/docs/lanes.svg" alt="The coordinator prompts two lanes and asks you for decisions and approvals; the lanes send questions back as text; jh watch reads lane state, PRs and checks and wakes the coordinator.">
337
+ </picture>
482
338
 
483
- `/orchestrate` needs herdr: it checks that `herdr` is on the path and `HERDR_ENV=1` is set, and stops otherwise. Without herdr, `/implement` still runs independent phases of one plan as parallel subagents in a single checkout, kept apart by their disjoint `Writes` sets.
339
+ `/jh-orchestrate` needs herdr: it checks that `herdr` is on the path and `HERDR_ENV=1` is set, and stops otherwise. Without herdr, `/jh-implement` still runs independent phases of one plan as parallel subagents in a single checkout, kept apart by their disjoint `Writes` sets.
484
340
 
485
341
  #### Starting
486
342
 
487
- 1. Set `"terminal": { "adapter": "herdr" }` in `.jackherd/config.json` (or `~/.jackherd/config.json`), so the plan view and `jh context` read agent states and context fill from herdr.
488
- 2. Open herdr, run Claude Code in the main checkout and type `/orchestrate docs/plans/<board>/board.md`. That session is the coordinator.
343
+ 1. Set `"terminal": { "adapter": "herdr" }` in `.jackherd/config.json` (or `~/.jackherd/config.json`), so the herd and `jh context` read agent states and context fill from herdr.
344
+ 2. Open herdr, run Claude Code in the main checkout and type `/jh-orchestrate docs/plans/<board>/board.md`. That session is the coordinator.
489
345
  3. **Plan and board on the base branch.** Before the first lane starts, the coordinator checks that the board and every plan it links are on `origin/<baseBranch>`. A fresh plan is not, and a lane cut from the base branch would not find it. No merge is needed first: the coordinator asks once, then commits the missing files on a branch `docs/plan-<topic>` from a temporary worktree, pushes it and opens a documentation PR. The lanes of that plan start from that branch until the files are on the base branch. Say no and no lane of these plans starts.
490
346
 
491
- It names itself in herdr (`orchestrator-<repository>` by default, since herdr names are unique across all repositories), opens the plan view beside its pane, tells you which lanes start now and which wait, and starts the watcher.
347
+ It names itself in herdr (`orchestrator-<repository>` by default, since herdr names are unique across all repositories), opens the herd beside its pane, tells you which lanes start now and which wait, and starts the watcher.
492
348
 
493
349
  #### What the coordinator does
494
350
 
@@ -497,10 +353,17 @@ Lanes ask Jack, not you: the coordinator checks their questions against the plan
497
353
  1. **Reads the board.** The `## Lanes` table names each lane, its port, the plan and phases it works on, what it starts after, and the model. It is the only place that says which lane runs which phase. The coordinator adds a row itself when a lane starts without one.
498
354
  2. **Starts ready lanes.** A phase is ready when its starts-after entry and the plan's dependencies are met and its `Writes` set and serial markers collide with no running lane; shared paths run one after the other, migrations strictly in order. For each lane it creates a worktree from the base branch, copies the untracked files every worktree needs, installs dependencies, starts the agent on the board's model, checks the banner shows that model, opens a plan pane beside it, and sends the lane prompt: plan, phases, the paths it may write, its port.
499
355
  3. **Runs dev servers.** A lane whose phase changes something a user sees gets its dev server in a pane of its own when the lane starts, never in the lane's shell.
500
- 4. **Vets questions.** A lane never opens a dialog. It ends its turn with a text block: the question, the options, its recommendation, the evidence at `file:line`. The coordinator checks the premises against the code and the plan, answers what the plan or a rule already settles, and brings only the open decisions to you, each as a clickable choice. A question in a lane's report is closed in the same turn, in the lane or with you. A draft you review (a README, a page) goes in rounds: you pick the remarks, the lane changes it, you see it again, and the push waits for your approval. Your decision goes into the plan or the board in the same turn, with the date, so it is visible in the plan view and survives the chat.
356
+ 4. **Vets questions.** A lane never opens a dialog; it ends its turn with a text block. The coordinator checks the premises against the code and the plan and brings the open decisions to you, each as a clickable choice.
357
+ - The block holds the question, the options, the lane's recommendation and the evidence at `file:line`.
358
+ - A question in a lane's report is closed in the same turn, in the lane or with you.
359
+ - A draft you review (a README, a page) goes in rounds: you pick the remarks, the lane changes it, you see it again, and the push waits for your approval.
360
+ - Your decision goes into the plan or the board in the same turn, with the date, so it is visible in the herd and survives the chat. The date and time come from `date`, never from the chat or a guess.
501
361
  5. **Reviews results.** When a lane is `done` or `idle`, it checks the diff against the lane's `Writes` set and that checks are quoted with numbers, not claimed. Then it starts the lane's next ready phase or names the reason to wait.
502
362
  6. **Asks once per PR.** A lane works uncommitted until its PR is ready. The coordinator then asks you once, with the diff summary, the checks with numbers, open points and the commit message; for a visible change it first walks the changed path in the browser. That approval covers the commits, the push and the PR. The question has three options: you merge, you approve and let the coordinator merge once the checks are green ([self-merge](#user-content-guarded-commands-and-self-merge)), or you change something first.
503
- 7. **Keeps the merge order.** Merge order is the board's, and the documentation PR of a fresh plan merges first. Afterwards the lanes rebase as after any merge, and the coordinator removes the copies of the plan files in the main checkout that equal the merged ones, so the next update of the checkout does not stop on them. After each merge the remaining lanes fetch and rebase on the base branch and re-run their checks; a lock-file conflict is never resolved by hand. Each lane gets its next phase or a named reason to wait.
363
+ 7. **Keeps the merge order.** Merges follow the board's order, the documentation PR of a fresh plan first. After each merge:
364
+ - the remaining lanes fetch and rebase on the base branch and re-run their checks; a lock-file conflict is never resolved by hand.
365
+ - the coordinator removes the copies of the plan files in the main checkout that equal the merged ones, so the next update of the checkout does not stop on them.
366
+ - each lane gets its next phase or a named reason to wait.
504
367
  8. **Closes lanes.** After a lane's last merge and your agreement, it ends the agent, proves the worktree holds nothing unmerged, removes the worktree and the branch, and notes the end in the board.
505
368
 
506
369
  #### What happens on its own, and what waits for you
@@ -516,7 +379,11 @@ Who merges follows the project's own rules: by default you, unless the project s
516
379
 
517
380
  #### Guarded commands and self-merge
518
381
 
519
- A merge or a release is the step nobody takes back. In a project install the `merge-guard` hook asks you before `gh pr merge` and `gh workflow run` (the usual production release) run: it recognises them when the command spells them out: behind options before the verb (`gh -R x pr merge`), a chain (`a && gh pr merge 12`), a wrapper (also one it does not know, such as `mise exec -- gh pr merge 12`, as any command whose words contain the guarded words in this order), `sh -c` and `eval`, and shows the dialog even in auto mode. A quoted text that names the words, such as a commit message, passes, and so does everything else; the hook prints nothing unless it asks.
382
+ A merge or a release is the step nobody takes back.
383
+
384
+ ##### What is guarded
385
+
386
+ In a project install the `merge-guard` hook asks you before `gh pr merge` and `gh workflow run` (the usual production release) run. It recognises them when the command spells them out: behind options before the verb (`gh -R x pr merge`), a chain (`a && gh pr merge 12`), a wrapper, known or not (any command whose words contain the guarded words in this order, such as `mise exec -- gh pr merge 12`), `sh -c` and `eval`. It shows the dialog even in auto mode. A quoted text that names the words, such as a commit message, passes, and so does everything else; the hook prints nothing unless it asks.
520
387
 
521
388
  ```json
522
389
  {
@@ -528,10 +395,18 @@ A merge or a release is the step nobody takes back. In a project install the `me
528
395
  ```
529
396
 
530
397
  - `guard.commands` lists the guarded commands as words, a program and one to three plain words after it: letters, digits and `-`, no `:` and no option. These two are the default; `git push` is not on the list. An empty list switches the guard off.
531
- - `guard.selfMerge.offer` (default `true`) lets `/orchestrate` offer "approve, and merge it yourself after green checks" in its PR question. With `false` the question has two options and the hook honours no such answer.
398
+ - `guard.selfMerge.offer` (default `true`) lets `/jh-orchestrate` offer "approve, and merge it yourself after green checks" in its PR question. With `false` the question has two options and the hook honours no such answer.
532
399
  - `guard.selfMerge.approvalMinutes` (default 180) is how long that answer lets `gh pr merge <number>` pass without a second dialog.
533
400
 
534
- **Merging without checks.** A pull request that only changes documents rarely needs its checks. List the paths in `merge.withoutChecks` (default empty, so every merge waits for the checks as before):
401
+ ##### Self-merge
402
+
403
+ You pick the second option of the PR question. The coordinator commits, pushes and opens the PR, waits for the checks in the background, merges with `gh pr merge <number> --squash --delete-branch` when they are green and tells you in one line; on a red check it does not merge and reports. The project supplement can block the option per approval tier.
404
+
405
+ The hook does not take the agent's word for your answer. It reads the session's transcript, which Claude Code writes, and looks for a dialog result where you picked that exact option for a question naming one branch. Then it asks GitHub which branch pull request `<number>` carries and lets the merge pass if the two match, the PR is open and not from a fork, and the command is exactly the plain form: `gh pr merge <number>` with `--squash`, `--merge`, `--rebase` and `--delete-branch` (or `-s`, `-m`, `-r`, `-d`) as the only flags, run on its own in the directory you work in (no `-R`, no `--admin`, no chain, no wrapper). `gh workflow run` and every other guarded command ask every time. The approval covers the branch, not the commits you saw, for the configured minutes.
406
+
407
+ ##### Merging without checks
408
+
409
+ A pull request that only changes documents rarely needs its checks. List the paths in `merge.withoutChecks` (default empty, so every merge waits for the checks as before):
535
410
 
536
411
  ```json
537
412
  {
@@ -539,16 +414,37 @@ A merge or a release is the step nobody takes back. In a project install the `me
539
414
  }
540
415
  ```
541
416
 
542
- A pattern is made of path words with `*` and `**`: no `..`, not absolute, no braces or negation, and at least one whole path segment without a wildcard, so `docs/**/*.md` is fine and `**`, `**/*.md` and `**/*.*` are refused. Keep the folder in the pattern: a `.md` file elsewhere can be an agent instruction (`CLAUDE.md`, a skill) that ships with a package and deserves its checks. With the list set, `/orchestrate` lists a pull request's files with `gh pr diff <number> --name-only` before it waits for checks and merges at once when every file matches. The merge guard checks the same itself: for a plain `gh pr merge <number>` it asks GitHub for the pull request and then for its files in that repository (`gh api …/pulls/<number>/files`, which also names the old path of a renamed file) and does not ask you when the pull request is open, from this repository, GitHub lists as many files as the pull request changes (fewer than 3000) and every one matches a pattern. This works without a self-merge answer, also when `guard.selfMerge.offer` is `false`. No file, one file outside, a count that differs, a failed `gh` call or a pattern list it cannot read means it asks as before. Limit: a push between its look and the merge is not seen.
417
+ A pattern is made of path words with `*` and `**`: no `..`, not absolute, no braces or negation, and at least one whole path segment without a wildcard, so `docs/**/*.md` is fine and `**`, `**/*.md` and `**/*.*` are refused. Keep the folder in the pattern: a `.md` file elsewhere can be an agent instruction (`CLAUDE.md`, a skill) that ships with a package and deserves its checks.
418
+
419
+ With the list set, `/jh-orchestrate` lists a pull request's files with `gh pr diff <number> --name-only` before it waits for checks and merges at once when every file matches.
420
+
421
+ The merge guard checks the same itself: for a plain `gh pr merge <number>` it asks GitHub for the pull request and then for its files in that repository (`gh api …/pulls/<number>/files`, which also names the old path of a renamed file). It does not ask you when the pull request is open, from this repository, GitHub lists as many files as the pull request changes (fewer than 3000) and every one matches a pattern. This works without a self-merge answer, also when `guard.selfMerge.offer` is `false`. No file, one file outside, a count that differs, a failed `gh` call or a pattern list it cannot read means it asks as before.
543
422
 
544
- **What self-merge does.** You pick the second option of the PR question. The coordinator commits, pushes and opens the PR, waits for the checks in the background, merges with `gh pr merge <number> --squash --delete-branch` when they are green and tells you in one line; on a red check it does not merge and reports. The project supplement can block the option per approval tier.
423
+ ##### Limits
545
424
 
546
- **What the hook checks.** It does not take the agent's word for your answer. It reads the session's transcript, which Claude Code writes, and looks for a dialog result where you picked that exact option for a question naming one branch. Then it asks GitHub which branch pull request `<number>` carries and lets the merge pass if the two match, the PR is open and not from a fork, and the command is exactly the plain form: `gh pr merge <number>` with `--squash`, `--merge`, `--rebase` and `--delete-branch` as the only flags, run on its own in the directory you work in (no `-R`, no `--admin`, no chain, no wrapper). `gh workflow run` and every other guarded command ask every time.
425
+ The hook reads the command as written, so it does not see what a command runs behind its back: a script file or a project script (`bash ./release.sh`, `./release.sh`, `bun run release`, `make release`) that calls `gh workflow run`, a shell alias or function, `gh alias` and git aliases, text that is encoded or assembled at run time, and a wrapper that spells the words differently. Add the script runners you use to `guard.commands`, or protect the repository itself.
547
426
 
548
- **Its limit.** The hook reads the command as written, so it does not see what a command runs behind its back: a script file or a project script (`bash ./release.sh`, `./release.sh`, `bun run release`, `make release`) that calls `gh workflow run`, a shell alias or function, `gh alias` and git aliases, text that is encoded or assembled at run time, and a wrapper that spells the words differently. Add the script runners you use to `guard.commands`, or protect the repository itself. The agent runs with your account, so it can also edit a transcript, drop the hook from `.claude/settings.json` or merge through `gh api`. The guard stops a merge or a release by mistake, by a misread instruction or a mistyped command; it does not stop an agent that sets out to get around it. For that, use branch protection and required reviews on the repository. The approval covers the branch, not the commits you saw, for the configured minutes. A global install ships no hook, so there the skill text alone asks you. If Bun cannot start (a process out of file descriptors, say), the hook cannot run and every Bash call is blocked, on purpose: a guard that cannot run does not wave commands through.
427
+ The agent runs with your account, so it can also edit a transcript, drop the hook from `.claude/settings.json` or merge through `gh api`. The guard stops a merge or a release by mistake, by a misread instruction or a mistyped command; it does not stop an agent that sets out to get around it. For that, use branch protection and required reviews on the repository.
428
+
429
+ - The merge-without-checks look is a snapshot: a push between its look and the merge is not seen.
430
+ - A global install ships no hook, so there the skill text alone asks you.
431
+ - If Bun cannot start (a process out of file descriptors, say), the hook cannot run and every Bash call is blocked, on purpose: a guard that cannot run does not wave commands through.
432
+
433
+ ##### Dialogs inside a lane
549
434
 
550
435
  A permission dialog inside a lane the coordinator confirms itself only for the commit and push of the lane's own branch under its PR approval, and for the fetch, rebase and lock-file steps after a merge, always with the one-time option. Every other dialog goes to you.
551
436
 
437
+ #### Approvals of a lane
438
+
439
+ In a project install the `approval-gate` hook takes over the permission dialogs of a lane. A call that would ask for your approval inside a lane (an `ask` rule in the permissions, such as a database tool or a project CLI) is held: the hook writes it to `.jackherd/approvals/<id>.json` in the main checkout (ignored by git), the watcher reports `=== approval <lane> <id> <tool> · <call>`, and the coordinator shows you the whole call from that file and asks you in its own pane, with the mark `` `approval <id> <hash>` `` in the question (the hash of the call you were shown, so your answer approves that content and nothing the file says later) and the options *Allow this call* and *Deny this call* (in German *Aufruf erlauben* and *Aufruf ablehnen*). The hook reads your answer only from the coordinator's transcript, never from a file of the lane, and then lets the call run or denies it.
440
+
441
+ - It waits up to `guard.approvals.waitMinutes` (1 to 9, default 8). Without an answer by then it denies the call with a note to retry it once approved; the retry of the same call passes at once when the answer is there.
442
+ - An approval holds once, for exactly that call (lane, directory, tool and input), and for 30 minutes.
443
+ - Outside a lane (no herdr, or not in a worktree under `worktreeDirectory`), for a call whose input exceeds 64 000 characters, and on any failure the hook decides nothing, and the dialog stays.
444
+ - The lane's pane shows the dialog meanwhile; a click there decides instead of your answer to the coordinator. The hook keeps waiting after such a click and spends a later answer to the same request, which then decides nothing; a retry of the call meanwhile may then need a second question.
445
+ - The hook runs from the lane's worktree (`.claude/hooks/approval-gate/`), so an edit to it there takes effect at the lane's next call.
446
+ - The coordinator is any agent in the main checkout; its herdr name differs per repository. The limit is the merge guard's: an agent that runs with your account could write a transcript line itself.
447
+
552
448
  #### The watcher
553
449
 
554
450
  Jack does not sit and stare at every pane. He waits, and barks when something moves: a lane is blocked or done, a check turns red, a pull request gets feedback.
@@ -558,7 +454,7 @@ Jack does not sit and stare at every pane. He waits, and barks when something mo
558
454
  Why it exists: the coordinator is a chat, and it only acts when something arrives in it. Without the watcher it would have to read every lane's pane in turn, or you would have to tell it that a lane is waiting. `jh watch` does the waiting instead and prints a report when there is something to do:
559
455
 
560
456
  - a lane's agent turned `blocked`, `done` or `idle`, or left herdr's list; a blocked lane adds the duty to vet its question. Under the lane's line stands its report file (`.claude/handover/<lane>-report.md` in its worktree: `report <path>` and its first 15 lines, a shorter head of 8 lines when it has one, plus every `## Questions` section from the first line the head leaves out, wherever it stands, under a `questions: <n>` line, within 20 lines and 1500 characters) when the lane wrote one since the last shown, else its screen without Claude Code's input box and status bar; a blocked lane always shows its whole screen, since the dialog is the news
561
- - a lane's pull request was merged (with a duty line per lane: rebase, next phase, or a reason), or its checks turned red or green
457
+ - a lane's pull request was merged (with a duty line per lane: rebase, next phase, or a reason), or its checks turned red or green; a red one names its failed checks and tests: `=== checks failed #<n> (<lane>): test (2 tests: search > finds a word, …)`. For that the watcher reads `gh run view <id> --log-failed` once per head commit (30 s, the last 2 MB, after the run has completed; a run still in progress is asked again at the next poll) and picks the lines `watch.checks.failedTestPattern` matches (default: Bun's `(fail) <name>`); without a match only the check names. The line is reported once per head commit and names tests only when the log was readable at that poll; the herd fills them in later
562
458
  - one of your own open pull requests on a branch no lane has, such as a documentation or `chore` PR the coordinator opened itself, was merged or its checks turned red or green: `=== checks failed #<n> (branch <name>)`; a merge asks every lane to rebase. The watcher finds them with one search for the pull requests of the account `gh` runs as (`--author @me`); the first sighting is a baseline
563
459
  - a deploy run ended, with its target, when the config sets `watch.deploy`; the run of a merged pull request without a lane names its number, `(push, #<n>)`
564
460
  - new feedback on a lane's open pull request: a review, an inline comment, a pull request comment, or one edited since (`watch.feedback`)
@@ -567,13 +463,15 @@ Why it exists: the coordinator is a chat, and it only acts when something arrive
567
463
  - `gh` became unreachable
568
464
  - npm has a newer jackherd than the one running: `=== update available <old> → <new>`, one line, once per version. The watcher asks npm once a day on the timestamp the `SessionStart` hook uses (`~/.jackherd/update-check.json`), so the two never ask twice a day or report twice; with nothing newer it prints nothing. The coordinator asks you and runs `jh update` only after your yes
569
465
  - a lane's context fill rose to `warn` or `alert` (`=== lane <name> alert 47 %`, with a duty line at `alert`: request the lane's hand-over at its next phase boundary), against the lanes' thresholds in `plans.context`
466
+ - an idle lane's last answer came from a model its board row's model column does not name (`=== model <name> <id> · board Opus 5.5`, with a duty line: switch it with `/exit` and `claude --resume <session> --model <id>`, not `/model`). Every model the column names fits, written as a name (`Opus 5.5`) or a full id, matched by family and version, notes in brackets ignored; once per deviation, again only when the model changes
467
+ - a lane's call waits for your approval (`=== approval <lane> <id> <tool> · <call>`, with a duty line naming the question's mark and options), see [Approvals of a lane](#user-content-approvals-of-a-lane)
570
468
  - the coordinator's own context fill rose to `warn` or `alert`, so it hands itself over in time
571
- - `lane added` / `lane removed` when a worktree with an agent or a board row appears or goes
469
+ - `lane added` / `lane removed` when a worktree with an agent or a board row appears or goes; a lane's helper agent, named `<lane>-<purpose>`, is watched with it
572
470
  - the heartbeat, a status line every 15 minutes (`--heartbeat`)
573
471
 
574
- Without `--board` the watcher chooses the board by the lanes it finds: the board whose table names the most found lanes (a worktree with a herdr agent of its name), then the most recently changed (last commit on the base branch, else the file's change time). The first line ends with the board it took (`armed: … board docs/plans/board-x/board.md`); when several boards were in question, the next line names the reason and the others, and `--board <path>` overrides. `jh plans` chooses the same way and shows that line with its errors.
472
+ Without `--board` the watcher chooses the board by the lanes it finds: the board whose table names the most found lanes (a worktree with a herdr agent of its name), then the most recently changed (last commit on the base branch, else the file's change time). The first line ends with the board it took (`armed: … board docs/plans/board-x/board.md`); when several boards were in question, the next line names the reason and the others, and `--board <path>` overrides. `jh herd` chooses the same way and shows that line with its errors.
575
473
 
576
- After a herdr server restart, panes come back as shells in their directories and the plans views are gone. `jh plans --ensure` brings them back beside the coordinator and each lane. Nobody has to run it by hand: inside herdr the watcher runs it at its start, for every `lane added` and whenever a lane's agent appears, so a new lane gets its view too (a lane without its agent waits, so its shell stays free for the agent), and the kit's herdr plugin runs it after a server start (herdr's `[[startup]]` hook), once herdr answers for every pane (up to 10 s; the terminals take about a second) and with up to four tries 2 s apart. A pane herdr lists an agent for is never taken as a free shell, also in the seconds after a restart before the agent's process is back. The watcher prints a line per view it started; a failure prints `plans --ensure failed, still watching: <reason>` once and does not stop the watch. It finds the coordinator by its herdr name, else by the calling pane, else as the only agent in the main checkout.
474
+ After a herdr server restart, panes come back as shells in their directories and the herd panes are gone. `jh herd --ensure` brings them back beside the coordinator and each lane. Nobody has to run it by hand: inside herdr the watcher runs it at its start, for every `lane added` and whenever a lane's agent appears, so a new lane gets its view too (a lane without its agent waits, so its shell stays free for the agent), and the kit's herdr plugin runs it after a server start (herdr's `[[startup]]` hook), once herdr answers for every pane (up to 10 s; the terminals take about a second) and with up to four tries 2 s apart. A pane herdr lists an agent for is never taken as a free shell, also in the seconds after a restart before the agent's process is back. The watcher prints a line per view it started; a failure prints `herd --ensure failed, still watching: <reason>` once and does not stop the watch. It finds the coordinator by its herdr name, else by the calling pane, else as the only agent in the main checkout.
577
475
 
578
476
  If the coordinator's herdr name is gone (a resumed session keeps the pane, not the name), the watcher reads the fill over its own pane (`HERDR_PANE_ID`) and the status line says `pane without a name, herdr agent rename "$HERDR_PANE_ID" <name>`. Without such an agent it says `no agent named <name>` instead of `null`. The watcher never renames an agent; `jh context --coordinator` reports the same on stderr.
579
477
 
@@ -590,7 +488,7 @@ coordinator coordinator no value (no agent named coordinator)
590
488
  gh unavailable since 11:24:31
591
489
  ```
592
490
 
593
- As a stream (`--stream`) it keeps running, and the heartbeat is one line. A working lane shows its plan progress, `<lane> working: P12 7/12` (the lane's current phase and its ticked checkboxes, counted as the plans view counts them), but only when the count moved since the last heartbeat; a lane that stays on one number says nothing, and you look for yourself. The plans are read only when a lane works:
491
+ As a stream (`--stream`) it keeps running, and the heartbeat is one line. A working lane shows its plan progress, `<lane> working: P12 7/12` (the lane's current phase and its ticked checkboxes, counted as the herd counts them), but only when the count moved since the last heartbeat; a lane that stays on one number says nothing, and you look for yourself. The plans are read only when a lane works:
594
492
 
595
493
  ```text
596
494
  armed: search=no agent board docs/plans/board-search/board.md
@@ -627,6 +525,8 @@ The form is `review <state>` (`approved`, `changes requested`, `commented`), `in
627
525
  { "watch": { "feedback": { "ignore": ["status-bot[bot]"] } } }
628
526
  ```
629
527
 
528
+ A bot's comment that only says it found nothing is no feedback: a comment of a login ending `[bot]` whose text, whitespace collapsed, equals one of `watch.feedback.noFindingTemplates`, with no inline comment of the same author within five minutes. The default is the clean-run comment of the CI code review (`## Code review` / `No issues found. Checked for bugs and CLAUDE.md compliance.`); `[]` counts every bot comment. Its inline comments, the real findings, always count.
529
+
630
530
  A pull request seen for the first time, and every pull request on a first start without saved state, is a baseline: what it already carries is not reported. Seen entries and their last change are part of the saved state, so a restart reports nothing twice and an edited comment is reported again. A REST read that fails reports nothing and the next one reaches back over the gap. The cost is two calls per GitHub read plus one per open lane pull request, against GitHub's 5000 REST calls per hour.
631
531
 
632
532
  **Preview reports** are off unless the config sets `watch.previews`. Once a lane pushes a new head commit and its deploy preview is updated after it, the watcher reports the link, once per head commit:
@@ -643,7 +543,52 @@ Two sources, either or both. `deployments: true` reads GitHub's deployments of e
643
543
 
644
544
  An edit without a new head commit reports nothing, so a bot that updates one comment per push wakes the coordinator once per push. A pull request seen for the first time is a baseline, as with feedback, and the reported head is part of the saved state. Where a bot first edits its comment to say the build is running and the link is already in it, that edit is the one reported, before the preview is ready. An edit read before GitHub's list shows the new head counts for the old head, and the new head is reported only at the next edit. A head costs one deployment list and at most one status call per GitHub read, and after a report no deployment is read for that pull request until its next push; the comments come from the feedback read, so they cost no call of their own while feedback is on.
645
545
 
646
- **Source reports** are off unless the config lists `watch.sources`. The watcher cannot use the MCP servers of a Claude Code session: their connections and logins (often OAuth in a browser) belong to the session. A source is a command instead, which prints JSON on stdout. It runs without a shell, in the main checkout, with your environment, so its token stays where it is. `/follow` sets one up for you (`/follow T-123`): it asks what to follow, checks the tool and its login, fills a recipe from below, shows a dry run and writes the source only after you agreed.
546
+ **Source reports**: a ticket, an issue or a status page outside GitHub, set up with `/jh-follow` and reported as `=== source <name> …`. → [Following outside GitHub](#user-content-following-outside-github)
547
+
548
+ #### Hand-over to a fresh chat
549
+
550
+ A long chat answers worse and gets cut off. Jack hands over to a fresh one before that, with a note of the state. Both sides hand over at a quiet moment, never in the middle of a task:
551
+
552
+ - **A lane**, at a phase boundary: `/jh-implement` reads its own fill with `jh context`. At `warn` or `alert`, and with a next phase to go, it asks whether that phase runs in a new chat. The watcher reads the lanes' fills too, once a minute, and reports a rise; at `alert` the coordinator asks the lane for its hand-over at the end of its current phase, so a long phase cannot run past the threshold unnoticed, and the lane then writes it without asking. On yes it writes `.claude/handover/<lane>.md` (state, open points, next step, traps, links; ignored by git). The coordinator asks you, ends the agent, starts a new one with the same model in the same worktree, and gives it the hand-over file as its first prompt.
553
+ - **The coordinator**, when the watcher reports `coordinator warn`: it records the state of every lane in the board's history, writes `.claude/handover/coordinator.md` and asks you. On yes it runs a script that waits until the coordinator is idle, sends `/clear`, and types `/jh-orchestrate <board>` with a pointer to the hand-over only once herdr shows a new session id for the pane. If any step fails, the script stops, logs the reason and the two inputs to type by hand to `.claude/handover/coordinator.log`, and shows a herdr notice.
554
+
555
+ Decisions never live only in a hand-over note: they are in the plan or the board first.
556
+
557
+ #### Lane setup from the config
558
+
559
+ - `commands.install` (default `bun install`, or what the lock file implies) installs a new lane's dependencies.
560
+ - `commands.dev` (default `bun run dev`) runs as `PORT=<port> <dev>` in the lane's dev-server pane.
561
+ - `lanes.copy` lists the untracked files every worktree needs (env files, say); with `lanes.copy` empty, the files `.worktreeinclude` lists are copied. Each file keeps its mode.
562
+ - `lanes.lockFile` (default `bun.lock`) is the file a rebase takes from the base branch and regenerates.
563
+ - `worktreeDirectory` (default `.claude/worktrees`) is where lane worktrees go: relative, below the repository root, without `..`; `jh sync` refuses anything else.
564
+
565
+ In a repository that ignores `docs/`, plan and board exist only in the main checkout and the herd reads them there; list the plan in `lanes.copy` so the lane has it to work from and to tick off its own progress.
566
+
567
+ The herdr plugin `zerodice0.worktree-bootstrap`, when enabled and configured in the main checkout, can copy files and run setup commands for new worktrees; the coordinator checks its result with the install command and a frozen lock file (`bun install --frozen-lockfile`, `pnpm install --frozen-lockfile`, `yarn install --immutable`, `npm ci`, derived from `commands.install`; an install command of your own runs as written) and does the step itself when it is missing.
568
+
569
+ </details>
570
+
571
+ <details>
572
+ <summary><b>Following outside GitHub</b></summary>
573
+
574
+ ### Following outside GitHub
575
+
576
+ Not everything that moves lives on GitHub. A product owner answers in the ticket, a vendor's status page turns red. Point Jack at it, and he keeps an ear on it:
577
+
578
+ ```text
579
+ /jh-follow PROJ-123
580
+ ```
581
+
582
+ `/jh-follow` asks what to follow, checks the tool and its login, shows you a dry run, and writes the source only after your yes.
583
+
584
+ From then on [the watcher](#user-content-the-watcher) reads it every few minutes and barks at the coordinator when something changes; a ticket also shows as a badge beside its lane's plan. That needs herdr. Without it you can still set a source up and dry-run it.
585
+
586
+ - [How a source works](#user-content-how-a-source-works)
587
+ - [Recipes](#user-content-recipes)
588
+
589
+ #### How a source works
590
+
591
+ Source reports are off unless the config lists `watch.sources`. The watcher cannot use the MCP servers of a Claude Code session: their connections and logins (often OAuth in a browser) belong to the session. A source is a command instead, which prints JSON on stdout. It runs without a shell, in the main checkout, with your environment, so its token stays where it is. `/jh-follow` fills one of the recipes below for you.
647
592
 
648
593
  ```json
649
594
  {
@@ -675,9 +620,9 @@ An edit without a new head commit reports nothing, so a bot that updates one com
675
620
  https://<host>/browse/T-123
676
621
  ```
677
622
 
678
- `items` is the path of the list in the output (without it the output is the list), `map` picks each entry's fields: `id` and `updatedAt` are required, `title`, `url`, `body` and `author` optional, and any further field you name (`status`, `priority`, `assignee`; a letter, then letters, digits and `_`) is read for `reportOn`. A path is `.` for the whole value or a chain of `.key`, `[n]` and `[-n]` (counted from the end), nothing more; for anything else, put a script in between.
623
+ `items` is the path of the list in the output (without it the output is the list), `map` picks each entry's fields: `id` is required, `updatedAt` too unless a content field (`title`, `author`, `body`, `url`) or `reportOn` can tell a change, and `title`, `url`, `body`, `author` and `status` (a ticket's status, below) are optional; any further field you name (`priority`, `assignee`; a letter, then letters, digits and `_`) is read for `reportOn`. A path is `.` for the whole value or a chain of `.key`, `[n]` and `[-n]` (counted from the end), nothing more; for anything else, put a script in between.
679
624
 
680
- What counts as news: an unknown `id` reports `new`; `updated` only when what you read changed, a short hash over `title`, `author`, `body` and `url`. A change of the time alone (a label, a sprint, a status) wakes nobody; where none of the four is mapped, `updatedAt` is the content. An entry whose `author` is in `ignoreAuthors` (case ignored) is recorded but wakes nobody, so your own comment does not. The first successful run of a source is a baseline, and the saved state holds per source only each id with its hash (with `reportOn` also the values of those fields, which may name people, such as an assignee), the 1000 seen most recently, so a restart repeats nothing and an entry that falls out of a time window and comes back is not new. Everything one GitHub read finds goes into one report, at most `reportLimit` entries per source (`5`), the rest as one line `=== source tickets +3 more`. The body shows its first line with text that is no Markdown heading (a bot's `## Code review` is skipped; a body of headings only shows the first), at most 160 characters, and the URL only as an `https:` URL without user name or password. `every` is in minutes, at least 1, `5` by default; the sources run with the GitHub read, so at most once a minute, and after a restart each runs at once.
625
+ What counts as news: an unknown `id` reports `new`; `updated` only when what you read changed, a short hash over `title`, `author`, `body` and `url`. A change of the time alone (a label, a sprint, a status) wakes nobody; where none of the four is mapped, `updatedAt` is the content, and then it is required. An entry whose `author` is in `ignoreAuthors` (case ignored) is recorded but wakes nobody, so your own comment does not. The first successful run of a source is a baseline, and the saved state holds per source only each id with its hash (with `reportOn` also the values of those fields, which may name people, such as an assignee), the 1000 seen most recently, so a restart repeats nothing and an entry that falls out of a time window and comes back is not new. Everything one GitHub read finds goes into one report, at most `reportLimit` entries per source (`5`), the rest as one line `=== source tickets +3 more`. The body shows its first line with text that is no Markdown heading (a bot's `## Code review` is skipped; a body of headings only shows the first), at most 160 characters, and the URL only as an `https:` URL without user name or password. `every` is in minutes, at least 1, `5` by default; the sources run with the GitHub read, so at most once a minute, and after a restart each runs at once.
681
626
 
682
627
  **Report a status change.** `reportOn` names the mapped fields whose change reports, in place of the content hash: with `"reportOn": ["status"]` a ticket that moves from one column to the next wakes the coordinator, and a new comment alone does not. The report names each changed field with its old and new value, cut to 60 characters, `(empty)` for none, in one line; the body follows only when `body` is one of the changed fields. An unknown `id` still reports `new`, and `ignoreAuthors`, `reportLimit` and the one report per read stay as they are. `status` is just a field name: any mapped field but `id` may be listed, including `title` or `body`.
683
628
 
@@ -699,9 +644,11 @@ A run that ends with an exit code other than 0, runs past 30 seconds (then its w
699
644
  === source tickets failed: exit 1
700
645
  ```
701
646
 
647
+ **Show a ticket beside its plan.** `"ticket": true` marks a source's entries as tickets. The herd then shows each one as a badge in the 📎 line of its lane's plan, right after `📄 Plan`: `📡 T-123 · In Progress`, linked to the ticket. A ticket belongs to the source's `lane`, and also to any lane whose board row, name or plan names its id as a whole word (`T-12` is not found in `T-123`); so one source listing all your open tickets works without `lane`. `map.status` is the status the badge shows; without it the badge shows only the key. A ticket whose last reported change is less than a day old is amber, and a folded lane then shows `📡 <n>` in amber before its bar, linked to the first new ticket. A lane shows at most three tickets, new ones first, then `+<n>`; a link chip of the plan with the same URL gives way to the badge. For this the saved state keeps, of a marked source only, each entry of its last successful run with its URL, its status (stored like a `reportOn` value) and the time its last change was reported. The badges come from the watcher's state like the pull request badges: without a running watcher or with a state older than three minutes there are none, and the header says `watcher off` or `state 4 min old`, also without a pull request. The [GitHub Projects recipe](#user-content-recipes) is a ticket source with a status.
648
+
702
649
  **How you hear about it.** The report goes to the coordinator, as a `=== source …` event of its watcher. It passes you one line with the entry, its gist and the link. A decision inside it, such as a product owner's answer, it takes over only after you confirmed it, since the text comes from outside. You hear of it only while the coordinator's session and its watcher run; what happened in between is reported at the next start. There is no desktop notification of its own: you get the one herdr shows for any lane that needs you. What a source reports is a change in the mapped content fields (`title`, `author`, `body`, `url`), or with `reportOn` a change of the fields it names, such as a status.
703
650
 
704
- **Try a source before the watcher runs it.** `jh watch source <name> --dry-run` runs a configured source once; a draft not yet in the config comes as a file (`jh watch source draft.json --dry-run`, one source object) or on stdin (`-`). It lists the entries (`<id> · <author> · <title>`), says that the watcher's first run of the source is a baseline and reports nothing, and shows one entry as a later report would print it; it neither reads nor changes the watcher's state. A field of `map` that is empty in every entry is named with its path (`map.updatedAt: in 23 of 23 entries empty (.fields.updated)`), read from the raw output, so a run that failed on a missing `id` or `updatedAt` names it too; the dry run then ends with exit code 1, as for a failed run, and `/follow` does not write the source. Without entries it says `0 entries: map not checked`. `--raw` adds the command's output, for finding the paths of `items` and `map`:
651
+ **Try a source before the watcher runs it.** `jh watch source <name> --dry-run` runs a configured source once; a draft not yet in the config comes as a file (`jh watch source draft.json --dry-run`, one source object) or on stdin (`-`). It lists the entries (`<id> · <author> · <title>`), says that the watcher's first run of the source is a baseline and reports nothing, and shows one entry as a later report would print it; it neither reads nor changes the watcher's state. A field of `map` that is empty in every entry is named with its path (`map.updatedAt: in 23 of 23 entries empty (.fields.updated)`), read from the raw output, so a run that failed on a missing `id` or `updatedAt` names it too; the dry run then ends with exit code 1, as for a failed run, and `/jh-follow` does not write the source. Without entries it says `0 entries: map not checked`. `--raw` adds the command's output, for finding the paths of `items` and `map`:
705
652
 
706
653
  ```text
707
654
  dry run source tickets: ["tickets-cli","search","--query","key in (T-123)","--json"]
@@ -718,7 +665,7 @@ The watcher reads `watch.sources` when it starts: a new or changed source counts
718
665
 
719
666
  Three limits stand: the watcher cannot make a command read only, so name only commands that read. A source in `.jackherd/config.json` runs for everyone who starts the watcher in the repository, at the same level of trust as `check.checks` and hooks. The watcher reads the config of the main checkout, never the one of a lane's worktree; a dry run started inside a worktree reads that worktree's config first. And `jh watch source … --dry-run` runs whatever command its draft names, so it never belongs in a permission allowlist.
720
667
 
721
- ##### Recipes
668
+ #### Recipes
722
669
 
723
670
  Each recipe is one `watch.sources` entry; put in your key, project or query, then try it with `--dry-run` (and `--raw` where the shape differs from what is shown). A token never goes into an argument: an argument shows in the process list. Where a tool keeps its own login, it is used; where a token sits in an environment variable, a small TypeScript script run by Bun (which runs wherever `jh` does) puts it from `process.env` straight into the request header. A script fails with an exit code, never with an empty answer the watcher would take for a source with nothing new, and it prints neither the token nor the body of a failed answer. The closing `export {}` makes the file a module, so the type check accepts top-level `await` and the names do not clash between scripts. A recipe that needs no script (`gh …`, `curl` on a public page, `curl --netrc`) stays a direct command. The watcher starts a source without a shell and reads `bun` as the first word to mean the Bun that runs the watcher itself, so the entry needs no absolute path, which would differ from machine to machine, even when Bun is not on the `PATH` (installed in `~/.bun/bin` only, say).
724
671
 
@@ -872,6 +819,21 @@ Check with `--raw` which end of `comments.nodes` holds the newest comment; `[0]`
872
819
  }
873
820
  ```
874
821
 
822
+ **GitHub Projects.** Reads the cards of a project board as tickets, without a script. Login: `gh` needs the `project` scope, `gh auth refresh -s project`. `<n>` is the project's number, `<owner>` its organization or `@me`; without `--limit` `gh` returns only 30 cards. Each card is `items[]` with its `id`, `title`, `content` (the issue or pull request, `content.url`; a draft card has none, so its badge has no link) and one key per project field, the name with a lower-case first letter, so the `Status` field is `.status` and holds the option's name. A card carries no time of its own, so the entry maps no `updatedAt` and a change of the title or URL is the change. The cards belong to a lane through `lane`, since their ids (`PVTI_…`) are not what a plan names:
823
+
824
+ ```json
825
+ {
826
+ "name": "board",
827
+ "command": ["gh", "project", "item-list", "<n>", "--owner", "<owner>", "--format", "json", "--limit", "200"],
828
+ "items": ".items",
829
+ "ticket": true,
830
+ "lane": "<lane>",
831
+ "map": { "id": ".id", "title": ".title", "url": ".content.url", "status": ".status" }
832
+ }
833
+ ```
834
+
835
+ jackherd only reads the board; the status moves by the project's own workflows (Settings → Workflows: "Item closed" and "Pull request merged" set Done, "Auto-add" brings new issues in), and a pull request moves its issue's card only when its description links it with `Closes #<n>`; otherwise the status stays where it was. Add `"reportOn": ["status"]` to be told of each move as well.
836
+
875
837
  **Sentry.** Token: an auth token with `event:read` in `SENTRY_AUTH_TOKEN`; `<host>` is `sentry.io` or your own. The script, for example `scripts/sources/sentry.ts`:
876
838
 
877
839
  ```ts
@@ -914,35 +876,14 @@ export {}
914
876
 
915
877
  The newest update stands first in `incident_updates`, so each new update of an open incident reports `updated` with its text.
916
878
 
917
- #### Hand-over to a fresh chat
918
-
919
- A long chat answers worse and gets cut off. Jack hands over to a fresh one before that, with a note of the state. Both sides hand over at a quiet moment, never in the middle of a task:
920
-
921
- - **A lane**, at a phase boundary: `/implement` reads its own fill with `jh context`. At `warn` or `alert`, and with a next phase to go, it asks whether that phase runs in a new chat. The watcher reads the lanes' fills too, once a minute, and reports a rise; at `alert` the coordinator asks the lane for its hand-over at the end of its current phase, so a long phase cannot run past the threshold unnoticed, and the lane then writes it without asking. On yes it writes `.claude/handover/<lane>.md` (state, open points, next step, traps, links; ignored by git). The coordinator asks you, ends the agent, starts a new one with the same model in the same worktree, and gives it the hand-over file as its first prompt.
922
- - **The coordinator**, when the watcher reports `coordinator warn`: it records the state of every lane in the board's history, writes `.claude/handover/coordinator.md` and asks you. On yes it runs a script that waits until the coordinator is idle, sends `/clear`, and types `/orchestrate <board>` with a pointer to the hand-over only once herdr shows a new session id for the pane. If any step fails, the script stops, logs the reason and the two inputs to type by hand to `.claude/handover/coordinator.log`, and shows a herdr notice.
923
-
924
- Decisions never live only in a hand-over note: they are in the plan or the board first.
925
-
926
- #### Lane setup from the config
927
-
928
- - `commands.install` (default `bun install`, or what the lock file implies) installs a new lane's dependencies.
929
- - `commands.dev` (default `bun run dev`) runs as `PORT=<port> <dev>` in the lane's dev-server pane.
930
- - `lanes.copy` lists the untracked files every worktree needs (env files, say); with `lanes.copy` empty, the files `.worktreeinclude` lists are copied. Each file keeps its mode.
931
- - `lanes.lockFile` (default `bun.lock`) is the file a rebase takes from the base branch and regenerates.
932
- - `worktreeDirectory` (default `.claude/worktrees`) is where lane worktrees go.
933
-
934
- In a repository that ignores `docs/`, plan and board exist only in the main checkout and the plan view reads them there; list the plan in `lanes.copy` so the lane has it to work from and to tick off its own progress.
935
-
936
- The herdr plugin `zerodice0.worktree-bootstrap`, when enabled and configured in the main checkout, can copy files and run setup commands for new worktrees; the coordinator checks its result with the install command and a frozen lock file (`bun install --frozen-lockfile`, `pnpm install --frozen-lockfile`, `yarn install --immutable`, `npm ci`, derived from `commands.install`; an install command of your own runs as written) and does the step itself when it is missing.
937
-
938
879
  </details>
939
880
 
940
881
  <details>
941
- <summary><b>Plan view and context</b></summary>
882
+ <summary><b>Herd and context</b></summary>
942
883
 
943
- ### Plan view and context
884
+ ### Herd and context
944
885
 
945
- `jh plans` is the plan files read for you: one live view of every lane of a board, kept open in a terminal or a herdr pane beside your sessions. The coordinator opens it beside its own pane and one per lane (`--lane <name>`).
886
+ `jh herd` shows the whole herd at a glance: every lane of a board with its plan progress, and with herdr also its agent's state, pull request, checks and context fill. It only reads and starts nothing; `/jh-orchestrate` runs the lanes and opens the herd beside the coordinator and one per lane (`--lane <name>`). Keep it open in a terminal or a herdr pane beside your sessions; `jh plans` still works as an alias.
946
887
 
947
888
  - [What it shows](#user-content-what-it-shows)
948
889
  - [Attachments](#user-content-attachments)
@@ -954,45 +895,49 @@ The herdr plugin `zerodice0.worktree-bootstrap`, when enabled and configured in
954
895
 
955
896
  One block per lane of the chosen board, lanes that wait on you first:
956
897
 
957
- - the agent's state: `❓ blocked` (waits for you), `📨 done` (the agent finished its answer, not the lane), `⏸ idle`, `⚡ working`, or `·` no agent
898
+ - the agent's state, a family of circles in one column: `● working`, `◆ blocked` in amber (waits for you), `◉ done` (the agent finished its answer, not the lane), `○ idle`, or `·` no agent
958
899
  - which lanes are listed at all. A lane with an agent or an open pull request is drawn in full. A lane with a worktree but no agent is listed under `· no agent`. A lane without a worktree is listed under `· waiting`, with what it starts after, when a phase it names is still open in its plan or, if it names no plan, when its "starts after" cell says something other than "now" (`sofort`); otherwise it is finished and not shown. A lane whose name cell carries the cleaned-up mark (`abgeräumt`) is finished whatever its plan says. The board needs no extra column for this
959
- - how full the agent's context is, and a bar with the lane's ticked tasks
900
+ - how full the agent's context is (`🥣`), and a bar with the lane's ticked tasks (`◐`)
960
901
  - the branch, commits ahead and uncommitted files
961
902
  - the lane's open pull request with its checks
962
- - per plan its attachments as chips (`📎`), the lane's phases with their counts, and the next open task of the current phase. The current phase is the one the lane's newest board row names: an open phase whose ticks in the worktree differ from the base branch, else one it ticked to the end there, shown as `ticked, not merged` until its ticks reach the base branch (in the sidebar title and the watcher's status line too), else its first open phase. A phase the newest row repeats from an earlier row counts as named. Ticks in older phases, say from tidying the plan, decide only when the newest row names no phase or only merged ones: then the same order runs over all rows, and without a touched phase the open phase of its newest row counts
903
+ - per plan its attachments as chips (`📎`), the lane's phases with their counts, and the next open task of the current phase (`▶`). A finished phase is a closed row of its own with a green `✓` and a green `n/n`; a phase whose only open box is the documentation box of its review gate reads `docs open` instead of n-1/n.
904
+ - The current phase is the one whose checkboxes moved last: on every re-read the herd compares each lane's ticks with the read before, and when exactly one phase changed, that phase becomes current and stays so until another single phase moves. On the first read, after a read where several phases changed at once (a merge, say), or when the lane does not show the moved phase, the newest board row decides, as follows. The memory lives only in the running `jh herd`, so a restart starts again from the board. The newest board row names the current phase this way: an open phase whose ticks in the worktree differ from the base branch, else one it ticked to the end there, shown as `ticked, not merged` until its ticks reach the base branch (in the sidebar title and the watcher's status line too), else its first open phase. A phase the newest row repeats from an earlier row counts as named. Ticks in older phases, say from tidying the plan, decide only when the newest row names no phase or only merged ones: then the same order runs over all rows, and without a touched phase the open phase of its newest row counts
963
905
 
964
- Three lanes of the example board in [Planning](#user-content-boards), with herdr agents, a pull request each for two of them and a mockup and a Figma link in the search plan, rendered by the package's own layout from example data at 80 columns:
906
+ Four lanes of an example board, three with herdr agents and one without, rendered by the package's own layout from example data at 80 columns. `search-ui` waits on you; its P2 is finished, its P3 lacks only the documentation box, and its plan carries a ticket, a mockup and a Figma link. Two lanes have a pull request:
965
907
 
966
908
  ```text
967
- Board 01 11:38
909
+ 🐾 Board 01 11:38
968
910
  ────────────────────────────────────────────────────────────────────────────────
969
- ▾ ❓ search-ui blocked 🧠 62 % │ ██░░░░░░░░ ✅ 1/5
911
+ ▾ ◆ search-ui blocked 🥣 62 % │ ██████░░░░ ◐ 6/9
970
912
  ⎇ feat/search-ui ↑1 ±4
971
913
  │
972
914
  └─ Product search
973
- ├─ 📎 📄 Plan ✦ Mockup ◈ Search box
915
+ ├─ 📎 📄 Plan 📡 PROJ-123 · In Progress ✦ Mockup ◈ Search box
974
916
  │
975
- ├─ ▸ P2 Search box 1/4
976
- └─ ▸ P3 Docs 0/1
977
- └─ ▶ Search flow
917
+ ├─ ✓ P2 Search box 4/4
918
+ ├─ ▸ P3 Docs docs open
919
+ │ └─ ▶ Dokumentation aktualisiert (README)
920
+ └─ ▸ P4 Review 0/2
978
921
  ────────────────────────────────────────────────────────────────────────────────
979
- ▸ 📨 checkout-fee done ↗ #42 💬 2 🧠 48 % │ ██████████ ✅ 6/6
922
+ ▸ ◉ checkout-fee done ↗ #42 💬 2 🥣 48 % │ ██████████ ◐ 6/6
980
923
  ────────────────────────────────────────────────────────────────────────────────
981
- ▾ ⚡ search-index working 🧠 34 % │ ████████░░ ✅ 4/5
924
+ ▾ ● search-index working 🥣 34 % │ ████████░░ ◐ 4/5
982
925
  ⎇ feat/search-index ↑3 ±2
983
926
  ↗ #41 … checks 🌐 preview 💬 1 new Search index
984
927
  │
985
928
  └─ Product search
986
929
  └─ ▸ P1 Index 4/5
987
- └─ ▶ /uncle-bob
930
+ └─ ▶ /jh-uncle-bob
931
+ ────────────────────────────────────────────────────────────────────────────────
932
+ · no agent (1) docs-site 1/3
988
933
  ────────────────────────────────────────────────────────────────────────────────
989
- ↑↓ select →← open a all n notes s html q quit ? help
934
+ ↑↓ select →← open a show ticked s html q quit ? help
990
935
  ```
991
936
 
992
- Right after `init`, on the example plan and board, without herdr and without a remote, both lanes have no agent yet and land in one group; `search-index` has 2 of its 5 boxes ticked (tasks and review gate), `search-ui` none. This is `plans --once`:
937
+ Right after `init`, on the example plan and board, without herdr and without a remote, both lanes have no agent yet and land in one group; `search-index` has 2 of its 5 boxes ticked (tasks and review gate), `search-ui` none. This is `herd --once`:
993
938
 
994
939
  ```text
995
- Board 01 11:38:08
940
+ 🐾 Board 01 11:38:08
996
941
  ───────────────────────────────────────────────────────────────────────────────
997
942
  ───────────────────────────────────────────────────────────────────────────────
998
943
  · no agent (2) search-index 2/5 · search-ui 0/5
@@ -1001,30 +946,30 @@ Board 01 11:38:08
1001
946
  gh pr list: no git remotes found
1002
947
  origin/main not found, reading plans from the checkout
1003
948
  ───────────────────────────────────────────────────────────────────────────────
1004
- ↑↓ select →← open a all n notes s html q quit ? help
949
+ ↑↓ select →← open a show ticked s html q quit ? help
1005
950
  ```
1006
951
 
1007
952
  #### Attachments
1008
953
 
1009
954
  Under each plan's title, a `📎` line carries the plan's links as chips; a click opens one in the browser:
1010
955
 
1011
- - `📄 Plan` opens the board's HTML page at that plan: its status, its chips and its phases with their checkboxes. The view writes the page when it is missing or the plans changed.
956
+ - `📄 Plan` opens the board's HTML page at that plan: its status, its chips and its phases with their checkboxes. The herd writes the page when it is missing or the plans changed.
1012
957
  - Links of a known kind become chips of their own: `✦` a Claude artifact (a mockup, say), `◈` Figma, `⑂` a GitHub pull request or issue. The chip's text is the link text, else the bold label before the link (`**Mockup:** <url>`), else the kind's name. A link on a line that says it is private carries that mark.
1013
958
 
1014
959
  Nothing is fetched to find them; the kinds are URL patterns, and `plans.linkKinds` in the config replaces them with your own (`pattern`, `label`, `icon`).
1015
960
 
1016
961
  #### Preview and feedback
1017
962
 
1018
- A pull request row reads `↗ #<n> ✓ checks`, then the watcher's badges, then the title, cut with `…` beside the badges and wrapped under itself without them; the number is a grey badge linked to the pull request. While the watcher runs (`jh watch`), `🌐 preview` opens the deploy preview the watcher reported for the pull request's current head (`watch.previews`), `💬 <n> new` in amber opens the pull request and counts the feedback since its last push that `watch.feedback` does not ignore, and `✋ changes requested` in dark red opens it while a reviewer's latest decisive review requests changes, which a push does not end; an ignored author counts there, since their review blocks the merge all the same. Only when number, checks and badges leave no room for a title do the badges move to a line below, starting in the column of the number. A folded lane shows each pull request as a badge, `↗ #42 💬 2` (amber while there is feedback, the count only above zero; `↗ #42 💬 2 ✋` in dark red while changes are requested), in one column right before the bar, the same for every lane. The words follow `responseLanguage` (`💬 3 neu`, `✋ Änderungen verlangt` in German). Everything comes from the watcher's saved state; the view makes no GitHub call for it. Without a running watcher, with a state older than three minutes (three missed GitHub reads), after a push until the watcher reports the new head, or for a preview recorded before 0.26.0 there is no such badge; while a lane has an open pull request, the header then says why beside the clock: `watcher off` or `state 4 min old`.
963
+ A pull request row reads `↗ #<n> ✓ checks` (red: the failed checks, `✗ test, lint`, at most three and `+n`; under a lane's pull request up to three failed tests and `+n`), then the watcher's badges, then the title, cut with `…` beside the badges and wrapped under itself without them; the number is a grey badge linked to the pull request. While the watcher runs (`jh watch`), `🌐 preview` opens the deploy preview the watcher reported for the pull request's current head (`watch.previews`), `💬 <n> new` in amber opens the pull request and counts the feedback since its last push that `watch.feedback` does not ignore, and `✋ changes requested` in dark red opens it while a reviewer's latest decisive review requests changes, which a push does not end; an ignored author counts there, since their review blocks the merge all the same. Only when number, checks and badges leave no room for a title do the badges move to a line below, starting in the column of the number. A folded lane shows each pull request as a badge, `↗ #42 💬 2` (amber while there is feedback, the count only above zero; `↗ #42 💬 2 ✋` in dark red while changes are requested), in one column right before the bar, the same for every lane. The words follow `responseLanguage` (`💬 3 neu`, `✋ Änderungen verlangt` in German). Everything comes from the watcher's saved state; the herd makes no GitHub call for it. Without a running watcher, with a state older than three minutes (three missed GitHub reads), after a push until the watcher reports the new head, or for a preview recorded before 0.26.0 there is no such badge; while a lane has an open pull request, the header then says why beside the clock: `watcher off` or `state 4 min old`.
1019
964
 
1020
965
  #### Where the numbers come from
1021
966
 
1022
- - **Plans and board** are read at `origin/<baseBranch>`, and a lane's own phases from its worktree once it has changes there. A phase no row of the lane names comes from the worktree too when it is new there or ticked further than on the base branch; one with fewer ticks there stays at the base, since the lane holds an old copy. Lanes and `↳` steps that only the checkout's board has are added to what the base branch says, so a row written a minute ago shows at once, without a mark: that they still wait for a merge is the coordinator's to track, and its watcher reminds it (`board: 2 rows only in the checkout` after its coordinator line). Rows both boards have, and a board missing on the base branch (read whole from the checkout, with its notice), are unchanged. The view fetches the base branch in the background every 5 minutes (`plans.fetchIntervalMinutes`, `0` turns it off) and redraws when a plan file changes or a fetch lands.
1023
- - **Pull requests and checks** come from `gh`. Without `gh` the view runs and says why the PRs are missing.
967
+ - **Plans and board** are read at `origin/<baseBranch>`, and a lane's own phases from its worktree once it has changes there. A phase no row of the lane names comes from the worktree too when it is new there or ticked further than on the base branch; one with fewer ticks there stays at the base, since the lane holds an old copy. Lanes and `↳` steps that only the checkout's board has are added to what the base branch says, so a row written a minute ago shows at once, without a mark: that they still wait for a merge is the coordinator's to track, and its watcher reminds it (`board: 2 rows only in the checkout` after its coordinator line). Rows both boards have, and a board missing on the base branch (read whole from the checkout, with its notice), are unchanged. The herd fetches the base branch in the background every 5 minutes (`plans.fetchIntervalMinutes`, `0` turns it off) and redraws when a plan file changes or a fetch lands.
968
+ - **Pull requests and checks** come from `gh`. Without `gh` the herd runs and says why the PRs are missing.
1024
969
  - **Agent state and context fill** come from herdr, with `"terminal": { "adapter": "herdr" }` in the config. Without it, every lane shows no agent.
1025
970
  - **A running lane without a board row**, neither at the base branch nor in the checkout, shows as `no row in lanes`, without plan and phases.
1026
971
 
1027
- While it runs inside herdr, the view also sets each lane's sidebar title (`P4 · 7/12`) and clears it on exit.
972
+ While it runs inside herdr, the herd also sets each lane's sidebar title (`P4 · 7/12`) and clears it on exit.
1028
973
 
1029
974
  #### Keys
1030
975
 
@@ -1032,14 +977,13 @@ While it runs inside herdr, the view also sets each lane's sidebar title (`P4 ·
1032
977
  | --- | --- |
1033
978
  | `↑` `↓` | select a lane, phase or task |
1034
979
  | `→` `←` | open or close the selected row |
1035
- | `a` | show or hide what is already ticked |
1036
- | `n` | show or hide a lane's notes |
980
+ | `a` | list the ticked checkboxes one by one, or sum them up again |
1037
981
  | `s` | write the board as one HTML page with every lane and plan, which also shows which lane waits for which, and open it |
1038
982
  | click, `enter`, `space` | on a lane or phase: open or close it; on a task: show its whole text; on a chip, a badge or a `↗` pull request: open it in the browser |
1039
983
  | `?` | the legend |
1040
984
  | `q` | quit |
1041
985
 
1042
- Options: `--once` prints one frame and exits (for reading the view from a script or a session), `--ensure` brings back the missing views beside the coordinator and each lane of the board (an empty shell in that tab takes the view, else the agent's pane is split) and prints what it did; the watcher does the same at its start, for every new lane and when a lane's agent appears (a lane without its agent waits), so a view is never started by hand, `--lane <name>` shows one lane with its current phase open, and a board path picks another board. Without one, the board is chosen as the watcher chooses it: the one that names the most lanes with a worktree and a herdr agent, then the most recently changed; the reason shows with the errors when several boards were in question.
986
+ Options: `--once` prints one frame and exits (for reading the herd from a script or a session), `--ensure` brings back the missing herd panes beside the coordinator and each lane of the board (an empty shell in that tab takes the herd, else the agent's pane is split) and prints what it did; the watcher does the same at its start, for every new lane and when a lane's agent appears (a lane without its agent waits), so a view is never started by hand, `--lane <name>` shows one lane with its current phase open, and a board path picks another board. Without one, the board is chosen as the watcher chooses it: the one that names the most lanes with a worktree and a herdr agent, then the most recently changed; the reason shows with the errors when several boards were in question.
1043
987
 
1044
988
  #### Context fill
1045
989
 
@@ -1078,12 +1022,12 @@ At `warn` a lane offers a fresh chat at its next phase boundary, and the watcher
1078
1022
  | Command | What it does | Options |
1079
1023
  | ------- | ------------ | ------- |
1080
1024
  | `jh --version` | The installed version, e.g. `1.6.0`; `-v` is the same | none |
1081
- | `jh init` | Creates `.jackherd/config.json` and installs the kit | `--global`: into `~/.claude` and `~/.jackherd`; `--yes`/`--no`: answer all its questions (globally the hook and the status line, in a project the prefix and the status line) and take the default [setup](#user-content-setup-questions); a status line of your own is replaced only by a yes in the dialog |
1025
+ | `jh init` | Creates `.jackherd/config.json` and installs the kit | `--global`: into `~/.claude` and `~/.jackherd`; `--yes`/`--no`: answer all its questions (globally the hook and the status line, in a project the prefix and the status line) and take the default [setup](https://unpkg.com/jackherd/INSTALL.md); a status line of your own is replaced only by a yes in the dialog |
1082
1026
  | `jh sync` | Updates the kit files; edited files get a `.kit-new` beside them | `--global`; `--accept <path>` takes the kit's version; `--global --if-changed` syncs only after a package update and names a newer npm release once a day |
1083
1027
  | `jh update` | Installs the newest release with the package manager that holds the kit globally, then syncs `~/.claude` and the project with the new code | none; does nothing when the installed version is the latest |
1084
1028
  | `jh config` | The values the current repository decides (`test`, `typecheck`, `lint`, `format`, `install`, `dev`, `lockFile`, `baseBranch`), as set or detected | `<name>`: one bare value |
1085
- | `jh check` | Types, lint and tests of the packages you touched, plus the project's own checks; in changed plans, an open checkbox whose `→ P<n>` is not at the end of the line fails, and so does a phase the change adds with tasks but without a review gate (or a `**No review gate:** <reason>` line); in a changed board, a lane row the change adds or edits whose phases cell names no `P<n>` warns; in a changed plan, a phase whose tasks are all ticked on `origin/<baseBranch>`, that the change does not tick further and that still has open boxes without `→ P<n>` warns | `--skip-slow`: lint and fast checks only |
1086
- | `jh plans` | Live view of the board's lanes and plans ([Plan view](#user-content-plan-view-and-context)) | `--once`: one frame and exit; `--lane <name>`: one lane; `--ensure`: bring back the missing views beside the coordinator and each lane, and exit; a board path (default: the newest board) |
1029
+ | `jh check` | Types, lint and tests of the packages you touched, plus the project's own checks; in changed plans, an open checkbox whose `→ P<n>` is not at the end of the line fails, and so does a phase the change adds with tasks but without a review gate (or a `**No review gate:** <reason>` line); in a changed board, a lane row the change adds or edits whose phases cell names no `P<n>` warns; so does one whose phases cell is longer than 250 characters or records a side order of the user (`also (User …`), which belongs as a task in the plan's phase; a phase of a changed plan without a row in its dependency table warns; in a changed plan, a phase whose tasks are all ticked on `origin/<baseBranch>`, that the change does not tick further and that still has open boxes without `→ P<n>` warns | `--skip-slow`: lint and fast checks only; `--parallel <plan>`: only the groups of phases that can run side by side |
1030
+ | `jh herd` | Live view of the board's lanes and plans ([Herd](#user-content-herd-and-context)) | `--once`: one frame and exit; `--lane <name>`: one lane; `--ensure`: bring back the missing herd panes beside the coordinator and each lane, and exit; a board path (default: the newest board) |
1087
1031
  | `jh context` | How full an agent's context is, as one line of JSON, or `null` | `<name>`: the agent (default: this worktree's); `--coordinator`: the coordinator's thresholds |
1088
1032
  | `jh watch` | Waits for the lanes and reports what the coordinator has to do ([The watcher](#user-content-the-watcher)) | `--stream`, `--heartbeat <minutes>`, `--board <path>`, `--coordinator <name>`, lane names (default: found) |
1089
1033
 
@@ -1096,11 +1040,11 @@ Without a global install, run any of them as `bunx jackherd <command>`.
1096
1040
  | Key | Default | What it decides |
1097
1041
  | --- | --- | --- |
1098
1042
  | `responseLanguage` | `en` | the language the skills speak with you, and the watcher's status words |
1099
- | `responseAddress` | `informal` | `informal` or `formal`: how replies address you where the language has both (German: `du` or `Sie`). `jh sync` writes it once into the kit rule `rules/kit/code-style.md`, which every session loads; it follows `responseLanguage`; the status words of the watcher and the plans view use no pronoun and stay as they are |
1043
+ | `responseAddress` | `informal` | `informal` or `formal`: how replies address you where the language has both (German: `du` or `Sie`). `jh sync` writes it once into the kit rule `rules/kit/code-style.md`, which every session loads; it follows `responseLanguage`; the status words of the watcher and the herd use no pronoun and stay as they are |
1100
1044
  | `planLanguage` | `en` | the language of plans and boards, including their headings |
1101
1045
  | `planDirectory` | `docs/plans` | where plans and boards live |
1102
1046
  | `board.pattern`, `board.file`, `board.term` | `board-*`, `board.md`, `board` | [Boards](#user-content-boards) |
1103
- | `worktreeDirectory` | `.claude/worktrees` | where lane worktrees go |
1047
+ | `worktreeDirectory` | `.claude/worktrees` | where lane worktrees go; relative, below the repository root |
1104
1048
  | `baseBranch` | detected, else `main` | the branch lanes start from and plans are read at |
1105
1049
  | `skillPrefix` | `''` (global: `jh-`) | put before every skill and agent name |
1106
1050
  | `commands.test`, `typecheck`, `lint`, `format`, `install`, `dev` | detected from the lock file | what the skills and `check` run; `dev` runs as `PORT=<port> <dev>` |
@@ -1108,16 +1052,17 @@ Without a global install, run any of them as `bunx jackherd <command>`.
1108
1052
  | `lanes.lockFile` | detected, else `bun.lock` | the lock file a rebase takes from the base branch |
1109
1053
  | `models.plan`, `implement`, `review`, `explore`, `orchestrate` | written by `init` | full model IDs per role; aliases are refused |
1110
1054
  | `terminal.adapter` | `none` | `herdr` for agent states and context fill |
1111
- | `plans.fetchIntervalMinutes` | `5` | background fetch of the base branch while `plans` runs |
1055
+ | `plans.fetchIntervalMinutes` | `5` | background fetch of the base branch while the herd runs |
1112
1056
  | `plans.linkKinds` | built in | links in a plan the board page shows as chips |
1113
1057
  | `plans.context` | lanes 60 % / 80 %, coordinator 50 % / 70 %, window 200 000 | [Context fill](#user-content-context-fill) |
1114
1058
  | `watch.deploy` | none | the deploy workflow and environments the watcher reports |
1115
- | `watch.feedback` | `{ "ignore": [] }` | `false` turns feedback reports off; `ignore` lists logins whose feedback does not count |
1059
+ | `watch.feedback` | `{ "ignore": [] }` | `false` turns feedback reports off; `ignore` lists logins whose feedback does not count; `noFindingTemplates`: bot comments that report no finding (default: the CI code review's clean run) |
1060
+ | `watch.checks` | `{}` | `failedTestPattern`: the regular expression for a failed test in a red run's log, first group the name (default: Bun's `(fail) <name>`); no nested quantifiers |
1116
1061
  | `watch.previews` | none | `deployments` (`false`), `authors` (`[]`) and `urlPattern`: where the watcher reads a lane's deploy preview |
1117
- | `watch.sources` | `[]` | commands whose JSON output the watcher reports as `source`: `name`, `command`, `every` (`5`), `items`, `map`, `ignoreAuthors` (`[]`), `reportLimit` (`5`), `lane`, `reportOn`; [recipes](#user-content-recipes) |
1062
+ | `watch.sources` | `[]` | commands whose JSON output the watcher reports as `source`: `name`, `command`, `every` (`5`), `items`, `map`, `ignoreAuthors` (`[]`), `reportLimit` (`5`), `lane`, `reportOn`, `ticket`; [recipes](#user-content-recipes) |
1118
1063
  | `check.lintFilesCommand` | detected | lint over the changed files |
1119
1064
  | `check.checks` | `[]` | project checks (`name`, `command`, optional `globs`) |
1120
- | `check.reviewerRoutes` | `[]` | which reviewer `/pre-commit` runs for which paths (`reviewer`, `globs`, `why`) |
1065
+ | `check.reviewerRoutes` | `[]` | which reviewer `/jh-pre-commit` runs for which paths (`reviewer`, `globs`, `why`) |
1121
1066
  | `check.generatorOwned` | `[]` | files a generator owns (`glob`, `generator`); `check` names the generator when one of them changed |
1122
1067
  | `check.buildArtifacts` | build output globs | staged files `check` refuses |
1123
1068
  | `check.publicContent` | none | [published files](#user-content-a-package-you-publish-from-the-repository) |
@@ -1150,7 +1095,7 @@ What usually stays to configure is what no file in the repository says, for exam
1150
1095
  - `merge-guard` asks you before `gh pr merge` and `gh workflow run` run, when they are spelled out ([Guarded commands](#user-content-guarded-commands-and-self-merge)).
1151
1096
  - `ask-hint` (event `Stop`) tells you when a turn ends in a question asked as running text and used no `AskUserQuestion` dialog. It only hints, never blocks, and stays silent in a lane session, which asks as a text block. Switch it off with `"hints": { "askUserQuestion": false }` in `.jackherd/config.json`.
1152
1097
  - `format-on-edit` runs the project's own Biome on edited TS, JS and JSON files, when the project has it installed.
1153
- - **herdr plugin:** a plans pane and an action that opens it ([Installation](#user-content-project-install)).
1098
+ - **herdr plugin:** a herd pane and an action that opens it ([Installation](https://unpkg.com/jackherd/INSTALL.md)).
1154
1099
 
1155
1100
  Each kit skill reads `.claude/project/<skill>.md` first when it exists; that file extends the skill for the project and wins where the two disagree. A project rule beside `.claude/rules/kit/` extends the kit rule of the same name.
1156
1101
 
@@ -1167,7 +1112,7 @@ When the repository publishes a package, `check.publicContent` names its files,
1167
1112
  ```
1168
1113
 
1169
1114
  - **`jh check`** reads the added lines against names it gathers on every run and never stores: the repositories beside this one (their names, their organisations from the remotes, the ticket keys in their branch names), this project's app folders, package scopes and the domains in its `.env*.example` files. A name the published files already use counts as their own word. A hit names file, line and kind (`names a neighbour repository`), never the name. More work directories and terms can come from `~/.jackherd/public-content.json` (`{ "workDirectories": ["~/work"], "terms": ["…"] }`), which lives outside every repository.
1170
- - **The `public-content` agent**, which `/pre-commit` starts for such a change, reads only the diff, as a stranger reads the package, and reports what gives away a project, a client, a team or a person. A global install names it `jh-public-content` in `check.publicContent.reviewer`.
1115
+ - **The `public-content` agent**, which `/jh-pre-commit` starts for such a change, reads only the diff, as a stranger reads the package, and reports what gives away a project, a client, a team or a person. A global install names it `jh-public-content` in `check.publicContent.reviewer`.
1171
1116
 
1172
1117
  </details>
1173
1118
 
@@ -1176,19 +1121,19 @@ When the repository publishes a package, `check.publicContent` names its files,
1176
1121
 
1177
1122
  ### Troubleshooting
1178
1123
 
1179
- **`/orchestrate` stops right away.** It runs only inside herdr: `command -v herdr` must find the binary and `HERDR_ENV` must be `1`. Start Claude Code in a herdr pane. For a single session, use `/implement` instead; it still runs independent phases in parallel as subagents.
1124
+ **`/jh-orchestrate` stops right away.** It runs only inside herdr: `command -v herdr` must find the binary and `HERDR_ENV` must be `1`. Start Claude Code in a herdr pane. For a single session, use `/jh-implement` instead; it still runs independent phases in parallel as subagents.
1180
1125
 
1181
- **The plan view shows every lane as `no agent`, and no context fill.** Set `"terminal": { "adapter": "herdr" }` in the config. A lane is matched to its herdr agent by name: the worktree directory, the board's lane name and the herdr agent must carry the same name.
1126
+ **The herd shows every lane as `no agent`, and no context fill.** Set `"terminal": { "adapter": "herdr" }` in the config. A lane is matched to its herdr agent by name: the worktree directory, the board's lane name and the herdr agent must carry the same name.
1182
1127
 
1183
1128
  **A lane shows `no row in lanes`.** Neither the board at `origin/<baseBranch>` nor the checkout's board has a row for it. Add the row (the coordinator does this itself when it starts a lane). A row that only the checkout has is shown like any other, not as `no row in lanes`.
1184
1129
 
1185
- **A lane cannot find its plan.** The plan is not on the base branch yet, and the lane's worktree was cut from there. A lane `/orchestrate` starts gets it: before the first lane, the coordinator checks board and plans against `origin/<baseBranch>` and, after your yes, starts the lanes from a documentation branch that carries them. A worktree made by hand needs the plan merged first.
1130
+ **A lane cannot find its plan.** The plan is not on the base branch yet, and the lane's worktree was cut from there. A lane `/jh-orchestrate` starts gets it: before the first lane, the coordinator checks board and plans against `origin/<baseBranch>` and, after your yes, starts the lanes from a documentation branch that carries them. A worktree made by hand needs the plan merged first.
1186
1131
 
1187
- **A lane shows no plan.** The view finds a lane's plan only through the Markdown link in the row's plan column. Link the plan once it exists, in the row of every lane that implements one of its phases.
1132
+ **A lane shows no plan.** The herd finds a lane's plan only through the Markdown link in the row's plan column. Link the plan once it exists, in the row of every lane that implements one of its phases.
1188
1133
 
1189
- **The view says `origin/main not found, reading plans from the checkout`.** The remote has no such branch yet, or the base branch is another one. Check `jh config baseBranch`, and set `baseBranch` if detection could not decide (it falls back to `main` when `origin` has both `main` and `master`, or neither).
1134
+ **The herd says `origin/main not found, reading plans from the checkout`.** The remote has no such branch yet, or the base branch is another one. Check `jh config baseBranch`, and set `baseBranch` if detection could not decide (it falls back to `main` when `origin` has both `main` and `master`, or neither).
1190
1135
 
1191
- **Pull requests and checks are missing.** They come from `gh`. The view and the watcher run without it and print why (`gh pr list: no git remotes found`, say); install and authenticate `gh` for them.
1136
+ **Pull requests and checks are missing.** They come from `gh`. The herd and the watcher run without it and print why (`gh pr list: no git remotes found`, say); install and authenticate `gh` for them.
1192
1137
 
1193
1138
  **A context fill of 100 %, or one that looks too high.** Session logs do not name the context window. Set `plans.context.windows` for your model IDs; otherwise 200 000 tokens are assumed.
1194
1139
 
@@ -1208,7 +1153,7 @@ When the repository publishes a package, `check.publicContent` names its files,
1208
1153
 
1209
1154
  **The config is refused.** Every command validates the whole config and names the key. A model alias (`opus`) is refused in favour of a full ID (`claude-opus-5-5`); `sprintPattern` is refused since 0.13 in favour of [`board`](#user-content-boards).
1210
1155
 
1211
- **`init --global` could not add the hook.** A `settings.json` it cannot read or merge into, or a symlink, stays as it is. The entry to add by hand is in [Installation](#user-content-keeping-the-global-kit-current).
1156
+ **`init --global` could not add the hook.** A `settings.json` it cannot read or merge into, or a symlink, stays as it is. The entry to add by hand is in [Installation](https://unpkg.com/jackherd/INSTALL.md).
1212
1157
 
1213
1158
  **`update` changes nothing.** The installed version is the latest, or the kit is a project dependency or a source checkout, which `update` leaves alone. Update the dependency and run `jh sync`.
1214
1159
 
@@ -1222,4 +1167,4 @@ When the repository publishes a package, `check.publicContent` names its files,
1222
1167
 
1223
1168
  ## License
1224
1169
 
1225
- The code is MIT. See [LICENSE](https://unpkg.com/jackherd@1.0.0/LICENSE); [NOTICE](https://unpkg.com/jackherd@1.0.0/NOTICE) lists the third-party material the kit files adapt. All rights to the artwork in [`assets/branding`](https://unpkg.com/jackherd@1.0.0/assets/branding/README.md) are reserved.
1170
+ The code is MIT. See [LICENSE](https://unpkg.com/jackherd@1.0.0/LICENSE); [NOTICE](https://unpkg.com/jackherd@1.0.0/NOTICE) lists the third-party material the kit files adapt. All rights to the artwork in [`assets/branding`](https://unpkg.com/jackherd@1.7.0/assets/branding/README.md) are reserved.