wherdr 1.3.3 → 2.0.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 (252) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/_nuxt/BDNMzG2s.js +1 -0
  3. package/.output/public/_nuxt/BETID3_E.js +1 -0
  4. package/.output/public/_nuxt/BHenDMeH.js +1 -0
  5. package/.output/public/_nuxt/BYZVrreW.js +1 -0
  6. package/.output/public/_nuxt/BhgehRdJ.js +1 -0
  7. package/.output/public/_nuxt/{yzABg5xl.js → Bpoxvzh6.js} +1 -1
  8. package/.output/public/_nuxt/BtH82ZuZ.js +9 -0
  9. package/.output/public/_nuxt/C25ROUa9.js +3 -0
  10. package/.output/public/_nuxt/C3Bkn4ac.js +62 -0
  11. package/.output/public/_nuxt/CDWjMk9C.js +2 -0
  12. package/.output/public/_nuxt/{Ci8N4mWR.js → CXJnLmWv.js} +1 -1
  13. package/.output/public/_nuxt/CuUQ4mEf.js +1 -0
  14. package/.output/public/_nuxt/DFGEl0v2.js +23 -0
  15. package/.output/public/_nuxt/{CKhgznq4.js → DFmgQVme.js} +42 -39
  16. package/.output/public/_nuxt/DZGKxROq.js +6 -0
  17. package/.output/public/_nuxt/DmkWvmnE.js +2 -0
  18. package/.output/public/_nuxt/DrKKeFFE.js +31 -0
  19. package/.output/public/_nuxt/DyfFwwGq.js +1 -0
  20. package/.output/public/_nuxt/FaNto0ga.js +105 -0
  21. package/.output/public/_nuxt/NIF0VwHk.js +25 -0
  22. package/.output/public/_nuxt/R0Y4VoeX.js +1 -0
  23. package/.output/public/_nuxt/board.CEEcFc6M.css +1 -0
  24. package/.output/public/_nuxt/builds/latest.json +1 -1
  25. package/.output/public/_nuxt/builds/meta/0b28b3e9-664e-4347-a35b-afb0a711d5c5.json +1 -0
  26. package/.output/public/_nuxt/entry.CKoXcwRa.css +2 -0
  27. package/.output/public/_nuxt/pdf.min.t82Z80JU.mjs +28 -0
  28. package/.output/public/_nuxt/pdf.worker.min.wgc6bjNh.mjs +28 -0
  29. package/.output/public/_nuxt/settings.Cdb21nNw.css +1 -0
  30. package/.output/public/sw.js +1 -1
  31. package/.output/server/chunks/_/branding.mjs +1 -1
  32. package/.output/server/chunks/_/changes.mjs +4 -4
  33. package/.output/server/chunks/_/fileDownload.mjs +278 -0
  34. package/.output/server/chunks/_/files.mjs +60 -20
  35. package/.output/server/chunks/_/machineOrder.mjs +1 -1
  36. package/.output/server/chunks/_/onboarding.mjs +1 -1
  37. package/.output/server/chunks/_/package.mjs +11 -3
  38. package/.output/server/chunks/_/plugins.mjs +92 -122
  39. package/.output/server/chunks/_/restart.mjs +1 -1
  40. package/.output/server/chunks/_/selfupdate.mjs +1 -1
  41. package/.output/server/chunks/_/settingstabs.mjs +36 -0
  42. package/.output/server/chunks/_/updates.mjs +1 -1
  43. package/.output/server/chunks/_/worktrees.mjs +1 -1
  44. package/.output/server/chunks/_/ws.mjs +43 -6
  45. package/.output/server/chunks/nitro/nitro.mjs +14126 -10238
  46. package/.output/server/chunks/raw/check-doc-links.mjs +5 -0
  47. package/.output/server/chunks/raw/check-leaks.mjs +1 -1
  48. package/.output/server/chunks/raw/check-release-notes.mjs +5 -0
  49. package/.output/server/chunks/raw/herdr-plugin.mjs +1 -1
  50. package/.output/server/chunks/raw/install-claude-statusline.mjs +1 -1
  51. package/.output/server/chunks/raw/prerelease-summary.mjs +5 -0
  52. package/.output/server/chunks/raw/prerelease.mjs +7 -0
  53. package/.output/server/chunks/raw/reveal.mjs +1 -1
  54. package/.output/server/chunks/raw/test-affected.mjs +5 -0
  55. package/.output/server/chunks/routes/api/_..._.mjs +6 -5
  56. package/.output/server/chunks/routes/api/agents.post.mjs +6 -5
  57. package/.output/server/chunks/routes/api/ask-tab.post.mjs +6 -5
  58. package/.output/server/chunks/routes/api/attach.post.mjs +6 -5
  59. package/.output/server/chunks/routes/api/auth/disable.post.mjs +6 -5
  60. package/.output/server/chunks/routes/api/auth/lock-all.post.mjs +6 -5
  61. package/.output/server/chunks/routes/api/auth/lock.post.mjs +6 -5
  62. package/.output/server/chunks/routes/api/auth/login/options.post.mjs +6 -5
  63. package/.output/server/chunks/routes/api/auth/login/verify.post.mjs +6 -5
  64. package/.output/server/chunks/routes/api/auth/max-session.post.mjs +6 -5
  65. package/.output/server/chunks/routes/api/auth/register/options.post.mjs +6 -5
  66. package/.output/server/chunks/routes/api/auth/register/verify.post.mjs +6 -5
  67. package/.output/server/chunks/routes/api/auth/status.get.mjs +6 -5
  68. package/.output/server/chunks/routes/api/changes.get.mjs +7 -6
  69. package/.output/server/chunks/routes/api/chat/image.get.mjs +7 -6
  70. package/.output/server/chunks/routes/api/chat.get.mjs +44 -11
  71. package/.output/server/chunks/routes/api/choose.post.mjs +44 -30
  72. package/.output/server/chunks/routes/api/claude-setup.post.mjs +42 -0
  73. package/.output/server/chunks/routes/api/claude-statusline.post.mjs +7 -6
  74. package/.output/server/chunks/routes/api/clear-queued-input.post.mjs +42 -0
  75. package/.output/server/chunks/routes/api/close/status.get.mjs +7 -6
  76. package/.output/server/chunks/routes/api/close.post.mjs +6 -5
  77. package/.output/server/chunks/routes/api/codex-update.post.mjs +7 -6
  78. package/.output/server/chunks/routes/api/commands.get.mjs +9 -7
  79. package/.output/server/chunks/routes/api/config.get.mjs +10 -13
  80. package/.output/server/chunks/routes/api/dirs.get.mjs +7 -6
  81. package/.output/server/chunks/routes/api/dismiss-stopped.post.mjs +7 -6
  82. package/.output/server/chunks/routes/api/dismiss.post.mjs +7 -6
  83. package/.output/server/chunks/routes/api/effort.post.mjs +7 -6
  84. package/.output/server/chunks/routes/api/efforts.get.mjs +7 -6
  85. package/.output/server/chunks/routes/api/file.post.mjs +7 -6
  86. package/.output/server/chunks/routes/api/files/download.get.mjs +12 -24
  87. package/.output/server/chunks/routes/api/files/download.head.mjs +41 -0
  88. package/.output/server/chunks/routes/api/files/read.get.mjs +8 -7
  89. package/.output/server/chunks/routes/api/files.get.mjs +7 -6
  90. package/.output/server/chunks/routes/api/health.get.mjs +6 -5
  91. package/.output/server/chunks/routes/api/input.post.mjs +33 -15
  92. package/.output/server/chunks/routes/api/interrupt.post.mjs +24 -21
  93. package/.output/server/chunks/routes/api/isgit.get.mjs +8 -8
  94. package/.output/server/chunks/routes/api/machine/awake.get.mjs +7 -6
  95. package/.output/server/chunks/routes/api/machine/awake.post.mjs +7 -6
  96. package/.output/server/chunks/routes/api/machine/order.get.mjs +6 -5
  97. package/.output/server/chunks/routes/api/machine/order.post.mjs +6 -5
  98. package/.output/server/chunks/routes/api/machine/reconnect.post.mjs +40 -0
  99. package/.output/server/chunks/routes/api/machine/rename.post.mjs +7 -6
  100. package/.output/server/chunks/routes/api/machine/status.post.mjs +39 -0
  101. package/.output/server/chunks/routes/api/menu-left.post.mjs +40 -0
  102. package/.output/server/chunks/routes/api/menu.post.mjs +10 -6
  103. package/.output/server/chunks/routes/api/model.post.mjs +7 -6
  104. package/.output/server/chunks/routes/api/models.get.mjs +7 -6
  105. package/.output/server/chunks/routes/api/nav.post.mjs +40 -26
  106. package/.output/server/chunks/routes/api/onboarding.get.mjs +6 -5
  107. package/.output/server/chunks/routes/api/onboarding.post.mjs +6 -5
  108. package/.output/server/chunks/routes/api/phone.get.mjs +8 -10
  109. package/.output/server/chunks/routes/api/phone.post.mjs +8 -10
  110. package/.output/server/chunks/routes/api/plugins/actions.get.mjs +6 -8
  111. package/.output/server/chunks/routes/api/plugins/invoke.post.mjs +6 -8
  112. package/.output/server/chunks/routes/api/plugins/projects.get.mjs +10 -8
  113. package/.output/server/chunks/routes/api/plugins/projects.post.mjs +11 -7
  114. package/.output/server/chunks/routes/api/prompt.post.mjs +22 -13
  115. package/.output/server/chunks/routes/api/push/quiet.post.mjs +7 -6
  116. package/.output/server/chunks/routes/api/push/subscribe.post.mjs +7 -7
  117. package/.output/server/chunks/routes/api/push/test.post.mjs +7 -6
  118. package/.output/server/chunks/routes/api/push/unsubscribe.post.mjs +7 -6
  119. package/.output/server/chunks/routes/api/quotas.get.mjs +7 -6
  120. package/.output/server/chunks/routes/api/rename.post.mjs +6 -5
  121. package/.output/server/chunks/routes/api/requeue.post.mjs +7 -6
  122. package/.output/server/chunks/routes/api/restart.get.mjs +6 -5
  123. package/.output/server/chunks/routes/api/restart.post.mjs +6 -5
  124. package/.output/server/chunks/routes/api/reveal.post.mjs +91 -8
  125. package/.output/server/chunks/routes/api/screen-key.post.mjs +19 -15
  126. package/.output/server/chunks/routes/api/screen.get.mjs +8 -40
  127. package/.output/server/chunks/routes/api/search.get.mjs +7 -6
  128. package/.output/server/chunks/routes/api/seen.post.mjs +7 -6
  129. package/.output/server/chunks/routes/api/sessions.get.mjs +7 -6
  130. package/.output/server/chunks/routes/api/sessions.post.mjs +7 -6
  131. package/.output/server/chunks/routes/api/settings-tab.post.mjs +90 -0
  132. package/.output/server/chunks/routes/api/{plugins/thread-limits.get.mjs → settings.get.mjs} +10 -9
  133. package/.output/server/chunks/routes/api/settings.post.mjs +40 -0
  134. package/.output/server/chunks/routes/api/space.post.mjs +34 -18
  135. package/.output/server/chunks/routes/api/state.get.mjs +7 -6
  136. package/.output/server/chunks/routes/api/tasks/action.post.mjs +39 -0
  137. package/.output/server/chunks/routes/api/{plugins/profiles.get.mjs → tasks/add.post.mjs} +12 -14
  138. package/.output/server/chunks/routes/api/tasks/after.post.mjs +39 -0
  139. package/.output/server/chunks/routes/api/tasks/approve.post.mjs +39 -0
  140. package/.output/server/chunks/routes/api/{project/report.get.mjs → tasks/archived.get.mjs} +12 -13
  141. package/.output/server/chunks/routes/api/{gitroot.get.mjs → tasks/autopilot.get.mjs} +13 -14
  142. package/.output/server/chunks/routes/api/tasks/autopilot.post.mjs +39 -0
  143. package/.output/server/chunks/routes/api/{index.get.mjs → tasks/board-settings.get.mjs} +12 -13
  144. package/.output/server/chunks/routes/api/tasks/board-settings.post.mjs +39 -0
  145. package/.output/server/chunks/routes/api/tasks/coordinator.get.mjs +40 -0
  146. package/.output/server/chunks/routes/api/tasks/coordinator.post.mjs +39 -0
  147. package/.output/server/chunks/routes/api/tasks/details.get.mjs +40 -0
  148. package/.output/server/chunks/routes/api/tasks/limit.post.mjs +39 -0
  149. package/.output/server/chunks/routes/api/tasks/links.get.mjs +39 -0
  150. package/.output/server/chunks/routes/api/tasks/models.get.mjs +40 -0
  151. package/.output/server/chunks/routes/api/tasks/pick.post.mjs +39 -0
  152. package/.output/server/chunks/routes/api/tasks/question.post.mjs +39 -0
  153. package/.output/server/chunks/routes/api/tasks/scheduled.get.mjs +40 -0
  154. package/.output/server/chunks/routes/api/{project → tasks}/settings.get.mjs +10 -11
  155. package/.output/server/chunks/routes/api/tasks/start.get.mjs +40 -0
  156. package/.output/server/chunks/routes/api/tasks/tell.post.mjs +39 -0
  157. package/.output/server/chunks/routes/api/tasks.get.mjs +39 -0
  158. package/.output/server/chunks/routes/api/unqueue.post.mjs +7 -6
  159. package/.output/server/chunks/routes/api/update/status.get.mjs +6 -5
  160. package/.output/server/chunks/routes/api/update.get.mjs +8 -10
  161. package/.output/server/chunks/routes/api/update.post.mjs +8 -10
  162. package/.output/server/chunks/routes/api/upload.post.mjs +7 -6
  163. package/.output/server/chunks/routes/api/worktrees/remove.post.mjs +6 -5
  164. package/.output/server/chunks/routes/api/worktrees.get.mjs +6 -5
  165. package/.output/server/chunks/routes/favicon.ico.get.mjs +6 -5
  166. package/.output/server/chunks/routes/icons/_name_.get.mjs +7 -6
  167. package/.output/server/chunks/routes/renderer.mjs +8 -7
  168. package/.output/server/chunks/routes/uploads/_...name_.get.mjs +7 -6
  169. package/.output/server/chunks/routes/ws/_..._.mjs +7 -6
  170. package/.output/server/chunks/routes/ws/events.mjs +9 -7
  171. package/.output/server/chunks/routes/ws/term.mjs +7 -6
  172. package/.output/server/chunks/virtual/precomputed.mjs +1 -1
  173. package/.output/server/index.mjs +7 -6
  174. package/.output/server/package.json +1 -1
  175. package/README.md +44 -1424
  176. package/bin/lib/commands.mjs +44 -9
  177. package/bin/lib/panel.mjs +3 -11
  178. package/bin/lib/service.mjs +41 -2
  179. package/bin/lib/skill.mjs +1 -1
  180. package/bin/lib/tailnet.d.mts +6 -3
  181. package/bin/lib/tailnet.mjs +70 -32
  182. package/bin/lib/userpath.d.mts +14 -0
  183. package/bin/lib/userpath.mjs +142 -0
  184. package/docs/README.md +58 -0
  185. package/docs/RELEASING.md +174 -0
  186. package/docs/board.md +164 -0
  187. package/docs/command.md +58 -0
  188. package/docs/configuration.md +39 -0
  189. package/docs/conversation.md +132 -0
  190. package/docs/development.md +38 -0
  191. package/docs/devices.md +58 -0
  192. package/docs/files.md +29 -0
  193. package/docs/herdr-projects-1x.md +278 -0
  194. package/docs/home.md +52 -0
  195. package/docs/installation.md +174 -0
  196. package/docs/machines.md +69 -0
  197. package/docs/migrate-from-1.x-docker.md +160 -0
  198. package/docs/networks.md +154 -0
  199. package/docs/notifications.md +83 -0
  200. package/docs/overview.md +71 -0
  201. package/docs/phone.md +26 -0
  202. package/docs/plugins.md +109 -0
  203. package/docs/quick-start.md +89 -0
  204. package/docs/quotas.md +65 -0
  205. package/docs/release-notes-2.0.0.md +84 -0
  206. package/docs/security.md +117 -0
  207. package/docs/terminal.md +15 -0
  208. package/docs/troubleshooting.md +45 -0
  209. package/package.json +11 -3
  210. package/skills/wherdr/SKILL.md +24 -167
  211. package/.output/public/_nuxt/B4Yk2tB1.js +0 -23
  212. package/.output/public/_nuxt/BBw_0a4M.js +0 -6
  213. package/.output/public/_nuxt/BSy6OCIY.js +0 -1
  214. package/.output/public/_nuxt/BX5PM2JQ.js +0 -1
  215. package/.output/public/_nuxt/BgPDnf2S.js +0 -1
  216. package/.output/public/_nuxt/BkOxQzbS.js +0 -2
  217. package/.output/public/_nuxt/CP8o925U.js +0 -1
  218. package/.output/public/_nuxt/CWwyK2XK.js +0 -2
  219. package/.output/public/_nuxt/CkbmecwS.js +0 -1
  220. package/.output/public/_nuxt/Cr3SrGky.js +0 -1
  221. package/.output/public/_nuxt/DAg9fiVh.js +0 -89
  222. package/.output/public/_nuxt/DT8qZ0Wv.js +0 -1
  223. package/.output/public/_nuxt/DaaJIRB3.js +0 -1
  224. package/.output/public/_nuxt/DcJi16XA.js +0 -1
  225. package/.output/public/_nuxt/SiL1FJ5s.js +0 -3
  226. package/.output/public/_nuxt/VpjCgSXu.js +0 -36
  227. package/.output/public/_nuxt/builds/meta/c735b6c0-1bd0-47d7-a208-d310f0a06287.json +0 -1
  228. package/.output/public/_nuxt/dPxB2L94.js +0 -89
  229. package/.output/public/_nuxt/entry.CGWKmYU3.css +0 -2
  230. package/.output/public/_nuxt/xYX85SPI.js +0 -1
  231. package/.output/server/chunks/_/pluginPolicy.mjs +0 -93
  232. package/.output/server/chunks/_/projectBoard.mjs +0 -366
  233. package/.output/server/chunks/_/projectDocs.mjs +0 -106
  234. package/.output/server/chunks/_/projectInbox.mjs +0 -135
  235. package/.output/server/chunks/_/projectThreads.mjs +0 -46
  236. package/.output/server/chunks/_/projectThreads2.mjs +0 -61
  237. package/.output/server/chunks/_/projectsActions.mjs +0 -143
  238. package/.output/server/chunks/_/projectsPlugin.mjs +0 -56
  239. package/.output/server/chunks/_/reveal.mjs +0 -115
  240. package/.output/server/chunks/raw/dev.wherdr.open.mjs +0 -7
  241. package/.output/server/chunks/raw/docker-entrypoint.mjs +0 -7
  242. package/.output/server/chunks/raw/install-host-open.mjs +0 -7
  243. package/.output/server/chunks/raw/wherdr-open.mjs +0 -7
  244. package/.output/server/chunks/routes/api/board.get.mjs +0 -147
  245. package/.output/server/chunks/routes/api/plugins/thread-limits.post.mjs +0 -45
  246. package/.output/server/chunks/routes/api/project/inbox.get.mjs +0 -43
  247. package/.output/server/chunks/routes/api/project/inbox.post.mjs +0 -43
  248. package/.output/server/chunks/routes/api/project/memory.get.mjs +0 -42
  249. package/.output/server/chunks/routes/api/project/routines.get.mjs +0 -43
  250. package/.output/server/chunks/routes/api/project/thread.get.mjs +0 -44
  251. package/.output/server/chunks/routes/api/project/thread.post.mjs +0 -45
  252. package/bin/install-docker-skill.sh +0 -20
