wherdr 1.3.2 → 1.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/_nuxt/{AgentView.C4YOwvZG.css → AgentView.DzFWBd2A.css} +1 -1
  3. package/.output/public/_nuxt/{Cd8j9O5w.js → BEJHMUrj.js} +1 -1
  4. package/.output/public/_nuxt/BOtcEDnA.js +1 -0
  5. package/.output/public/_nuxt/BUaYhQ2r.js +6 -0
  6. package/.output/public/_nuxt/{yzABg5xl.js → Bpoxvzh6.js} +1 -1
  7. package/.output/public/_nuxt/C25ROUa9.js +3 -0
  8. package/.output/public/_nuxt/CDWjMk9C.js +2 -0
  9. package/.output/public/_nuxt/CJKsMzIp.js +1 -0
  10. package/.output/public/_nuxt/CJNhn9sA.js +36 -0
  11. package/.output/public/_nuxt/COCvtdHN.js +89 -0
  12. package/.output/public/_nuxt/{Ci8N4mWR.js → CXJnLmWv.js} +1 -1
  13. package/.output/public/_nuxt/Cl45J6_Q.js +1 -0
  14. package/.output/public/_nuxt/CndPDbMI.js +2 -0
  15. package/.output/public/_nuxt/Ctbx58Um.js +23 -0
  16. package/.output/public/_nuxt/{8ksjcuDu.js → DMLmW6JM.js} +49 -56
  17. package/.output/public/_nuxt/Dl1PHLOB.js +1 -0
  18. package/.output/public/_nuxt/Nhex3_iH.js +1 -0
  19. package/.output/public/_nuxt/OpWX45i7.js +89 -0
  20. package/.output/public/_nuxt/builds/latest.json +1 -1
  21. package/.output/public/_nuxt/builds/meta/4994f3a4-4126-4f57-a9e5-c7ebb25850bc.json +1 -0
  22. package/.output/public/_nuxt/dTj21DMs.js +1 -0
  23. package/.output/public/_nuxt/entry.BohTWE-n.css +2 -0
  24. package/.output/public/_nuxt/kwSoIiM7.js +1 -0
  25. package/.output/public/_nuxt/mkEwYka4.js +1 -0
  26. package/.output/public/_nuxt/pdf.min.t82Z80JU.mjs +28 -0
  27. package/.output/public/_nuxt/pdf.worker.min.wgc6bjNh.mjs +28 -0
  28. package/.output/public/_nuxt/w7Rm7unj.js +1 -0
  29. package/.output/public/sw.js +1 -1
  30. package/.output/server/chunks/_/branding.mjs +1 -1
  31. package/.output/server/chunks/_/filePaths.mjs +25 -0
  32. package/.output/server/chunks/_/files.mjs +217 -0
  33. package/.output/server/chunks/_/machineOrder.mjs +1 -1
  34. package/.output/server/chunks/_/onboarding.mjs +1 -1
  35. package/.output/server/chunks/_/package.mjs +5 -2
  36. package/.output/server/chunks/_/pluginPolicy.mjs +93 -0
  37. package/.output/server/chunks/_/plugins.mjs +9 -96
  38. package/.output/server/chunks/_/projectBoard.mjs +124 -36
  39. package/.output/server/chunks/_/projectDocs.mjs +106 -0
  40. package/.output/server/chunks/_/projectInbox.mjs +135 -0
  41. package/.output/server/chunks/_/projectThreads.mjs +46 -0
  42. package/.output/server/chunks/_/projectThreads2.mjs +61 -0
  43. package/.output/server/chunks/_/projectsActions.mjs +1 -1
  44. package/.output/server/chunks/_/projectsPlugin.mjs +24 -50
  45. package/.output/server/chunks/_/projectsPlugin2.mjs +57 -0
  46. package/.output/server/chunks/_/restart.mjs +2 -312
  47. package/.output/server/chunks/_/reveal.mjs +2 -24
  48. package/.output/server/chunks/_/selfupdate.mjs +3 -2
  49. package/.output/server/chunks/_/settingstabs.mjs +36 -0
  50. package/.output/server/chunks/_/updates.mjs +51 -10
  51. package/.output/server/chunks/_/worktrees.mjs +1 -1
  52. package/.output/server/chunks/_/ws.mjs +1 -1
  53. package/.output/server/chunks/nitro/nitro.mjs +1718 -417
  54. package/.output/server/chunks/raw/bump-homebrew.mjs +1 -1
  55. package/.output/server/chunks/raw/herdr-plugin.mjs +1 -1
  56. package/.output/server/chunks/raw/release-ready.mjs +5 -0
  57. package/.output/server/chunks/routes/api/_..._.mjs +1 -1
  58. package/.output/server/chunks/routes/api/agents.post.mjs +1 -1
  59. package/.output/server/chunks/routes/api/ask-tab.post.mjs +1 -1
  60. package/.output/server/chunks/routes/api/attach.post.mjs +1 -1
  61. package/.output/server/chunks/routes/api/auth/disable.post.mjs +1 -1
  62. package/.output/server/chunks/routes/api/auth/lock-all.post.mjs +1 -1
  63. package/.output/server/chunks/routes/api/auth/lock.post.mjs +1 -1
  64. package/.output/server/chunks/routes/api/auth/login/options.post.mjs +1 -1
  65. package/.output/server/chunks/routes/api/auth/login/verify.post.mjs +1 -1
  66. package/.output/server/chunks/routes/api/auth/max-session.post.mjs +1 -1
  67. package/.output/server/chunks/routes/api/auth/register/options.post.mjs +1 -1
  68. package/.output/server/chunks/routes/api/auth/register/verify.post.mjs +1 -1
  69. package/.output/server/chunks/routes/api/auth/status.get.mjs +1 -1
  70. package/.output/server/chunks/routes/api/board.get.mjs +148 -0
  71. package/.output/server/chunks/routes/api/changes.get.mjs +2 -2
  72. package/.output/server/chunks/routes/api/chat/image.get.mjs +2 -2
  73. package/.output/server/chunks/routes/api/chat.get.mjs +26 -6
  74. package/.output/server/chunks/routes/api/choose.post.mjs +40 -14
  75. package/.output/server/chunks/routes/api/claude-statusline.post.mjs +2 -2
  76. package/.output/server/chunks/routes/api/close/status.get.mjs +2 -2
  77. package/.output/server/chunks/routes/api/close.post.mjs +1 -1
  78. package/.output/server/chunks/routes/api/codex-update.post.mjs +2 -2
  79. package/.output/server/chunks/routes/api/commands.get.mjs +4 -3
  80. package/.output/server/chunks/routes/api/config.get.mjs +3 -2
  81. package/.output/server/chunks/routes/api/dirs.get.mjs +2 -2
  82. package/.output/server/chunks/routes/api/dismiss-stopped.post.mjs +43 -0
  83. package/.output/server/chunks/routes/api/dismiss.post.mjs +2 -2
  84. package/.output/server/chunks/routes/api/effort.post.mjs +2 -2
  85. package/.output/server/chunks/routes/api/efforts.get.mjs +2 -2
  86. package/.output/server/chunks/routes/api/file.post.mjs +2 -2
  87. package/.output/server/chunks/routes/api/files/download.get.mjs +60 -0
  88. package/.output/server/chunks/routes/api/files/read.get.mjs +45 -0
  89. package/.output/server/chunks/routes/api/files.get.mjs +44 -0
  90. package/.output/server/chunks/routes/api/gitroot.get.mjs +2 -2
  91. package/.output/server/chunks/routes/api/health.get.mjs +1 -1
  92. package/.output/server/chunks/routes/api/index.get.mjs +2 -1
  93. package/.output/server/chunks/routes/api/input.post.mjs +32 -5
  94. package/.output/server/chunks/routes/api/interrupt.post.mjs +2 -2
  95. package/.output/server/chunks/routes/api/isgit.get.mjs +2 -2
  96. package/.output/server/chunks/routes/api/machine/awake.get.mjs +2 -2
  97. package/.output/server/chunks/routes/api/machine/awake.post.mjs +2 -2
  98. package/.output/server/chunks/routes/api/machine/order.get.mjs +1 -1
  99. package/.output/server/chunks/routes/api/machine/order.post.mjs +1 -1
  100. package/.output/server/chunks/routes/api/machine/rename.post.mjs +2 -2
  101. package/.output/server/chunks/routes/api/menu.post.mjs +5 -2
  102. package/.output/server/chunks/routes/api/model.post.mjs +2 -2
  103. package/.output/server/chunks/routes/api/models.get.mjs +2 -2
  104. package/.output/server/chunks/routes/api/nav.post.mjs +36 -22
  105. package/.output/server/chunks/routes/api/onboarding.get.mjs +1 -1
  106. package/.output/server/chunks/routes/api/onboarding.post.mjs +1 -1
  107. package/.output/server/chunks/routes/api/phone.get.mjs +2 -2
  108. package/.output/server/chunks/routes/api/phone.post.mjs +2 -2
  109. package/.output/server/chunks/routes/api/plugins/actions.get.mjs +4 -1
  110. package/.output/server/chunks/routes/api/plugins/invoke.post.mjs +4 -1
  111. package/.output/server/chunks/routes/api/plugins/profiles.get.mjs +4 -1
  112. package/.output/server/chunks/routes/api/plugins/projects.get.mjs +4 -3
  113. package/.output/server/chunks/routes/api/plugins/projects.post.mjs +4 -3
  114. package/.output/server/chunks/routes/api/plugins/thread-limits.get.mjs +2 -2
  115. package/.output/server/chunks/routes/api/plugins/thread-limits.post.mjs +2 -2
  116. package/.output/server/chunks/routes/api/project/inbox.get.mjs +44 -0
  117. package/.output/server/chunks/routes/api/project/inbox.post.mjs +44 -0
  118. package/.output/server/chunks/routes/api/project/memory.get.mjs +43 -0
  119. package/.output/server/chunks/routes/api/project/report.get.mjs +3 -2
  120. package/.output/server/chunks/routes/api/project/routines.get.mjs +44 -0
  121. package/.output/server/chunks/routes/api/project/settings.get.mjs +42 -0
  122. package/.output/server/chunks/routes/api/project/thread.get.mjs +45 -0
  123. package/.output/server/chunks/routes/api/project/thread.post.mjs +47 -0
  124. package/.output/server/chunks/routes/api/prompt.post.mjs +21 -3
  125. package/.output/server/chunks/routes/api/push/quiet.post.mjs +2 -2
  126. package/.output/server/chunks/routes/api/push/subscribe.post.mjs +2 -2
  127. package/.output/server/chunks/routes/api/push/test.post.mjs +2 -2
  128. package/.output/server/chunks/routes/api/push/unsubscribe.post.mjs +2 -2
  129. package/.output/server/chunks/routes/api/quotas.get.mjs +2 -2
  130. package/.output/server/chunks/routes/api/rename.post.mjs +1 -1
  131. package/.output/server/chunks/routes/api/requeue.post.mjs +2 -2
  132. package/.output/server/chunks/routes/api/restart.get.mjs +1 -1
  133. package/.output/server/chunks/routes/api/restart.post.mjs +1 -1
  134. package/.output/server/chunks/routes/api/reveal.post.mjs +2 -1
  135. package/.output/server/chunks/routes/api/screen-key.post.mjs +14 -11
  136. package/.output/server/chunks/routes/api/screen.get.mjs +6 -37
  137. package/.output/server/chunks/routes/api/search.get.mjs +2 -2
  138. package/.output/server/chunks/routes/api/seen.post.mjs +2 -2
  139. package/.output/server/chunks/routes/api/sessions.get.mjs +2 -2
  140. package/.output/server/chunks/routes/api/sessions.post.mjs +2 -2
  141. package/.output/server/chunks/routes/api/settings-tab.post.mjs +89 -0
  142. package/.output/server/chunks/routes/api/space.post.mjs +14 -14
  143. package/.output/server/chunks/routes/api/state.get.mjs +2 -2
  144. package/.output/server/chunks/routes/api/unqueue.post.mjs +2 -2
  145. package/.output/server/chunks/routes/api/update/status.get.mjs +1 -1
  146. package/.output/server/chunks/routes/api/update.get.mjs +2 -2
  147. package/.output/server/chunks/routes/api/update.post.mjs +2 -2
  148. package/.output/server/chunks/routes/api/upload.post.mjs +2 -2
  149. package/.output/server/chunks/routes/api/worktrees/remove.post.mjs +1 -1
  150. package/.output/server/chunks/routes/api/worktrees.get.mjs +1 -1
  151. package/.output/server/chunks/routes/favicon.ico.get.mjs +1 -1
  152. package/.output/server/chunks/routes/icons/_name_.get.mjs +2 -2
  153. package/.output/server/chunks/routes/renderer.mjs +3 -3
  154. package/.output/server/chunks/routes/uploads/_...name_.get.mjs +2 -2
  155. package/.output/server/chunks/routes/ws/_..._.mjs +2 -2
  156. package/.output/server/chunks/routes/ws/events.mjs +2 -2
  157. package/.output/server/chunks/routes/ws/term.mjs +2 -2
  158. package/.output/server/chunks/virtual/precomputed.mjs +1 -1
  159. package/.output/server/index.mjs +2 -2
  160. package/.output/server/package.json +1 -1
  161. package/README.md +368 -40
  162. package/bin/install-docker-skill.sh +20 -0
  163. package/bin/lib/commands.mjs +5 -1
  164. package/bin/lib/core.mjs +1 -0
  165. package/bin/lib/install-skill.sh +100 -0
  166. package/bin/lib/skill.mjs +16 -0
  167. package/bin/lib/updater.mjs +65 -12
  168. package/bin/lib/verify-release.mjs +20 -0
  169. package/package.json +5 -2
  170. package/skills/wherdr/SKILL.md +186 -0
  171. package/.output/public/_nuxt/B7QP1TFs.js +0 -23
  172. package/.output/public/_nuxt/BDNMzG2s.js +0 -1
  173. package/.output/public/_nuxt/BOpBIziZ.js +0 -6
  174. package/.output/public/_nuxt/BWXdFfeg.js +0 -17
  175. package/.output/public/_nuxt/COFCNFpG.js +0 -83
  176. package/.output/public/_nuxt/CWwyK2XK.js +0 -2
  177. package/.output/public/_nuxt/CXG-cOdh.js +0 -1
  178. package/.output/public/_nuxt/CkZ8t6uB.js +0 -1
  179. package/.output/public/_nuxt/D4Yz4rat.js +0 -65
  180. package/.output/public/_nuxt/D7sxNXx1.js +0 -1
  181. package/.output/public/_nuxt/DViwOclv.js +0 -1
  182. package/.output/public/_nuxt/DoD7Qb5P.js +0 -30
  183. package/.output/public/_nuxt/DyBZDSCV.js +0 -2
  184. package/.output/public/_nuxt/SiL1FJ5s.js +0 -3
  185. package/.output/public/_nuxt/bLP7Jj-b.js +0 -1
  186. package/.output/public/_nuxt/builds/meta/7afbf062-5369-4002-b20d-7a582ff6e0f1.json +0 -1
  187. package/.output/public/_nuxt/entry.Crt1r4l3.css +0 -2
  188. package/.output/server/chunks/routes/ws/mirror.mjs +0 -161
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  <p align="center"><b>A complete workspace for the coding agents running in <a href="https://herdr.dev">Herdr</a>, on your
8
8
  computer and on your phone.</b></p>