@@ -0,0 +1,174 @@
1
+ # Releasing wherdr
2
+
3
+ Publishing a version requires the user's explicit approval. Never republish a package held
4
+ for npm review. No new secret is needed: GitHub uses `GITHUB_TOKEN`, npm uses OIDC Trusted
5
+ Publishing (`npm.yml`), and the tap uses the existing optional `HOMEBREW_TAP_TOKEN`.
6
+
7
+ 1. Merge reviewed changes, including the release workflows, into `main`. The site workflow
8
+ deploys relevant changes on pushes to `main`, independently of tags and npm.
9
+ 2. Set the same version in `package.json`, `package-lock.json` and `herdr-plugin.toml`.
10
+ Move the Unreleased changelog into a dated version entry. Run tests, typecheck and leak
11
+ checks; review and merge this version commit before tagging it.
12
+ 3. Create the GitHub release as a **draft**, with reviewed English notes under one or more of New / Improved /
13
+ Fixed / Update. Write at least two readable sentences explaining what changed for users,
14
+ then link to the tagged CHANGELOG.md (see the example below). A link alone, including
15
+ "See CHANGELOG.md", is never sufficient. Push its version tag only after these notes are ready.
16
+ The workflow validates the draft before attaching the package and again immediately before
17
+ publication; missing or insufficient notes fail the job. It never generates stable release notes.
18
+ 4. The tag starts `release.yml` and `npm.yml` independently. `release.yml` runs `npm pack`
19
+ (prepack builds Nitro, includes `skills/wherdr`, resolves linked packages). It attaches
20
+ `wherdr-X.Y.Z.tgz` and `wherdr-X.Y.Z.tgz.sha256` to the draft. After the package job
21
+ succeeds, it publishes the release with `latest=false`. The public GitHub package is now
22
+ usable; native plugins compare the archive checksum. A failed package job leaves the
23
+ release draft; fix and rerun the failed job.
24
+ 5. The Homebrew job updates the formula URL and SHA from GitHub, without waiting for npm.
25
+ **The manual Homebrew step is MANDATORY while `HOMEBREW_TAP_TOKEN` is absent**. Wait for `release.yml` to finish successfully first, so its
26
+ archive is public; then run `scripts/bump-homebrew.sh`. Otherwise the legacy update channel
27
+ cannot advance even when npm is ready. A skipped Homebrew job does not complete this step.
28
+ Homebrew still uses npm to install the local archive and fetch its third-party dependency;
29
+ it does not need the new **wherdr version** to be available on npm.
30
+ 6. `npm.yml` waits for the attached archive (up to 30 minutes), verifies it, then publishes
31
+ that exact file with provenance. npm moderation may still delay registry availability.
32
+ If the assets were too slow to arrive, rerun the failed download job before any successful
33
+ publication; never retry a successful `npm publish` merely because moderation is pending.
34
+ To recover a workflow fix without moving a tag, run `gh workflow run npm.yml --ref main -f version=vX.Y.Z` after merging the fix; it checks out that tag and publishes its existing release archive.
35
+ 7. `release-ready.yml` checks hourly and after npm/release workflow completion. Once npm's
36
+ tarball and `latest` tag, and the Homebrew formula are ready, it marks the GitHub release
37
+ `latest`. Existing 1.3.x apps read this marker and can then safely use their npm updater.
38
+ New apps read published stable releases directly, checking npm or the formula for their
39
+ own installation mode. No update notice is offered while that channel is unavailable.
40
+
41
+ An old plugin can get the release immediately via **U** in Herdr or the one-command installer;
42
+ its old in-app Update button waits for the legacy channel. Plugin installation tries the exact
43
+ version from GitHub, then npm, then compiles only when neither prebuilt source works. This
44
+ includes older releases with no GitHub archive. Keep the previous npm version, GitHub assets,
45
+ and Homebrew keg available for automatic health-check rollback.
46
+
47
+ SHA-256 checks download integrity, not authenticity: the archive and checksum share an origin.
48
+ Replacing both defeats this check. npm fallback compares the archive to the SHA-512 integrity
49
+ in registry metadata, with the same limitation. There is no signature or build attestation check.
50
+
51
+ npm provenance identifies the publishing workflow (`npm.yml`); the archive was built by
52
+ `release.yml` in the same repository at the requested tagged commit. On a manual run from
53
+ `main`, provenance identifies the workflow's `main` commit, while checkout and version checks
54
+ use the requested tag. It does not independently attest that separate build workflow (M8);
55
+ this limitation is intentionally retained.
56
+
57
+ Readiness logs name each missing npm or Homebrew condition, and an already-current `latest`
58
+ marker is left alone. GitHub disables scheduled workflows in public repositories after 60 days
59
+ without repository activity. Check that `release-ready.yml` remains enabled; re-enable it and
60
+ run it manually if needed. After re-enabling, workflow-completion and manual checks work too.
61
+
62
+ ## herdr-projects tested version
63
+
64
+ wherdr installs one herdr-projects release, and offers an update to it on machines with an older
65
+ one: `PROJECTS_TESTED` in `shared/projectsPlugin.ts`. `PROJECTS_MIN` (1.2.1) is the oldest
66
+ release wherdr still reads; it moves only when wherdr drops one.
67
+
68
+ To move to a newer herdr-projects release:
69
+
70
+ 1. Download its binary from GitHub (`gh release download vX.Y.Z -R eliasstravik/herdr-projects`)
71
+ and check it against its `.sha256`. Run it with `HOME` set to an empty temporary folder and
72
+ Herdr unreachable. Record `version`, `list --json`, `list --json --archived`,
73
+ `details --json -- <id>`, `show --json -- <id>` and `coordinator --machine --json status`
74
+ into `tests/recordings/herdr-projects-X.Y.Z/` (no personal paths or machine names).
75
+ Also check that `tell`, `approve`, `after`, `archive`, `restore` and `coordinator … tell`
76
+ still take the same arguments.
77
+ 2. Set `PROJECTS_TESTED` to `X.Y.Z`, and point the recordings test in
78
+ `tests/projectsTasks.test.ts` at the new folder.
79
+ 3. If the release adds a feature worth naming, add it to `FEATURES` in
80
+ `app/components/ProjectsPluginSettings.vue` (the update's one-line summary, FR + EN).
81
+ 4. Run `npx vitest related --run shared/projectsPlugin.ts`: `tests/projectsPlugin.test.ts`
82
+ fails until the install commands in `docs/board.md`, `docs/herdr-projects-1x.md` and
83
+ `website/public/agent.md` name the new release.
84
+
85
+ ## Release notes checklist
86
+
87
+ - Summarize the changes in English under `## New`, `## Improved`, `## Fixed` or `## Update`;
88
+ omit categories with no relevant changes. Use complete sentences, at least two in total
89
+ (at least twelve words), describing the user-visible behavior and any required upgrade action.
90
+ - Put the full changelog link after the summary, using the release tag rather than `main`.
91
+ - Review the text against that version's changelog. The automated check enforces structure
92
+ and minimum content; the reviewer checks accuracy and clarity.
93
+ - Validate the exact draft text locally before pushing the tag:
94
+ `GITHUB_REPOSITORY=example/wherdr GITHUB_REF_NAME=vX.Y.Z node scripts/check-release-notes.mjs < /tmp/wherdr-X.Y.Z.md`.
95
+ If the workflow refuses the notes, edit the draft and rerun the failed jobs.
96
+
97
+ Example (replace `example/wherdr` and the version, and describe the actual release):
98
+
99
+ ```markdown
100
+ ## Improved
101
+ File downloads now work with the supported Node versions. Temporary download links
102
+ are released after the browser saves the file, keeping repeated downloads reliable.
103
+
104
+ [Full changelog](https://github.com/example/wherdr/blob/vX.Y.Z/CHANGELOG.md)
105
+ ```
106
+
107
+ ## Rolling v2 prerelease
108
+
109
+ `v2-prerelease.yml` rebuilds one prerelease on every push to the `v2` branch, so a machine
110
+ can install v2 from a prebuilt package (the plugin's GitHub download) and never compile it.
111
+ It publishes the version of `herdr-plugin.toml` (for example `2.0.0-dev`, before the stable version bump) as `v<version>`:
112
+
113
+ - the tag moves to the pushed commit; the release is a prerelease, never `latest`. The update
114
+ checks of every version, the legacy channel and `release-ready.yml` only read stable
115
+ `vX.Y.Z` releases, so none of them offers it;
116
+ - `wherdr-<version>.tgz` and `.tgz.sha256` are made as in `release.yml` (`npm pack`,
117
+ `sha256sum`) and replaced; the archive must hold the built server, `bin` with
118
+ `bin/lib/install-skill.sh`, `package.json` and `skills/wherdr/SKILL.md`, and no native code
119
+ (`.node`, `binding.gyp`, `prebuilds`, ELF or Mach-O files): the same file runs on
120
+ linux-arm64 and x64;
121
+ - `COMMIT` holds the full SHA of the packaged commit, also written in the notes. It is removed
122
+ before the archive is replaced and attached last: when `COMMIT` is there and names the
123
+ branch head, the archive is that commit's.
124
+
125
+ Once the version is stable, the workflow skips packaging and publication; it must not create a stable tag.
126
+
127
+ The rolling notes start with an Update summary of the first three top-level Unreleased
128
+ changelog entries and a link to the changelog at the packaged commit, followed by build
129
+ metadata. Keep these entries readable and current; packaging fails if they are absent or fail the same minimum-content check.
130
+
131
+ `scripts/prerelease.sh` does the checks and the publication. It refuses a version without a
132
+ prerelease suffix (`X.Y.Z-something`) and a release of that tag that is not a published
133
+ prerelease: stable versions keep going through the steps above. The tag is moved with
134
+ `GITHUB_TOKEN`, which starts neither `release.yml` nor `npm.yml`. The workflow runs from the
135
+ `v2` branch: it acts once this file is on `v2`.
136
+
137
+ ## Commands for 2.0.0
138
+
139
+ Run in a release checkout after explicit approval. These commands are documentation, not a
140
+ request to publish. The version commit must go through the usual reviewed PR process.
141
+
142
+ ```sh
143
+ git switch main
144
+ git pull --ff-only
145
+ git switch -c release/2.0.0
146
+ npm version 2.0.0 --no-git-tag-version
147
+ sed -i.bak 's/^version = ".*"/version = "2.0.0"/' herdr-plugin.toml
148
+ rm herdr-plugin.toml.bak
149
+ # Move Unreleased notes to the dated 2.0.0 entry, run the project checks, then commit.
150
+ git add package.json package-lock.json herdr-plugin.toml CHANGELOG.md
151
+ git commit -m "Prepare release 2.0.0"
152
+ git push -u origin release/2.0.0
153
+ gh pr create --base main --head release/2.0.0 --title "Prepare release 2.0.0" --body "Prepare the reviewed 2.0.0 release versions and changelog."
154
+ # Open, review and merge the version PR; refresh main before continuing.
155
+ git switch main
156
+ git pull --ff-only
157
+ # Use the reviewed notes committed with the version preparation.
158
+ GITHUB_REPOSITORY="$(gh repo view --json nameWithOwner -q .nameWithOwner)" GITHUB_REF_NAME=v2.0.0 node scripts/check-release-notes.mjs < docs/release-notes-2.0.0.md
159
+ gh release create v2.0.0 --target "$(git rev-parse HEAD)" --draft --title "wherdr 2.0.0" --notes-file docs/release-notes-2.0.0.md
160
+ git tag v2.0.0
161
+ git push origin v2.0.0
162
+ release_run=$(gh run list --workflow release.yml --commit "$(git rev-parse HEAD)" --json databaseId --jq '.[0].databaseId')
163
+ # If no run appears yet, wait for GitHub to register the tag and repeat the lookup.
164
+ gh run watch "$release_run" --exit-status
165
+ gh run list --workflow npm.yml --limit 3
166
+ # MANDATORY while the tap secret is absent. Run only after release.yml succeeds:
167
+ sh scripts/bump-homebrew.sh 2.0.0 "$(gh repo view --json owner -q .owner.login)"
168
+ # Inspect the readiness workflow; optionally request an immediate check:
169
+ gh workflow run release-ready.yml --ref main
170
+ ```
171
+
172
+ Use Node.js 22 for npm commands. Do not manually publish the draft or mark it latest ahead
173
+ of these checks. A GitHub release created by `GITHUB_TOKEN` does not trigger other workflows;
174
+ all publication work is driven by the pushed tag, not `release: published` events.
package/docs/board.md ADDED
@@ -0,0 +1,164 @@
1
+ # Board and coordinators
2
+
3
+ [Documentation](README.md) · [Project](../README.md)
4
+
5
+ On desktop, drag the ticket panel’s divider to adjust its width. It uses the same
6
+ handle as the navigation list: arrow keys (Shift for a larger step), double-click,
7
+ Home or Enter to restore the default width. The width is saved on this device;
8
+ the Board keeps at least 280 px when space permits. Phone panels stay full screen.
9
+
10
+ ## Works great with herdr-projects
11
+
12
+ [herdr-projects](https://github.com/eliasstravik/herdr-projects) is a work board for Herdr: one
13
+ list of tasks, each handed to an ordinary agent in its own space, reviewed when it finishes and
14
+ merged on your yes. wherdr shows it on the **Board** (the button next to Settings, or `H`), for
15
+ every machine at once. It needs **herdr-projects 1.2.1 or later**; the plugin is optional.
16
+
17
+ **Install herdr-projects** in **Settings → Plugins → herdr-projects**, or on the machine. wherdr
18
+ installs the release it was tested with (1.2.21):
19
+
20
+ ```sh
21
+ herdr plugin install eliasstravik/herdr-projects --ref v1.2.21 --yes
22
+ ```
23
+
24
+ A machine with an older 1.x (1.2.1 or later) still works. Settings says **Update available**
25
+ there, with what the update adds, and **Update to 1.2.21** replaces Herdr's copy of the plugin;
26
+ the tasks and settings stay. wherdr reads the program's own version (`herdr-projects version`),
27
+ so a machine that ran `herdr-projects update` to a newer release is never taken back.
28
+
29
+ > **Breaking change in wherdr 2.0: herdr-projects 0.2 is no longer read.** The Project panel,
30
+ > the `TASKS.md` board, threads, thread limits and **New project** belonged to herdr-projects
31
+ > 0.2 and are gone. With 0.2 (or a 1.x older than 1.2.1), Settings and the Board say
32
+ > **Update herdr-projects to 1.2.1 or later, or downgrade wherdr to 1.3.4**, with the commands.
33
+ > The step-by-step move, with a backup and the way back, is in
34
+ > [docs/herdr-projects-1x.md](herdr-projects-1x.md). wherdr 1.3.4 is the last version
35
+ > that reads herdr-projects 0.2.
36
+
37
+ What the Board shows and does:
38
+
39
+ - **The board's groups**: needs you, ready to approve, working, to do. **Done** is history, so it
40
+ is hidden by default: **Done · 9** at the end of the column heads (the last tab on a phone)
41
+ shows it, newest first, the latest five then **Show all**, and hides it again; the choice is
42
+ saved on the server and shared across devices. Headings still count done tasks. Side by side
43
+ on a computer, one at a time on a phone. A card shows
44
+ the task's key (`DEMO-12`), title, the line its agent reports, the agent program, progress, its
45
+ pull request and its review (pass or fail, with the findings by severity).
46
+ - **A task** opens one compact side panel from the Board or its home row. The header names
47
+ the machine, repo, task and agent program, with the Board's one state: Needs you, Ready to
48
+ approve, Working, To do or Done. **Conversation**, **Terminal**, **Task** and **Settings** sit below it.
49
+ Task holds the description, closing note, report, pull request, review findings, limits,
50
+ token use and actions; a dot marks a new closing note or review. The agent's own Herdr state
51
+ is in a tooltip, separate from the task's state. The panel sits beside the Board on a
52
+ computer (with a full-screen button) and fills the screen on a phone.
53
+ - **Settings** reads the effective task settings from `show --json` on its machine when
54
+ opened. Agent, review, plan and attempts, limits, merge and workspace settings show their
55
+ value and source: task, repository, you, repository file or default. Source details,
56
+ CLI notes and problems stay visible. This view is read-only; unavailable or missing data
57
+ is stated explicitly. Board refreshes do not reread the settings.
58
+ - **Needs you** shows where the task stands now: the Board's failure or question, its command
59
+ output and next-step hint. A failure the task has moved on from (a later stage, or its agent
60
+ started again) is not the banner, and gets no buttons: it stays in Task as an earlier failure.
61
+ It offers **Retry**, **Send the error to the agent** (`fix`), **Open terminal** and, when
62
+ allowed, **Approve anyway** with confirmation. After a failed review, it lists the open
63
+ findings (severity and subject, worst first) and offers **Send the review back to the agent**
64
+ (`review`) first, as herdr-projects does, with **Approve anyway** after it. While the reviewer
65
+ shows a dialog (`reviewneeds`), a reply goes to the reviewer, and wherdr says so. **Finish** (`finish`, after a confirmation)
66
+ takes the work as it is, then runs its checks and review: offered when the agent stopped at
67
+ a limit (Retry gives it the same limit again) or without a summary, and when its agent is at
68
+ rest while the row stays on "Finishing". A setup failure offers **Start again**:
69
+ herdr-projects uses `delegate` before an agent has started. With no conversation, the panel
70
+ keeps the explanation visible instead of opening a bare shell; Terminal stays reachable
71
+ when a pane exists. Read-only and unreachable machines cannot run banner actions.
72
+ - **A task's sheet**, from the panel's **…** button, has the same details and actions as
73
+ the Task tab. **Open the chat** closes it and opens the conversation. When the agent has
74
+ no pane, a field sends a reply through herdr-projects (`tell`; on a waiting plan, it sends
75
+ the plan back).
76
+ **Approve** merges finished work or says yes to a plan, after a confirmation; **Start**,
77
+ **Stop**, **Retry**, **Finish** and **Archive** where herdr-projects takes them. **Start** names the agent
78
+ the task starts with by default (its `worker.agent` and where that comes from) and offers the
79
+ other agents installed on its machine: one picked there is for this start only
80
+ (`delegate --worker.agent`). herdr-projects keeps that pick as the task's own setting while
81
+ its run lasts; wherdr puts back what the task had once the run is over (back in To do, or
82
+ done) and before its next Start, so its default, the repo's and your own settings stay as they
83
+ are (`data/start-agents.json` remembers what to put back). A default agent not installed on that
84
+ machine is shown but cannot be picked: Start then waits for an installed one. With every slot of
85
+ the board taken (`board.agents` tasks at work), **Start** says **Queue** and the place the task
86
+ would get (`delegate` queues it). **Start after…** picks tasks to wait for, by key, id or title, on
87
+ every machine the Board reads (another machine's as `machine:KEY-12`): `delegate --after`. A task
88
+ that waits names them, with **Stop waiting** (`after --clear`); one in the queue says its place.
89
+ herdr-projects' refusals (a circle, an unknown task, a machine that does not answer) are shown as
90
+ they are. After an action the sheet
91
+ shows the task's new state, or why it was refused. **Archive** closes the sheet and takes the
92
+ task off the Board, with **Restore** in a toast for a few seconds; **Archived** lists the
93
+ archived tasks, whose sheet is read-only with **Restore**, as in herdr-projects.
94
+ - **Coordinators**, in the same panel: a machine's heading opens its Coordinator, the agent that
95
+ turns what you write into tasks; a repo's heading opens that repo's project coordinator. One
96
+ not started yet takes a first message (`coordinator tell`), which starts it. One that
97
+ herdr-projects could not start (an agent not installed there…) says why, with **Try again**
98
+ (`coordinator restart`) once it is fixed: the message still waiting then goes in.
99
+ - **Autopilot** (herdr-projects 1.2.15 or later): each coordinator has a switch, under the Board's
100
+ bar for the main Coordinator, in each machine and repo heading, and at the top of its panel. It
101
+ shows whether the board wakes that coordinator to work toward its goal, and when next. Turning it
102
+ on asks for the goal (filled in with the saved one, required otherwise) and, optionally, how often
103
+ and how many tasks a day or at once, for this time only (`herdr-projects autopilot on --goal …
104
+ [--machine | --project <repo>]`); stopping asks first (`autopilot off`). The state shown is read
105
+ back from `herdr-projects autopilot --json` after each action; a refusal (no goal, older version)
106
+ is shown as the board says it.
107
+ - **Task identity** stays with the worker on the home list, Board card and conversation header.
108
+ During a review, **Reviewed by** names the reviewer beside its own small logo. The conversation
109
+ explains that it belongs to the worker and the review runs separately; **Open reviewer terminal**
110
+ opens the reviewer's terminal when reachable, or a session switch is offered when it runs in
111
+ another open session. After a worker fallback, the main logo names the current worker and
112
+ **Took over from** names the previous one from the recorded handover.
113
+ - **The agent list** groups the board's spaces under their repo, as Herdr's sidebar does: each
114
+ machine's Coordinator and machine coordinator first, each with its own icon and the Board's name (**Coordinator** with
115
+ the board's icon, **`<machine>` coordinator** with the machine's), then per repo a head row, its project
116
+ coordinator (named after the repo, the wherdr mark on the accent, **Coordinator**, its state; its
117
+ question and one-tap answers when it asks one), a bar under it (fold, the tasks' summary such as `4 TASKS · 1 YOUR TURN ·
118
+ 1 LIMIT`, branch and commits behind its upstream, and the repo space's **…** menu, which opens
119
+ its terminal), and its tasks' spaces, indented and folding with the bar (key, title, state,
120
+ progress, time on it, the line the board reports; the Board icon opens the task there). One
121
+ row per task: its reviewer, planner and attempts, each in a tab of the task's space, are part
122
+ of it; in normal mode the row says the stage (**Under review · codex**), and both modes
123
+ open the task panel while a review runs. The counters count tasks, not tabs. A repo
124
+ coordinated from another machine shows **Coordinated from <machine>** above the bar instead
125
+ of a local coordinator. Without either coordinator, the bar is the first row; the repo's plain
126
+ terminal stays accessible through its **…** menu. wherdr reads this from
127
+ the board's files (`~/.herdr-projects/data`: tasks, attempts, reviewers, coordinators, repos)
128
+ and from Herdr's worktree groups, every 15 seconds while the list is shown, never through
129
+ herdr-projects' command line; the branch and behind count come from `git` in the repo's main
130
+ checkout, once a minute, without fetching.
131
+ - **Scheduled** (FR **Programmé**), collapsed in every coordinator panel: its Autopilot
132
+ status, wake frequency, goal and daily limits; board automations for that project
133
+ (including events across all repos), their latest firings and links to created tasks;
134
+ and Claude Code session timers reconstructed from successful transcript tool calls.
135
+ Open the section to read it; refreshing the Board refreshes an open section. It is
136
+ read only. Dates use the coordinator machine's time zone. Session timers disappear
137
+ when deleted, after a one-shot fires, or after seven days; they are lost when the
138
+ Claude Code session closes. An unavailable source is shown explicitly rather than
139
+ presented as an empty schedule.
140
+ - **Coordinator entry points**, named as herdr-projects names them, one name per level on the
141
+ Board, the home list, the conversation header and the menus: the top of the Board offers the
142
+ main **Coordinator** (FR **Coordinateur**), for all repos and machines it can reach. With
143
+ several hosts, its menu lists them by name; unavailable and read-only hosts stay listed with
144
+ their reason. Machine headings offer **`<machine> coordinator`** (FR **Coordinateur ·
145
+ `<machine>`**: the machine as a whole, its repos and folders, its tasks and agents), repo
146
+ headings offer **`<repo> coordinator`** (FR **Coordinateur · `<dépôt>`**: work in that repo). Hover or long-press an entry for its role;
147
+ the conversation header repeats that description.
148
+ - **A machine is one board**, shared by its named sessions: one list, one queue, one card per
149
+ task. A machine whose read fails says why on the Board, and its last tasks stay, marked with
150
+ the time they were read.
151
+ - What wherdr runs, on the task's machine and in its Herdr session (on an SSH machine, its own
152
+ session by name): `herdr-projects list --json`,
153
+ `details <id> --json`, `show <id> --json`, `set`/`unset worker.agent --task <id>` (to put back a pick), `tell <id> <text>`, `approve <id>`, `delegate` (with `--after`), `after <id> --clear`, `stop`, `retry`,
154
+ `archive` and `restore <id>`, `list --json --archived` (Archived), `coordinator tell <text>`,
155
+ `coordinator status --json` and `coordinator restart` (your
156
+ words always after `--`, so they are never read as options), through the plugin's own
157
+ launcher (`bin/run.sh`). Each command also runs herdr-projects' own upkeep, so wherdr calls it
158
+ sparingly: one command at a time per machine, a read every 15 seconds and only while the Board
159
+ is open (a list less than 5 seconds old is reused), and the last list kept when a machine is
160
+ slow or unreachable. Nothing runs where herdr-projects is missing or older than 1.2.1: its first
161
+ run would take over an older install's files.
162
+ - **Agents in user folders**: wherdr runs herdr-projects with your [PATH](installation.md#agent-path), on this
163
+ machine and over SSH, so `claude is not installed here` does not come from a login service's
164
+ short `PATH`.
@@ -0,0 +1,58 @@
1
+ # The wherdr command
2
+
3
+ [Documentation](README.md) · [Project](../README.md)
4
+
5
+ ### The `wherdr` command
6
+
7
+ An alternative to [the one command](installation.md#the-one-command), from npm or Homebrew: the same app, without
8
+ the Herdr plugin. npm can hold a new release for up to two days (moderation), so these get updates
9
+ later than the installer, which downloads the GitHub release package. The npm package holds the
10
+ built app: nothing is compiled on your machine. Try it with `npx wherdr` (or `bunx wherdr`,
11
+ `pnpm dlx wherdr`); to keep it, install it once:
12
+
13
+ ```sh
14
+ npm install -g wherdr # or: pnpm add -g wherdr, bun add -g wherdr
15
+ wherdr service install # configures automatic startup; prints the address
16
+ wherdr phone # phone state, the app's phone setup page, QR code once it answers
17
+ ```
18
+
19
+ | Command | What it does |
20
+ | --- | --- |
21
+ | `wherdr` (or `wherdr run`) | Runs in the foreground; Ctrl+C stops it. |
22
+ | `wherdr start` · `stop` · `restart` | Background server, pid and log in `~/wherdr`. `start` says *started* only once the port answers; otherwise it prints the end of the log. With a login service installed, they drive the service. |
23
+ | `wherdr status` | Address, process, service, data folder and log. |
24
+ | `wherdr logs` (`-f` to follow, `-n 100`) | The log, `~/wherdr/wherdr.log`. |
25
+ | `wherdr open` | Opens wherdr in the browser: its tailnet address when published and answering, else `localhost`. |
26
+ | `wherdr phone` | Whether your phone can reach wherdr (Tailscale, `tailscale serve`, the address answering), the `tailscale serve` command to publish it when it is not (wherdr then enables the address by itself), the link to **Settings › Phone**, and the QR code once the address answers. |
27
+ | `wherdr service install` · `uninstall` | Configure automatic startup: a LaunchAgent on macOS (`~/Library/LaunchAgents/dev.wherdr.plist`) starts at login; a `systemd --user` unit on Linux starts at boot with lingering enabled, otherwise at login. The command tries to enable lingering (`loginctl enable-linger`, without sudo; when your system refuses it, the command to run is printed) so it keeps running while you are logged out; without lingering it stops after logout. The service gets your [PATH](installation.md#agent-path). The one command and key **A** of the plugin's panel run it too. |
28
+ | `wherdr doctor` | Checks Node/Bun, Herdr and its socket, the port, the service, the data folder and `APP_URL`. |
29
+
30
+ Options: `--port` (default `7683`), `--host` (default `127.0.0.1`; loopback or this machine's
31
+ tailnet address, anything else is [refused](security.md#network-access) unless `WHERDR_TRUSTED_NETWORKS` names it),
32
+ `--data-dir` (passkeys, push keys and settings; default `~/wherdr/data`, the folder the Herdr
33
+ plugin and the install script use), `--session` (a named Herdr session). Every
34
+ [environment variable](configuration.md#configuration) works too, and so do `KEY=VALUE` lines in
35
+ `~/wherdr/wherdr.env` (for example `APP_URL=…`, read at each start); options win, then the
36
+ environment, then that file. `start` and `service install` remember the port and folders for
37
+ the other commands.
38
+
39
+ **Homebrew:** `brew install afloury/tap/wherdr` installs the same package; the first install also
40
+ brings Homebrew's Node.js (heavier than the Herdr plugin when Node.js 22 is already there). Then:
41
+
42
+ 1. `brew services start wherdr`: runs `wherdr run` now and at every login, log in
43
+ `$(brew --prefix)/var/log/wherdr.log` (`wherdr logs` reads it).
44
+ 2. `wherdr open`: the setup guide in your browser.
45
+ 3. Its Phone step (or `wherdr phone`).
46
+
47
+ On a Homebrew install, `wherdr start`, `stop`, `restart` and `service install` point to
48
+ `brew services` (the installed path changes at each upgrade); `wherdr status` and `wherdr doctor`
49
+ show the Homebrew service. Update: `brew upgrade wherdr && brew services restart wherdr`.
50
+
51
+ The login service records the **absolute path** of the runtime (n, nvm, fnm, Volta or Homebrew
52
+ node) and your [PATH](installation.md#agent-path), since launchd and systemd do not see your shell's. It refuses to point at a
53
+ temporary `npx` / `pnpm dlx` / `bunx` folder: install the package globally first. To update:
54
+ `npm install -g wherdr@latest && wherdr restart` (with `npx`: stop it, then `npx wherdr@latest`).
55
+
56
+ Bun runs wherdr too (WebSockets, push, passkeys and Herdr's socket work); when Node.js 22 is
57
+ also installed, `bunx wherdr` hands the server to Node, the reference runtime. Set
58
+ `WHERDR_RUNTIME=bun` to keep Bun.
@@ -0,0 +1,39 @@
1
+ # Settings and configuration
2
+
3
+ [Documentation](README.md) · [Project](../README.md)
4
+
5
+ - **Themes**: wherdr Titanium (default), herdr.dev and Herdr's built-in themes, or follow your Herdr theme.
6
+ **English and French** interface.
7
+
8
+ ## Configuration
9
+
10
+ All settings are environment variables: `KEY=VALUE` lines in `~/wherdr/wherdr.env` for the
11
+ native service (read at each start: `wherdr restart`, or **R** in the panel).
12
+
13
+ | Variable | Default | Meaning |
14
+ | --- | --- | --- |
15
+ | `PORT` | `7683` | Listening port. |
16
+ | `HOST` | `127.0.0.1` (`npm start`) | Listening address: loopback, or this machine's tailnet address (`tailscale ip`, with Tailscale running). Any other address (`0.0.0.0`, a LAN address) stops wherdr at startup unless `WHERDR_TRUSTED_NETWORKS` covers it. |
17
+ | `WHERDR_TRUSTED_NETWORKS` | *(empty)* | Other private networks wherdr accepts besides this computer and the tailnet, as comma-separated CIDR ranges or addresses (e.g. `10.147.17.0/24` for ZeroTier). `any` accepts every network, with a warning at startup and in the app: not recommended. See [Network access](security.md#network-access). |
18
+ | `HOST_LABEL` | server hostname | Name of this machine in the app (can be renamed in the app). |
19
+ | `APP_URL` | *(empty)* | App address and allowed host; a valid HTTPS URL enables Web Push. HTTP, empty or invalid values disable Web Push with a warning. With Tailscale, leave it empty: wherdr adopts the address `tailscale serve` publishes. |
20
+ | `TAILNET_REFRESH_MS` | `30000` | How often wherdr reads again what `tailscale serve` publishes for its port. |
21
+ | `HERDR_WEB_ALLOWED_HOSTS` | *(empty)* | Additional hostnames or IP addresses allowed to open the app, comma-separated. |
22
+ | `PASSKEY_USER` | `wherdr` | User name stored with the passkeys. |
23
+ | `DATA_DIR` | `./data` | VAPID keys, push subscriptions, passkeys, recent folders, and `settings.json`: the display settings that follow you across devices (theme, machine bar and groups, home list, Board and file browser preferences). Screen-dependent ones (content width, sidebar width, terminal size and rendering), the language, the last tab or filter and drafts stay in each browser. |
24
+ | `HERDR_BIN` | `~/.local/bin/herdr`, else `herdr` in `PATH` | Herdr binary. |
25
+ | `HERDR_WEB_SESSION` | *(default session)* | Named Herdr session to drive. Not `HERDR_SESSION`, which Herdr reads itself. |
26
+ | `HERDR_PROJECTS_DATA_DIR` | `~/.herdr-projects/data` | herdr-projects' data folder, where wherdr reads the `PATH` it recorded ([Agent PATH](installation.md#agent-path)). |
27
+ | `AGENT_KINDS` | all known agents | Agents offered in **New** (only installed ones are shown). |
28
+ | `HERDR_WEB_MACHINES` | `on` | `off` to ignore the SSH machines registered in Herdr. |
29
+ | `HERDR_WEB_SELF_HOSTS` | | Other names / IPs of this machine, comma-separated (profiles pointing to it are ignored). |
30
+ | `HERDR_WEB_REMOTE_SESSION` | | Herdr session to use on every remote machine instead of the profile's. |
31
+ | `HERDR_WEB_HERDR_NOTIFICATIONS` | `on` | `off` to stop relaying `herdr notification show` as push. |
32
+ | `UPLOAD_DIR` | `~/.cache/herdr-web/uploads` | Where photos sent to agents are stored (deleted after 7 days). |
33
+ | `ATTACH_DIR` | `~/.cache/herdr-web/files` | Where other files attached to messages are stored, on the agent's machine (mode 600, deleted after 7 days). |
34
+ | `TZ` | `UTC` | Time zone. |
35
+
36
+ In the app, **Settings** holds display preferences such as theme, typing effect and what the
37
+ home screen shows; these follow you across devices through `settings.json`. Language,
38
+ notifications, terminal text size and renderer remain device-specific. The passkey lock is
39
+ managed under Settings › Security.
@@ -0,0 +1,132 @@
1
+ # Conversation and replies
2
+
3
+ [Documentation](README.md) · [Project](../README.md)
4
+
5
+ - **Conversation view**: the agent's real transcript (Claude Code, Codex and omp), rendered as
6
+ Markdown, with grouped tool calls, images (full-screen viewer with pinch / wheel zoom and pan), timestamps, search and infinite scroll back to the
7
+ first message. Reading a conversation never touches the terminal, so it never resizes a pane.
8
+ A command the agent proposes (shell code block, or inline `! command`) can be copied without
9
+ its prompt, or run in the agent's shell mode (`!`, Claude Code, Codex and omp) after you
10
+ confirm the full command.
11
+ - **Interactive agent screens**: in a conversation, an uncertain menu or panel opens the
12
+ pane's real terminal in a modal window, with arrows, Enter, Escape, Tab, digits and y/n.
13
+ The rest of the app waits behind a scrim (the window fills the screen on a phone); in a
14
+ split, only the cell in use opens it. It closes after the agent's message field returns.
15
+ Close it yourself at any time with its button or a click on the scrim: that releases the
16
+ terminal without pressing Escape, which goes to the agent, and the same interaction stays
17
+ closed until you reopen it. Existing native questions, approvals, menus, waiting screens and
18
+ Claude settings cards keep their controls. The window is a fallback after those
19
+ recognizers, with two explicit exceptions: Codex's two-column `/usage` menu and
20
+ its Agent Command Center. The slash menu still lists and sends commands. On a phone, the window
21
+ temporarily fits the real pane to its width and restores its size on release, using
22
+ the same lease as Terminal view; it does not shrink 120 columns into unreadable text.
23
+ A pane already shown in Terminal keeps its existing live view. Try `/usage` on the
24
+ Codex agent in the browser demo (scripted, no account data).
25
+ In the compact list, native questions keep their preview and one-tap answers.
26
+ Unrecognized blocking screens offer an **Open interactive terminal** button.
27
+ - **Composer**: send messages while the agent works (queued, cancellable: the agent's own
28
+ queue when it takes them, else held by wherdr and sent when the turn ends; never left
29
+ half-typed in its field; a message pulled back out of Claude's queue before it read it, or not seen after an hour, is
30
+ marked “Not sent” with Retry / Cancel, and “Not sent” clears once the message shows in its transcript), attach or paste
31
+ photos and the files the agent can read (Claude Code: PDFs, notebooks, text and code of any
32
+ extension; Codex: notebooks, text and code), run slash commands (`/compact`, `/clear`, `/context`, `/usage`…) and see the output
33
+ of local commands. Stop button while the agent works. When Claude Code suggests a reply
34
+ (grayed-out in the empty field), `Tab` takes it on a computer and **Use**, inside the field on
35
+ its right, on a phone: the field gets the text, to edit or send. A long pasted text (log, output) becomes
36
+ a "Pasted text · N lines" card, sent to the agent as it is and shown the same way in the
37
+ conversation, where it opens in full with Copy; long typed messages fold with Show more.
38
+ The draft (text, quotes, attachments) is kept per agent, across reloads: when Herdr closes a
39
+ pane and opens a new one for the same agent (the same conversation, or the same herdr-projects
40
+ coordinator or task, as after `coordinator restart`), the view moves to the new pane and the
41
+ draft comes along. A pane closed for good keeps it under its banner, with **Copy draft**.
42
+ - **Model and effort pickers** for Claude Code, Codex and omp (omp: its
43
+ "Switch Model" selector, `/switch` or `/model`, and its thinking level, changed with its own
44
+ ⇧⇥ cycle). Changes apply **to the current session only**; wherdr never changes your default
45
+ model.
46
+ **Settings › Conversation › Reply style** chooses how an agent's reply offers to be quoted in
47
+ the field, question by question and point by point (a list item or a paragraph that asks
48
+ nothing), so that one message answers them all:
49
+
50
+ | Style | A question | A point |
51
+ | --- | --- | --- |
52
+ | **Icon** (default) | A small `↳` after it, in the middle or at the end of the message. | A grey `↳` at its end: on hover on a computer, always there and pale on a phone. |
53
+ | **Tap the text** | No button: the question is underlined, tap or click it. | Click it on a computer. On a phone, tap it, then **↳ Discuss**: a single tap never quotes, so reading, scrolling and selecting text stay as they are. |
54
+ | **List under the message** | A number after it, and the questions listed under the message. | **+ Quote a point** under the message, then the point. Offered when the reply has a list item to quote, or two points or more: not under one paragraph of prose. |
55
+
56
+ Every one of these is a button reachable with the keyboard (`Tab`, then `Enter`), and selecting a
57
+ passage still offers **Reply** on it. A quoted question or point shows `✓`.
58
+
59
+ **One syntax for every reference.** Whatever you reply to, the field gets one line that names it,
60
+ and your answer goes on the lines below:
61
+
62
+ ```
63
+ ↳ Quote message 11:37 ~k3f : I can merge the PR —
64
+ Go ahead.
65
+ ↳ Quote point 11:37 ~k3f : Shall I tag the release today? —
66
+ Yes
67
+ ↳ Quote decision 11:37 #3 ~k3f : Publish the release notes on the site? —
68
+ No
69
+ ```
70
+
71
+ | Line | Written by |
72
+ | --- | --- |
73
+ | `↳ Quote message <time> ~<code> : <start of the message> —` | **Reply** under an agent message. |
74
+ | `↳ Quote point <time> ~<code> : <excerpt> —` | `↳` on a question or a point, **Reply** on a selected passage. |
75
+ | `↳ Quote decision <time> #<n> ~<code> : <question> —` | **Yes**, **No** or `↳` on a row of a decision table. |
76
+ | `↳ Quote decisions <time> #<rows> ~<code> : <questions> —` | **OK to all** on a decision table. |
77
+
78
+ - The time is the one shown on the agent's message, so an answer to an earlier message is never
79
+ read as an answer to the last one. The types are the same words in every language.
80
+ - The code after `~` is three characters wherdr derives from the message (and the rank of the
81
+ table, from the second table of a message on). It tells apart two messages of the same minute
82
+ and two tables of one message, whatever the excerpt shows. The field draws it dimmed, like
83
+ the words before the excerpt; the quote of a sent message leaves it out. The rows of **OK to
84
+ all** are the numbers the table really has: `#1-4`, or `#1,4` when rows 2 and 3 do not exist.
85
+ - A reference is a whole line: it starts with `↳` in the first column and ends with ` —` at the
86
+ end of the line, and only there, so an excerpt may hold dashes of its own. The excerpt is plain
87
+ text on one line; a long one is cut with `…` (a message keeps its start, a passage its start
88
+ and its end).
89
+ - Several references fit in one message, each followed by its answer.
90
+ - Anything else is your own text: a `>` at the start of a line, a `↳` line of an unknown type or
91
+ with words after its dash. Text you paste never becomes a reference either: a pasted line that
92
+ reads like one gets a `\` before its `↳`. A long paste, shown as a **Pasted text** card, is
93
+ sent exactly as it was pasted.
94
+ - In the conversation, each reference of a sent message shows as a quote; tap it to see the
95
+ message it names. Messages sent earlier with `> ` lines still show as quotes.
96
+
97
+ **Settings › Conversation › Quoted replies** chooses how the field shows these lines: **Tokens,
98
+ native field** (default) draws each one as a token in the usual field, **Plain text** shows the
99
+ same lines as text, a fallback if the tokens misbehave. The message sent is the same.
100
+
101
+ A **closed question**, one that yes or no answers in full, also gets **Yes** and **No** next to
102
+ its `↳` (at the end of its row in the list style). A tap refers to the question and writes the
103
+ answer under it, in the language of the interface, exactly as Reply and typing would; nothing is sent, so several questions can be
104
+ answered in a row before sending. On a computer a click hands the field the focus, the caret
105
+ right after the answer, so Enter sends it at once; the keyboard stays down on a phone, and a
106
+ button pressed with the keyboard keeps the focus. Tapping the other answer
107
+ replaces the first; words you typed under a quote are never replaced. The rule is cautious, and
108
+ in doubt only Reply is offered: a single sentence that opens like a yes/no question (`Shall I…`,
109
+ `Do you…`, `Is it…`, `Want me to…`, `Est-ce que…`, `Je lance… ?`, `On…`, `Dois-je…`) or ends
110
+ with `, OK?` / `, d'accord ?`, with no alternative (`or`, `ou`), no interrogative word (`which`,
111
+ `how`, `quel`, `comment`…) and no negation.
112
+
113
+ A **decision table**, a Markdown table whose rows are numbered questions as a coordinator writes
114
+ them, gets a panel right under it: **OK to all** refers to the whole table and writes `OK to all`
115
+ under it (a second tap takes it back), and each row has **Yes**, **No** and `↳`, which refer to
116
+ the row by its number and write `Yes` or `No` under it, or nothing for an answer in words; a row
117
+ that asks an open question has `↳` alone. Every answer names the message and the row, even for
118
+ the last message: the agent may write another one before you send. In French: `OK tout`, `Oui`,
119
+ `Non`. Here too everything is composed in the field and you send; on a computer the field takes the focus
120
+ after a click, so Enter sends. A table qualifies when it has a
121
+ number column (a header `#`, `N°`, `No`, `Num`, `ID` or `Q` over short numbers, each once) and a
122
+ question column, known by its header (`Question`, `Decision`, `Choix`…), by cells that all end
123
+ with `?`, or by an advice column next to it (`Avis`, `Recommendation`, `Suggestion`…). Any other
124
+ table is left as it is.
125
+
126
+ Above the field, **N questions unanswered** counts the questions of the agent's last message
127
+ (and the rows of its decision tables) that your draft does not answer yet; tap it to scroll to
128
+ the first one. A question counts once it is quoted, a row once it is answered, quoted or covered
129
+ by **OK to all**; when the message asks one thing only, any words you type answer it. The line
130
+ goes when everything is answered and when you send, and it never shows for earlier messages,
131
+ while the agent is working, or while it waits on a prompt. It hangs from the top edge of the
132
+ field, so nothing moves when it comes or goes.
@@ -0,0 +1,38 @@
1
+ # Development and tests
2
+
3
+ [Documentation](README.md) · [Project](../README.md)
4
+
5
+ ### From source
6
+
7
+ For development, or to run a checkout of your own. With Herdr running, Git and Node.js 22 on the same machine:
8
+
9
+ ```sh
10
+ git clone https://github.com/afloury/wherdr.git
11
+ cd wherdr
12
+ npm ci
13
+ npm run build
14
+ npm start # listens on 127.0.0.1:7683
15
+ ```
16
+
17
+ Open `http://localhost:7683` in a browser on that computer: the desktop layout, passkeys and the
18
+ installable app work there, since browsers treat `localhost` as secure. There is no phone access
19
+ and no push notification in this setup; for that, use the [recommended setup](networks.md#recommended-always-on-server--tailscale) (or publish this
20
+ instance with `tailscale serve` as described there and start it with
21
+ `APP_URL=https://server.example.ts.net:7683/ npm start`).
22
+
23
+ Run it as the user who runs Herdr. It uses `$HOME` and `$HOME/.local/bin/herdr`, or `herdr` from
24
+ the `PATH` (Homebrew); set `HERDR_BIN` otherwise. `DATA_DIR` holds passkeys, push data and recent
25
+ folders (default `./data`). `npm start` listens on `127.0.0.1` (`HOST`) and port `7683` (`PORT`).
26
+ The first-passkey bootstrap token is printed in its output. Keep the process running with your
27
+ usual service manager (systemd user unit, launchd, tmux…).
28
+
29
+ With `APP_URL` empty or `http://localhost:7683/`, wherdr starts normally but disables Web Push
30
+ and logs a warning.
31
+
32
+ ## Contributing
33
+
34
+ See [CONTRIBUTING.md](../CONTRIBUTING.md), including the [agent test rule](../CONTRIBUTING.md#agent-test-rule)
35
+ and `npm run test:affected -- --base origin/v2 --dry-run`. Changes are listed in [CHANGELOG.md](../CHANGELOG.md).
36
+
37
+ Every commit is public: a leak check (gitleaks plus your own forbidden patterns) covers the files
38
+ and the commits about to be pushed; see [Leak check](../CONTRIBUTING.md#leak-check).