9
9
 
10
- <p align="center"><a href="https://wherdr.dev"><b>wherdr.dev</b></a> · <code>curl -fsSL https://wherdr.dev/install | sh</code> · <code>herdr plugin install afloury/wherdr</code></p>
10
+ <p align="center"><a href="https://wherdr.dev"><b>wherdr.dev</b></a> · <a href="#ask-your-ai-agent">Ask your AI agent</a></p>
11
11
 
12
12
  <p align="center"><a href="https://wherdr.dev/demo/"><b>Try it in your browser — no install</b></a>: the real app on scripted agents, nothing runs.</p>
13
13
 
@@ -15,7 +15,20 @@ computer and on your phone.</b></p>
15
15
 
16
16
  ## Quick start
17
17
 
18
- On the computer that runs [Herdr](https://herdr.dev) (≥ 0.9.1), macOS or Linux, one command:
18
+ ### Ask your AI agent
19
+
20
+ **Recommended.** Paste this into Claude Code, Codex or any coding agent: it installs and sets up wherdr for you.
21
+
22
+ ```text
23
+ Read https://wherdr.dev/agent.md and help me set up wherdr. Check what is already installed first, and ask me before installing anything.
24
+ ```
25
+
26
+ It follows [our setup guide for agents](https://wherdr.dev/agent.md): checks what you already have,
27
+ asks before installing anything, sets up your phone over Tailscale, never exposes wherdr to the Internet.
28
+
29
+ ### Or run the installer yourself
30
+
31
+ On the computer that runs [Herdr](https://herdr.dev) (≥ 0.9.1), macOS or Linux:
19
32
 
20
33
  ```sh
21
34
  curl -fsSL https://wherdr.dev/install | sh
@@ -102,7 +115,8 @@ Details in [Features](#features) and [Security](#security).
102
115
  - [Features](#features)
103
116
  - [How it works](#how-it-works)
104
117
  - [Requirements](#requirements)
105
- - [Installation](#installation): [the one command](#the-one-command) ·
118
+ - [Installation](#installation): [ask your AI agent](#ask-your-ai-agent-1) ·
119
+ [or run the installer yourself](#the-one-command) ·
106
120
  [which setup?](#which-setup) ·
107
121
  [always-on server + Tailscale](#recommended-always-on-server--tailscale) ·
108
122
  [other private networks](#other-private-networks) ·
@@ -126,9 +140,12 @@ Details in [Features](#features) and [Security](#security).
126
140
 
127
141
  ### Everywhere
128
142
 
129
- - **Live agent list**, one line per Herdr space, grouped by state (your turn, working, ready),
130
- with a preview of each agent's last answer. When an agent asks for permission or asks a
131
- question, the options show on its card: **answer in one tap** without opening it.
143
+ - **Live agent list**, one line per Herdr space, grouped by state (your turn, working, ready).
144
+ The list is compact by default: agent, title, project badge and state. When an agent asks for
145
+ permission or asks a question, its card opens on the question and its options: **answer in one
146
+ tap** without opening it; the card is one line again once answered. Turn off Settings ›
147
+ Appearance › Home screen › **Compact list** for detailed cards, with the folder, the model and
148
+ a preview of each agent's last answer.
132
149
  - **Conversation view**: the agent's real transcript (Claude Code, Codex and omp), rendered as
133
150
  Markdown, with grouped tool calls, images (full-screen viewer with pinch / wheel zoom and pan), timestamps, search and infinite scroll back to the
134
151
  first message. Reading a conversation never touches the terminal, so it never resizes a pane.
@@ -136,7 +153,7 @@ Details in [Features](#features) and [Security](#security).
136
153
  its prompt, or run in the agent's shell mode (`!`, Claude Code, Codex and omp) after you
137
154
  confirm the full command.
138
155
  - **Terminal view**: the real terminal (xterm.js, WebGL or DOM renderer) with take-over. Opening
139
- it resizes the real pane to your screen; closing it gives the pane the size it had before
156
+ it resizes the real pane to your screen (or its cell in a split); closing it gives the pane the size it had before
140
157
  (after 30 seconds when the connection just dropped, e.g. a locked phone), unless a Herdr
141
158
  client attached meanwhile laid it out its own way. On a
142
159
  computer, drag over the text on screen to select it: releasing the button copies it, as do
@@ -146,6 +163,22 @@ Details in [Features](#features) and [Security](#security).
146
163
  line wrapped by the width is copied in one piece, without the breaks between its rows. An image
147
164
  pasted with `⌘V` (Mac), here or in a side-by-side terminal, goes to the agent's machine and its
148
165
  path is pasted, which omp and Claude Code attach as an image, as in the conversation.
166
+ - **Interactive agent screens**: in a conversation, an uncertain menu or panel opens the
167
+ pane's real terminal in a modal window, with arrows, Enter, Escape, Tab, digits and y/n.
168
+ The rest of the app waits behind a scrim (the window fills the screen on a phone); in a
169
+ split, only the cell in use opens it. It closes after the agent's message field returns.
170
+ Close it yourself at any time with its button or a click on the scrim: that releases the
171
+ terminal without pressing Escape, which goes to the agent, and the same interaction stays
172
+ closed until you reopen it. Existing native questions, approvals, menus, waiting screens and
173
+ Claude settings cards keep their controls. The window is a fallback after those
174
+ recognizers, with two explicit exceptions: Codex's two-column `/usage` menu and
175
+ its Agent Command Center. The slash menu still lists and sends commands. On a phone, the window
176
+ temporarily fits the real pane to its width and restores its size on release, using
177
+ the same lease as Terminal view; it does not shrink 120 columns into unreadable text.
178
+ A pane already shown in Terminal keeps its existing live view. Try `/usage` on the
179
+ Codex agent in the browser demo (scripted, no account data).
180
+ In the compact list, native questions keep their preview and one-tap answers.
181
+ Unrecognized blocking screens offer an **Open interactive terminal** button.
149
182
  - **Composer**: send messages while the agent works (queued, cancellable), attach or paste
150
183
  photos and the files the agent can read (Claude Code: PDFs, notebooks, text and code of any
151
184
  extension; Codex: notebooks, text and code), run slash commands (`/compact`, `/clear`, `/context`, `/usage`…) and see the output
@@ -159,6 +192,20 @@ Details in [Features](#features) and [Security](#security).
159
192
  resumes the same conversation (only while Codex is idle). Codex's own weekly-limit warning
160
193
  (its footer gauge, or its startup heads-up) is repeated above the field, with its values, while
161
194
  Codex shows it.
195
+ - **After Codex updates itself and exits**: a **Your turn** card offers **Restart Codex**
196
+ for a new conversation, with the original launch arguments. For an existing conversation,
197
+ choose **Resume conversation** (its exact session, with the original options) or **Start
198
+ fresh**. If wherdr cannot identify the session, Resume opens Codex's picker rather than
199
+ choosing another pane's latest conversation. The usual attention notification applies.
200
+ Nothing restarts automatically: the pane must still show the same empty shell prompt,
201
+ with the shell in the foreground. Unrecognized shell prompts require a manual restart
202
+ in the terminal. wherdr must have observed Codex before it exited.
203
+ **Dismiss** puts the card away for good: the pane is a plain shell again, to use as you like.
204
+ Project panel messages wait in the queue until the agent returns; if it does not (Dismiss, or
205
+ a Codex that simply left), their text goes back into the pane's message field. Continuation
206
+ prompts (unfinished quotes or heredocs) refuse a restart too. If the final
207
+ transcript read fails, both conversation choices remain available; a session
208
+ contradicted by a guessed match is resumed through Codex's picker.
162
209
  - **Model and effort pickers** for Claude Code, Codex and omp (omp: its
163
210
  "Switch Model" selector, `/switch` or `/model`, and its thinking level, changed with its own
164
211
  ⇧⇥ cycle). Changes apply **to the current session only**; wherdr never changes your default
@@ -166,6 +213,30 @@ Details in [Features](#features) and [Security](#security).
166
213
  - **New agent**: pick an installed agent (or a plain terminal), a folder, optionally a separate
167
214
  Git **worktree** and branch, resume the last conversation, and queue a first message.
168
215
  - **Changes view**: Git status and diff of an agent's working folder; worktree management.
216
+ Review the diff like a pull request: comment on one line or on a **block of lines**. The code
217
+ itself is plain text — a click on it does nothing, so it can be selected and copied.
218
+ - **Mouse**: a **+** appears in the gutter of the hovered line; click it to comment that line,
219
+ or press it and drag over other lines to comment the block. With an editor open, Shift+click
220
+ another line to change its block.
221
+ - **Touch**: tap a line number to choose the line, tap another line to extend the block, then
222
+ **Comment** in the bar pinned at the bottom. Nothing is written by the first tap.
223
+ - **Keyboard**: one tab stop per file; arrow keys move between lines, Shift+arrows choose a
224
+ block, Enter opens the editor. In the editor, ⌘/Ctrl+Enter saves and Escape cancels (a second
225
+ Escape if text would be lost); the window stays open.
226
+
227
+ A block stays within one hunk (the other hunks dim while it is chosen) and may mix deleted and
228
+ new lines. Each comment is a thread under the last line of its block, headed by its lines
229
+ ("Lines 12–18"), with **Edit** and a two-step **Delete**; the lines it covers are marked in
230
+ the gutter. Comments, including the text of an editor left open, are saved on this device for
231
+ that agent, across refreshes and reloads. A block that leaves the diff, or whose code changed
232
+ between its first and last lines, is flagged above the diff and keeps the excerpt that was
233
+ commented.
234
+ **Send review** stays pinned with the number of comments; it groups them by file as
235
+ `file:12-18 — remark` (`file:12` for one line) followed by a short excerpt of the block, and
236
+ appends them to the conversation's message draft, preserving existing text; it never sends a
237
+ message. Deleted lines use the old file's numbers, explicitly labelled. **Discard** clears the
238
+ local review. Works on remote agents and in the demo too, with no writes to the agent's
239
+ machine. Browser storage must be available to retain comments after closing the view.
169
240
  - **Several machines**: agents of the SSH machines registered in Herdr (`herdr machine add`)
170
241
  appear in their own section; everything works the same on a remote agent.
171
242
  - **Named Herdr sessions**, **quotas** (remaining Claude and Codex usage limits), **Herdr plugin
@@ -176,7 +247,10 @@ Details in [Features](#features) and [Security](#security).
176
247
  ### On a computer
177
248
 
178
249
  - **Split panes, live**: a tab with several panes is drawn with Herdr's real layout; every pane
179
- shows its conversation or terminal live, and the one you click becomes interactive.
250
+ shows its conversation or terminal live. Every visible terminal fills its cell and follows
251
+ window and divider resizing, keeping its instance and connection when focus changes.
252
+ Click a cell to give it the keyboard. Leaving the tab restores each terminal's original size,
253
+ unless a Herdr client has resized it meanwhile.
180
254
  - **Rearrange the layout**: drag a pane onto another to move it, drag a divider to resize
181
255
  (arrow keys work on a focused divider); changes go to Herdr itself.
182
256
  - **Spaces and tabs**: sidebar with every space, tabs at the top, active tab remembered per space.
@@ -185,7 +259,8 @@ Details in [Features](#features) and [Security](#security).
185
259
  - **Keyboard shortcuts** (`Mod` is ⌘ on macOS, Ctrl elsewhere; `Mod+/` or `?` lists them all,
186
260
  also in Settings › Computer):
187
261
  - `Ctrl/⌘+K` global search across agents and conversations, `Alt+↑/↓` previous / next agent
188
- in the list, `Mod+,` settings.
262
+ in the list, `Mod+,` settings, `H` the [Board](#works-great-with-herdr-projects) (outside a
263
+ text field and the terminal).
189
264
  - `Mod+Alt+N` new agent in a new space, `Mod+Alt+T` new tab in the current space,
190
265
  `Mod+Alt+W` close the current pane (after confirmation). They work from the terminal too.
191
266
  - With [herdr-projects](#works-great-with-herdr-projects) on the agent's machine: `Mod+Alt+P`
@@ -198,10 +273,16 @@ Details in [Features](#features) and [Security](#security).
198
273
  and `Shift+Enter` adds a new line. On a "Your turn" card, `1`–`9` pick an option (on AZERTY
199
274
  without Shift too, outside the message field); on the `/resume` card, `Ctrl+A` switches
200
275
  between every project and the current one (`⌘A` still selects all on macOS).
276
+ - In the message field, `↑` on the first line recalls previous messages and slash commands;
277
+ `↓` on the last line returns to newer entries, then restores your draft. History keeps the
278
+ last 100 texts sent from this device per agent, without attachments or quoted references.
201
279
  - **Project board** for [herdr-projects](#works-great-with-herdr-projects): coordinator and threads grouped
202
280
  under their project, and a side panel with the project's task lists (to test, to decide,
203
281
  to review, in progress, in queue, blocked, to do, backlog — each optional) and one-click
204
282
  replies to the coordinator.
283
+ - **Board**: every agent, and with herdr-projects every project, thread and task, in four columns
284
+ (Blocked, Todo, Ongoing, Finished). Drag a task card to another column, or use its **Move
285
+ to…** menu, to ask the coordinator to move it.
205
286
  - **Settings** in a sidebar, with desktop-only options such as the content width.
206
287
 
207
288
  ### On a phone
@@ -231,7 +312,10 @@ phone / laptop ──private network──> HTTPS (tailscale serve, private prox
231
312
 
232
313
  wherdr runs on the same machine as the Herdr server (the "server" below). It uses Herdr's local
233
314
  socket API and CLI, reads the agents' transcript files, and serves a client-only Nuxt app. Data
234
- it keeps (VAPID keys, push subscriptions, passkeys, recent folders) lives in `data/`.
315
+ it keeps (VAPID keys, push subscriptions, passkeys, recent folders) lives in `data/`. So do the
316
+ long texts pasted into the message field, which the server keeps to show them as cards on every
317
+ device: `data/pastes.json`, in clear, readable by the server's user only (mode 600), at most the
318
+ last 100 texts and 2 MB, each one deleted 30 days after it was last sent.
235
319
 
236
320
  Built with Nuxt 4, Nuxt UI 4, Tailwind 4 and TypeScript; the Herdr gateway (API, WebSockets,
237
321
  Web Push, lock) runs in Nitro.
@@ -252,7 +336,20 @@ Web Push, lock) runs in Nitro.
252
336
 
253
337
  ## Installation
254
338
 
255
- ### The one command
339
+ ### Ask your AI agent
340
+
341
+ **Recommended.** Paste this into Claude Code, Codex or any coding agent: it installs and sets up wherdr for you.
342
+
343
+ ```text
344
+ Read https://wherdr.dev/agent.md and help me set up wherdr. Check what is already installed first, and ask me before installing anything.
345
+ ```
346
+
347
+ It follows [our setup guide for agents](https://wherdr.dev/agent.md): checks what you already have,
348
+ asks before installing anything, sets up your phone over Tailscale, never exposes wherdr to the Internet.
349
+
350
+ <a id="the-one-command"></a>
351
+
352
+ ### Or run the installer yourself
256
353
 
257
354
  On the computer that runs Herdr, as your user, on macOS or Linux:
258
355
 
@@ -289,7 +386,7 @@ Settings, as environment variables (`curl -fsSL https://wherdr.dev/install | WHE
289
386
  | `WHERDR_MODE` | — | `native`: Node.js even when Docker is there. `docker`: no plugin, Docker Compose by hand in `WHERDR_DIR` (Linux; see below). |
290
387
  | `WHERDR_YES` | — | `1` answers yes to every question (non-interactive use). |
291
388
  | `WHERDR_NO_BROWSER` | — | `1` never opens a browser. |
292
- | `WHERDR_REF` | latest | Git tag or branch of the plugin (or of `docker-compose.yml` with `WHERDR_MODE=docker`). |
389
+ | `WHERDR_REF` | main | Git tag or branch of the plugin (or of `docker-compose.yml` with `WHERDR_MODE=docker`). |
293
390
  | `WHERDR_PLUGIN` | `afloury/wherdr` | A local checkout to link and build instead (development, tests). |
294
391
 
295
392
  **Docker by hand, with the script:** `curl -fsSL https://wherdr.dev/install | WHERDR_MODE=docker sh`
@@ -615,8 +712,8 @@ setup by itself:
615
712
  `~/wherdr` (`docker-compose.yml`, `.env`), the same files as `WHERDR_MODE=docker` of
616
713
  [the one command](#the-one-command).
617
714
  - **Node.js 22** everywhere else, and always on macOS (Docker Desktop cannot reach Herdr's
618
- socket): the plugin downloads the prebuilt npm package of its version (or builds wherdr in its
619
- own folder when that fails), copies it to `~/wherdr/app` and runs it detached from there, with
715
+ socket): the plugin downloads the prebuilt package of its version from GitHub Releases and
716
+ verifies its SHA-256 checksum, copies it to `~/wherdr/app` and runs it detached from there, with
620
717
  its pid and log (`wherdr.log`) in `~/wherdr`. Herdr builds plugins in a temporary folder and
621
718
  then moves them, so the server never runs from the plugin folder. Bun works too when Node.js 22
622
719
  is missing. Without either, the install stops and says so.
@@ -738,6 +835,27 @@ home screen and in Settings › About, with the release notes and the exact comm
738
835
  Hide it until the next version with ×. Set `WHERDR_UPDATE_CHECK=off` to disable the check. The
739
836
  installed version is shown in Settings › About.
740
837
 
838
+ GitHub release packages (including the bundled agent skill), Docker images, and Homebrew
839
+ updates are published without waiting for npm moderation. Native plugin installs and updates
840
+ use the GitHub `.tgz` and verify its SHA-256 checksum before extraction. A failed one-tap
841
+ download or checksum check leaves the running version in place. Plugin installation tries
842
+ GitHub first, then the prebuilt npm package of the exact same version (with its registry integrity hash), and only builds from source when neither works.
843
+ This also keeps older 1.3.x releases without GitHub archives installable with Node.js or Bun.
844
+ Packages predating the bundled skill retain the plugin checkout's commands and skill, so
845
+ skill refresh, installation and uninstallation remain available.
846
+ The installer fetches `main` explicitly unless you set `WHERDR_REF`.
847
+
848
+ The SHA-256 checksum detects damaged downloads. It is served beside the archive, so someone
849
+ who can replace both files can make them match; it does not prove the publisher’s identity
850
+ or protect against replacement of the archive and checksum together.
851
+
852
+ `npm install -g`, `npx`, `bunx` and `pnpm dlx` still need npm to serve the wherdr package.
853
+ Their banner waits for registry availability; Homebrew's banner waits for its formula.
854
+ Versions through 1.3.2 use GitHub's `latest` marker and an npm-based updater. That marker only
855
+ advances once npm **and** Homebrew are ready, so their existing Update button continues to work.
856
+ To update an older native plugin earlier, rerun the installer or press **U** in its Herdr panel.
857
+ See [Releasing](docs/RELEASING.md) for the publication order and recovery steps.
858
+
741
859
  **Update in one tap.** When wherdr runs from the Herdr plugin (Node.js mode), a global npm install
742
860
  or Homebrew, the banner has an **Update** button instead of the command, for a session opened on
743
861
  this computer (`localhost`) or unlocked with a passkey. wherdr installs the new version in a
@@ -749,7 +867,7 @@ and the app says so. Every step is logged in `~/wherdr/update.log`.
749
867
 
750
868
  | Setup | What Update does |
751
869
  | --- | --- |
752
- | Herdr plugin, Node.js | Unpacks the npm package of the new version into `~/wherdr/app`, keeps the old copy, restarts |
870
+ | Herdr plugin, Node.js | Verifies and unpacks the GitHub release package of the new version into `~/wherdr/app`, keeps the old copy, restarts |
753
871
  | `npm install -g wherdr` | `npm install -g wherdr@X.Y.Z`, then restarts (login service included) |
754
872
  | Homebrew | `brew upgrade wherdr`, then `brew services restart wherdr` |
755
873
 
@@ -837,6 +955,92 @@ All settings are environment variables (`.env` with Docker).
837
955
  In the app, **Settings** holds per-device preferences: language, theme, notifications, terminal
838
956
  text size and renderer, typing effect, what the home screen shows, and the passkey lock.
839
957
 
958
+ **Settings › Conversation › Reply style** chooses how an agent's reply offers to be quoted in
959
+ the field, question by question and point by point (a list item or a paragraph that asks
960
+ nothing), so that one message answers them all:
961
+
962
+ | Style | A question | A point |
963
+ | --- | --- | --- |
964
+ | **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. |
965
+ | **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. |
966
+ | **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. |
967
+
968
+ Every one of these is a button reachable with the keyboard (`Tab`, then `Enter`), and selecting a
969
+ passage still offers **Reply** on it. A quoted question or point shows `✓`.
970
+
971
+ **One syntax for every reference.** Whatever you reply to, the field gets one line that names it,
972
+ and your answer goes on the lines below:
973
+
974
+ ```
975
+ ↳ Quote message 11:37 ~k3f : I can merge the PR —
976
+ Go ahead.
977
+ ↳ Quote point 11:37 ~k3f : Shall I tag the release today? —
978
+ Yes
979
+ ↳ Quote decision 11:37 #3 ~k3f : Publish the release notes on the site? —
980
+ No
981
+ ```
982
+
983
+ | Line | Written by |
984
+ | --- | --- |
985
+ | `↳ Quote message <time> ~<code> : <start of the message> —` | **Reply** under an agent message. |
986
+ | `↳ Quote point <time> ~<code> : <excerpt> —` | `↳` on a question or a point, **Reply** on a selected passage. |
987
+ | `↳ Quote decision <time> #<n> ~<code> : <question> —` | **Yes**, **No** or `↳` on a row of a decision table. |
988
+ | `↳ Quote decisions <time> #<rows> ~<code> : <questions> —` | **OK to all** on a decision table. |
989
+ | `↳ Decision: <task> —`, `↳ Problem: <task> —`, `↳ Question: <task> —`, `↳ Detail on <task> —`, `↳ Feedback on <task> —` (and their French labels) | **Answer**, **Problem**, **Question**, **Clarify** and **Comment** in the Project panel. |
990
+
991
+ - The time is the one shown on the agent's message, so an answer to an earlier message is never
992
+ read as an answer to the last one. The types are the same words in every language.
993
+ - The code after `~` is three characters wherdr derives from the message (and the rank of the
994
+ table, from the second table of a message on). It tells apart two messages of the same minute
995
+ and two tables of one message, whatever the excerpt shows. The field draws it dimmed, like
996
+ the words before the excerpt; the quote of a sent message leaves it out. The rows of **OK to
997
+ all** are the numbers the table really has: `#1-4`, or `#1,4` when rows 2 and 3 do not exist.
998
+ - A reference is a whole line: it starts with `↳` in the first column and ends with ` —` at the
999
+ end of the line, and only there, so an excerpt may hold dashes of its own. The excerpt is plain
1000
+ text on one line; a long one is cut with `…` (a message keeps its start, a passage its start
1001
+ and its end).
1002
+ - Several references fit in one message, each followed by its answer.
1003
+ - Anything else is your own text: a `>` at the start of a line, a `↳` line of an unknown type or
1004
+ with words after its dash. Text you paste never becomes a reference either: a pasted line that
1005
+ reads like one gets a `\` before its `↳`. A long paste, shown as a **Pasted text** card, is
1006
+ sent exactly as it was pasted.
1007
+ - In the conversation, each reference of a sent message shows as a quote; tap it to see the
1008
+ message it names. Messages sent earlier with `> ` lines still show as quotes.
1009
+
1010
+ **Settings › Conversation › Quoted replies** chooses how the field shows these lines: **Tokens,
1011
+ native field** (default) draws each one as a token in the usual field, **Plain text** shows the
1012
+ same lines as text, a fallback if the tokens misbehave. The message sent is the same.
1013
+
1014
+ A **closed question**, one that yes or no answers in full, also gets **Yes** and **No** next to
1015
+ its `↳` (at the end of its row in the list style). A tap refers to the question and writes the
1016
+ answer under it, in the language of the interface, exactly as Reply and typing would; nothing is sent, so several questions can be
1017
+ answered in a row before sending. The keyboard stays down on a phone. Tapping the other answer
1018
+ replaces the first; words you typed under a quote are never replaced. The rule is cautious, and
1019
+ in doubt only Reply is offered: a single sentence that opens like a yes/no question (`Shall I…`,
1020
+ `Do you…`, `Is it…`, `Want me to…`, `Est-ce que…`, `Je lance… ?`, `On…`, `Dois-je…`) or ends
1021
+ with `, OK?` / `, d'accord ?`, with no alternative (`or`, `ou`), no interrogative word (`which`,
1022
+ `how`, `quel`, `comment`…) and no negation.
1023
+
1024
+ A **decision table**, a Markdown table whose rows are numbered questions as a coordinator writes
1025
+ them, gets a panel right under it: **OK to all** refers to the whole table and writes `OK to all`
1026
+ under it (a second tap takes it back), and each row has **Yes**, **No** and `↳`, which refer to
1027
+ the row by its number and write `Yes` or `No` under it, or nothing for an answer in words; a row
1028
+ that asks an open question has `↳` alone. Every answer names the message and the row, even for
1029
+ the last message: the agent may write another one before you send. In French: `OK tout`, `Oui`,
1030
+ `Non`. Here too everything is composed in the field and you send. A table qualifies when it has a
1031
+ number column (a header `#`, `N°`, `No`, `Num`, `ID` or `Q` over short numbers, each once) and a
1032
+ question column, known by its header (`Question`, `Decision`, `Choix`…), by cells that all end
1033
+ with `?`, or by an advice column next to it (`Avis`, `Recommendation`, `Suggestion`…). Any other
1034
+ table is left as it is.
1035
+
1036
+ Above the field, **N questions unanswered** counts the questions of the agent's last message
1037
+ (and the rows of its decision tables) that your draft does not answer yet; tap it to scroll to
1038
+ the first one. A question counts once it is quoted, a row once it is answered, quoted or covered
1039
+ by **OK to all**; when the message asks one thing only, any words you type answer it. The line
1040
+ goes when everything is answered and when you send, and it never shows for earlier messages,
1041
+ while the agent is working, or while it waits on a prompt. It hangs from the top edge of the
1042
+ field, so nothing moves when it comes or goes.
1043
+
840
1044
  ## Several machines (SSH)
841
1045
 
842
1046
  wherdr also shows the agents of the **SSH machines registered in Herdr** — the ones the Herdr
@@ -911,15 +1115,33 @@ gets a default workspace, as with any attached client.
911
1115
 
912
1116
  ## Works great with herdr-projects
913
1117
 
914
- [herdr-projects](https://github.com/eliasstravik/herdr-projects) is a Herdr plugin that runs a
1118
+ [herdr-projects](https://github.com/afloury/herdr-projects) is a Herdr plugin that runs a
915
1119
  project as one **coordinator** conversation and parallel **threads**, each in its own Git
916
- worktree. It is optional; with it installed, wherdr adds:
1120
+ worktree. It is optional. wherdr works with its **0.2** line, installed from the fork (or with
1121
+ **Install herdr-projects** in **Settings → Plugins → herdr-projects**):
1122
+
1123
+ ```sh
1124
+ herdr plugin install afloury/herdr-projects --ref v0.2.36 --yes
1125
+ ```
1126
+
1127
+ > **herdr-projects 1.x is not supported yet.** Upstream
1128
+ > ([eliasstravik/herdr-projects](https://github.com/eliasstravik/herdr-projects)) moved to a 1.x
1129
+ > that is a different product (a task board, with no projects, `TASKS.md` or threads), and its
1130
+ > first run moves `~/.herdr-projects` to `~/.herdr-projects-legacy`. Settings says when a machine
1131
+ > has 1.x and gives the command to go back to 0.2. A 0.2 installed from upstream must not run
1132
+ > `herdr-projects update`, which would install 1.x: reinstall it from the fork
1133
+ > (`herdr plugin uninstall herdr-projects && herdr plugin install afloury/herdr-projects --ref v0.2.36 --yes`;
1134
+ > projects stay in `~/.herdr-projects`). The pinned v0.2.36 release downloads a prebuilt binary
1135
+ > for macOS or Linux, on ARM64 or x86_64.
1136
+
1137
+ With it installed, wherdr adds:
917
1138
 
918
1139
  - **Project groups** in the agent list: the coordinator first, its threads indented under it,
919
1140
  grouped by repository (`Repo web-shop · 2 worktrees`), with their thread number and state.
920
1141
  - **Project panel** next to the coordinator (a side panel on a computer, a tab on a phone). It
921
1142
  reads the project's `TASKS.md` and shows the lists it has, always in this order, with the open
922
- threads live (state, progress, report) and resolved threads under Done:
1143
+ threads live (state, progress, report) and threads marked done under Done (**Tasks** tab; the
1144
+ **Threads**, **Inbox**, **Routines**, **Settings** and **Memory** tabs are described below):
923
1145
 
924
1146
  | List | Meaning | Buttons |
925
1147
  | --- | --- | --- |
@@ -931,7 +1153,7 @@ worktree. It is optional; with it installed, wherdr adds:
931
1153
  | **Blocked** | Waiting for someone or something external | Unblock, Clarify |
932
1154
  | **To do** | To do soon, in your priority order; never launched on its own | Move up / down, Queue it, Launch now, Clarify, Back to backlog |
933
1155
  | **Backlog** | Everything else | Launch, Clarify |
934
- | **Done** | Resolved threads | |
1156
+ | **Done** | Threads marked done | |
935
1157
 
936
1158
  Every list is **optional**: you and your coordinator pick the ones a project uses (a small
937
1159
  project may only need Backlog, In progress and Done); any other `##` list shows in a neutral
@@ -942,6 +1164,73 @@ worktree. It is optional; with it installed, wherdr adds:
942
1164
  header shows the thread slots in use (`max_parallel_threads` in `PROJECT.md`) and the next
943
1165
  task, plus the machine's global limit when one is set
944
1166
  (`2 of 2 thread slots in use on <machine> (all projects)`).
1167
+ - **Threads tab** of the Project panel: every thread of the project, including those marked done.
1168
+ Open threads are grouped as herdr-projects groups them (Your turn, Ready for review, Working…),
1169
+ each with its machine and agent profile; threads marked done stay in their own folded section,
1170
+ shown by pages of 30. One filter covers both (ID, title, machine, profile). A tap opens the
1171
+ thread's record: state, its **Next** list, branch, dates, and these actions:
1172
+
1173
+ | Action | Command | Asks first |
1174
+ | --- | --- | --- |
1175
+ | **Acknowledge** | `thread ack`: you have seen its report | |
1176
+ | **Restart** | `thread restart`: bring back a thread whose pane is gone or whose start failed | |
1177
+ | **Stop** | `thread stop`: Escape in its agent's pane | Yes |
1178
+ | **Mark done** | `thread resolve`: final copy, then its worktree, merged branch and tab are cleaned up (report and library kept) | Yes |
1179
+
1180
+ Open agent, View report and Pull request are there too when they apply. wherdr only runs
1181
+ these `herdr-projects` commands on the coordinator's machine (and reads `thread show --json`);
1182
+ it writes no thread file itself, and herdr-projects has the last word (it refuses to restart a
1183
+ running thread, for instance): its answer is shown as is. With Docker, **Mark done** runs in
1184
+ the container, where the home folder is read-only: a thread of this machine is marked done and
1185
+ its open workspace removed through Herdr, but its merged branch, or a worktree whose workspace
1186
+ was already closed, may stay. herdr-projects lists what it kept, and
1187
+ `herdr-projects sweep <project>` on the host removes it.
1188
+ - **Inbox tab**: the project's unhandled inbox items, what herdr-projects tells the coordinator
1189
+ (a thread's new report, a routine due, a machine out of reach…), oldest first, up to 100. An
1190
+ item about a thread shows the thread's title and opens it. **Done** (✓) marks one item as
1191
+ handled with `herdr-projects inbox done`; a coordinator that has not read it yet will not see
1192
+ it any more. Summaries are shown as plain text.
1193
+ - **Routines tab**: each routine's schedule, whether it is enabled, its kind (prompt only, or a
1194
+ command and its approval) and its last and next run. Read-only: wherdr never approves,
1195
+ switches or runs a routine, and does not expose the plugin's safety settings.
1196
+ - **Settings tab**, read-only: what the project's `PROJECT.md` sets, the keys
1197
+ `herdr-projects set` changes (name, goal, coordinator and thread profiles,
1198
+ `max_parallel_threads`, `auto_resolve_days`, `nudge`, `mute`, repositories). A key the file
1199
+ leaves out shows the plugin's default, marked as such. Safety settings are not shown.
1200
+ - **Memory tab**, read-only: `MEMORY.md` (the index) and the `.md` files of `memory/`, with the
1201
+ title and hook the index gives them; a file the index does not mention is listed by name. A
1202
+ tap opens one, rendered as Markdown. The coordinator writes memory, wherdr never does.
1203
+
1204
+ With six tabs, the bar scrolls sideways on a phone and in a narrow side panel; a fade on its
1205
+ edge says there are more.
1206
+
1207
+ herdr-projects (0.2.34) has no JSON output for the inbox or the routines: wherdr reads the
1208
+ front matter of the project's `inbox/*.md` files, and the tab-separated lines of
1209
+ `herdr-projects routine list`, showing the run texts (`last … · next …`) as printed. No command
1210
+ prints a project's settings or memory either: those two tabs read the files named above.
1211
+ - **Board** (`H`, or the board button above the agent list): every project, thread, task and
1212
+ agent at a glance, in four columns. Agents outside projects show too. Each card opens what it
1213
+ stands for: a project or task opens its Project panel, a thread opens its agent (or its report
1214
+ once closed), an agent opens its conversation. A project card takes the most urgent column of
1215
+ its cards and counts them; Finished shows the 5 most recent threads and done tasks of each
1216
+ project, **Show all** the rest. The filter button in the header hides chosen projects, or the
1217
+ agents outside projects (**Other agents**); the choice is kept on the device, and a new project
1218
+ shows until you hide it.
1219
+
1220
+ | Card | Blocked | Todo | Ongoing | Finished |
1221
+ | --- | --- | --- | --- | --- |
1222
+ | **Task** (its `TASKS.md` list) | Blocked | To test, To decide, To review, In queue, To do, Backlog, other lists | In progress without an open thread | Done, or a checked line |
1223
+ | **Thread** | Its agent is your turn, or *waiting on you* | *Ready for review* | Working, landing, idle | Done |
1224
+ | **Agent** | Your turn | | Working, starting, restarting | Done, ready |
1225
+
1226
+ Moving a **task** card (drag and drop on a computer, **Move to…** everywhere) sends the
1227
+ coordinator the Project panel's message when one says it (**Launch now** from To do or In
1228
+ queue, **Launch** from Backlog, **Unblock** from Blocked, **Tested** from To test, **Reviewed**
1229
+ from To review), otherwise `↳ Mark blocked: …`, `↳ Move to To do: …` or `↳ Mark done: …`. The
1230
+ card shows *Sent* until the coordinator has moved the line; only the allowed columns are
1231
+ offered, and To decide tasks wait for your answer. Thread, agent and project cards follow
1232
+ what they do and do not move. The server reads every project at once
1233
+ (`GET /api/board`); a project on an offline machine keeps its last read, marked as such.
945
1234
  - **Max threads per machine**, across all projects: herdr-projects only limits threads per
946
1235
  project, so three coordinators could still start a dozen threads on one small machine. Set a
947
1236
  limit per machine in **Settings → Plugins → herdr-projects** (empty `—` = no global limit;
@@ -973,7 +1262,8 @@ worktree. It is optional; with it installed, wherdr adds:
973
1262
  ```markdown
974
1263
  - [ ] Stop button on iPhone [b:red(bug)] [b:gray(t-0140)](t-0140) [b:blue(PR #12)](https://github.com/owner/repo/pull/12) (me)
975
1264
  ```
976
- - **Settings → Plugins → herdr-projects**: install status per machine, the `TASKS.md` convention,
1265
+ - **Settings → Plugins → herdr-projects**: install status per machine (with a warning for an
1266
+ unsupported 1.x, or a 0.2 from upstream whose update would install 1.x), the `TASKS.md` convention,
977
1267
  a template, the max threads per machine and the coordinator rules to copy.
978
1268
  - **Projects entries** in the menus when the plugin is on the agent's machine: an agent's menu
979
1269
  (`…`) and its card's (right click, long press on the phone) offer the Project panel, **New
@@ -996,17 +1286,57 @@ worktree. It is optional; with it installed, wherdr adds:
996
1286
 
997
1287
  The Project panel only works well when the coordinator follows its conventions: which lists
998
1288
  mean what, the badges, `(agent → t-NNNN)`, and what to do with each message the buttons send
999
- (`✓ Tested: …`, `✗ Problem: … — …`, `↳ Queue: …`…). They are written once, as an agent skill:
1289
+ (`✓ Tested: …`, `↳ Queue: …`, `↳ Problem: … —` or `↳ Decision: … —` with the answer below it…). They are written once, as an agent skill:
1000
1290
  [`skills/wherdr/SKILL.md`](skills/wherdr/SKILL.md).
1001
1291
 
1002
- - **Herdr plugin**: the install links the skill for every coordinator, whatever its agent:
1003
- `~/.claude/skills/wherdr` (Claude Code, or `$CLAUDE_CONFIG_DIR/skills`) and
1004
- `~/.agents/skills/wherdr` (Codex, omp), each only when that agent is installed. Both point to a
1005
- copy in `~/wherdr/skills/wherdr`, refreshed on each update. An existing `wherdr` skill that is
1006
- not this link is left alone. Remove the links with `sh scripts/herdr-plugin.sh skill uninstall`
1007
- in the plugin folder.
1008
- - **Other installs**: link or copy `skills/wherdr` into your agent's skills folder yourself, or
1009
- paste **Settings → Plugins → herdr-projects → Copy rules for the coordinator** to it.
1292
+ The npm package (also used by Homebrew) and Docker image include the skill from that
1293
+ release. Installation is best effort: a missing agent or an unwritable home never blocks
1294
+ wherdr. It links `~/.claude/skills/wherdr` (or `$CLAUDE_CONFIG_DIR/skills/wherdr`) only
1295
+ when the Claude configuration folder exists, and `~/.agents/skills/wherdr` only when
1296
+ `.agents`, `.codex` or `.omp` exists. Links point to a stable copy in
1297
+ `${WHERDR_DIR:-$HOME/wherdr}/skills/wherdr`. Existing skills from elsewhere are left alone.
1298
+ Relative `WHERDR_DIR` resolves from the working directory; relative `CLAUDE_CONFIG_DIR`
1299
+ resolves from HOME, including when saved in a login service. Unchanged content is not rewritten.
1300
+ A broken link is repaired only when local metadata proves wherdr created it.
1301
+
1302
+ | Install mode | Skill installation and refresh |
1303
+ | --- | --- |
1304
+ | npm / npx / Bun / pnpm | On `wherdr`, `wherdr run`, `wherdr start` or `wherdr service install`; after updating the package, the next start refreshes it. |
1305
+ | Homebrew | On `wherdr` startup, including the Homebrew service; restart the service after `brew upgrade`. |
1306
+ | One-tap update (npm, Homebrew, native plugin) | Restarting wherdr refreshes the skill from the newly installed package; rollback restores the previous copy when that package also bundles the skill. |
1307
+ | Herdr plugin, Node.js | On plugin installation / reinstallation, and on startup from its installed package. |
1308
+ | Herdr plugin, Docker | On plugin installation and Update, extracted from the pulled image on the host. |
1309
+ | One-command installer, Docker | After each pull, including reruns and `WHERDR_MODE=docker`; saves host helpers in `$WHERDR_DIR/skill-installer`. |
1310
+ | Docker by hand | Run the host-side command below after the initial pull and after each image update. |
1311
+ | From source | Use `node bin/wherdr.mjs` after building, or run `sh bin/lib/install-skill.sh` yourself after updating; `npm start` alone does not install the skill. |
1312
+
1313
+ Docker cannot write the host's agent folders through its read-only home mount. From the
1314
+ repository checkout on the **host**, after pulling your image, run:
1315
+
1316
+ ```sh
1317
+ sh bin/install-docker-skill.sh ghcr.io/afloury/wherdr:latest
1318
+ ```
1319
+
1320
+ Pass your image tag if different. The helper creates a stopped temporary container, copies
1321
+ only `/app/skills/wherdr/SKILL.md` out of it, uses the local host installer, then removes
1322
+ the container. No host home is mounted into it. Repeat this command after each manual Docker update; Docker has no one-tap
1323
+ update in the app. Manual failures (including older images without the skill) return a
1324
+ nonzero status with diagnostics; plugin and one-command installation warn and continue. Without a checkout, use
1325
+ `sh "${WHERDR_DIR:-$HOME/wherdr}/skill-installer/bin/install-docker-skill.sh" <image>` after the one-command install.
1326
+
1327
+ Remove managed links with `sh bin/lib/install-skill.sh uninstall` (or
1328
+ `sh scripts/herdr-plugin.sh skill uninstall` in the plugin folder). Uninstall leaves
1329
+ `~/.local/state/wherdr/skill-disabled`: subsequent starts and updates respect it, even if
1330
+ `WHERDR_DIR` changes. To re-enable, explicitly run `sh bin/lib/install-skill.sh install`
1331
+ or the plugin's `skill install` (or the Docker host helper above). `WHERDR_SKILL=off`
1332
+ disables all installation and refresh, including explicit install; export it for interactive
1333
+ starts or set it when installing the login service to preserve it there.
1334
+
1335
+ Two limitations remain: rollback to an older package without the helper (such as 1.3.2)
1336
+ leaves the failed release's skill in place. With multiple wherdr versions sharing an account,
1337
+ the last one started supplies the skill; there is no version comparison.
1338
+
1339
+ You can also paste **Settings → Plugins → herdr-projects → Copy rules for the coordinator** to your agent.
1010
1340
 
1011
1341
  ## Herdr plugins
1012
1342
 
@@ -1060,16 +1390,13 @@ container talks to the Herdr server running on the host.
1060
1390
  allowed"); add it to `HERDR_WEB_ALLOWED_HOSTS`, then restart wherdr. This host check also
1061
1391
  applies to WebSockets.
1062
1392
  - **Passkey lock** (Settings → Security, recommended): once a passkey is registered, the API,
1063
- images, photos and WebSockets require an unlocked session (signed HttpOnly cookie). Two limits
1064
- apply:
1065
- - **12 hours without use**: the session slides, so the app only locks again after 12 hours
1066
- without any request (or when you lock it from Settings).
1067
- - **Maximum duration** since the last passkey unlock, set in Settings → Security for every
1068
- device: 1 day, 7 days (default), 30 days, 90 days or 1 year. The unlock time is signed in the
1069
- cookie and the slide never moves it. Past it, the device asks for the passkey again at the
1070
- next opening of the app (launch, reload, or back in the foreground), never in the middle of
1071
- use; the app warns in the last hours. A client that never reopens is cut 12 hours after the
1072
- deadline. A shorter duration applies to the sessions already open.
1393
+ images, photos and WebSockets require an unlocked session (signed HttpOnly cookie). One rule
1394
+ applies: the duration set in Settings → Security for every device, counted from the last
1395
+ passkey unlock, used or not in between: 1 day, 7 days (default), 30 days, 90 days or 1 year.
1396
+ There is no idle lock. Past it, the device asks for the passkey again at the next opening of
1397
+ the app (launch, reload, or back in the foreground), never in the middle of use; the app warns
1398
+ in the last hours. A client that never reopens is cut 12 hours after the deadline. A changed
1399
+ duration applies to the sessions already open.
1073
1400
 
1074
1401
  A network error or a server restart never locks the app. **Lock all devices** (Settings →
1075
1402
  Security, for a lost or stolen device) ends every session, this one included, and keeps the
@@ -1099,7 +1426,8 @@ See [SECURITY.md](SECURITY.md) to report a vulnerability.
1099
1426
  `herdr server`). With Docker, check that `HOST_HOME` and `PUID` match your user.
1100
1427
  - **No conversation, only the terminal**: the agent was started before the Herdr integration
1101
1428
  was installed, or it is not Claude Code / Codex / omp. Install the integration
1102
- (`herdr integration install claude|codex|omp`) and start a new agent.
1429
+ (`herdr integration install claude|codex|omp`) and start a new agent. When the integration
1430
+ is missing on the agent's machine, the conversation says so with the exact command.
1103
1431
  - **Passkeys or notifications unavailable**: the page must be served over HTTPS (or
1104
1432
  `localhost`). On iPhone, notifications need the app installed on the home screen.
1105
1433
  - **HTTP 403 "This address isn't enabled yet"**: for a tailnet address, run the command the
@@ -0,0 +1,20 @@
1
+ #!/bin/sh
2
+ # Run on the HOST after pulling an image; no container is started, no home mounted.
3
+ # Usage: sh bin/install-docker-skill.sh <image> [refresh|install]
4
+ extract_skill() (
5
+ set -eu
6
+ [ -n "${1:-}" ] || { echo 'usage: install-docker-skill.sh <image> [refresh|install]' >&2; exit 1; }
7
+ [ "${WHERDR_SKILL:-}" != off ] || { echo 'wherdr skill: disabled by WHERDR_SKILL=off'; exit 0; }
8
+ if [ "${2:-install}" != install ] && [ -e "${HOME:-}/.local/state/wherdr/skill-disabled" ]; then exit 0; fi
9
+ helper=$(CDPATH= cd -- "$(dirname "$0")" && pwd -P)/lib/install-skill.sh
10
+ tmp=$(mktemp -d)
11
+ container=
12
+ trap '[ -z "$container" ] || docker rm "$container" >/dev/null 2>&1; rm -rf "$tmp"' EXIT HUP INT TERM
13
+ container=$(docker create -- "$1")
14
+ mkdir -p "$tmp/skills/wherdr"
15
+ # Only data crosses the image boundary. The executed helper is local.
16
+ docker cp "$container:/app/skills/wherdr/SKILL.md" "$tmp/skills/wherdr/SKILL.md"
17
+ sh "$helper" "${2:-install}" "$tmp"
18
+ )
19
+ # Unlike startup, manual and plugin callers see failures and useful diagnostics.
20
+ extract_skill "$@"