wherdr 1.3.1 → 1.3.3
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.
- package/.output/nitro.json +1 -1
- package/.output/public/_nuxt/{AgentView.C4YOwvZG.css → AgentView.DzFWBd2A.css} +1 -1
- package/.output/public/_nuxt/B4Yk2tB1.js +23 -0
- package/.output/public/_nuxt/BBw_0a4M.js +6 -0
- package/.output/public/_nuxt/{B6qBWHWB.js → BSy6OCIY.js} +1 -1
- package/.output/public/_nuxt/BX5PM2JQ.js +1 -0
- package/.output/public/_nuxt/BgPDnf2S.js +1 -0
- package/.output/public/_nuxt/BkOxQzbS.js +2 -0
- package/.output/public/_nuxt/{WLQjK8uJ.js → CKhgznq4.js} +45 -46
- package/.output/public/_nuxt/{C2T9fQ4f.js → CP8o925U.js} +1 -1
- package/.output/public/_nuxt/CkbmecwS.js +1 -0
- package/.output/public/_nuxt/Cr3SrGky.js +1 -0
- package/.output/public/_nuxt/DAg9fiVh.js +89 -0
- package/.output/public/_nuxt/DT8qZ0Wv.js +1 -0
- package/.output/public/_nuxt/DaaJIRB3.js +1 -0
- package/.output/public/_nuxt/DcJi16XA.js +1 -0
- package/.output/public/_nuxt/VpjCgSXu.js +36 -0
- package/.output/public/_nuxt/builds/latest.json +1 -1
- package/.output/public/_nuxt/builds/meta/c735b6c0-1bd0-47d7-a208-d310f0a06287.json +1 -0
- package/.output/public/_nuxt/dPxB2L94.js +89 -0
- package/.output/public/_nuxt/{entry.cKR16VqG.css → entry.CGWKmYU3.css} +1 -1
- package/.output/public/_nuxt/hePW80VL.js +1 -0
- package/.output/public/_nuxt/xYX85SPI.js +1 -0
- package/.output/public/sw.js +1 -1
- package/.output/server/chunks/_/branding.mjs +1 -1
- package/.output/server/chunks/_/filePaths.mjs +25 -0
- package/.output/server/chunks/_/files.mjs +204 -0
- package/.output/server/chunks/_/machineOrder.mjs +1 -1
- package/.output/server/chunks/_/onboarding.mjs +1 -1
- package/.output/server/chunks/_/package.mjs +97 -0
- package/.output/server/chunks/_/pluginPolicy.mjs +93 -0
- package/.output/server/chunks/_/plugins.mjs +4 -94
- package/.output/server/chunks/_/projectBoard.mjs +120 -29
- package/.output/server/chunks/_/projectDocs.mjs +106 -0
- package/.output/server/chunks/_/projectInbox.mjs +135 -0
- package/.output/server/chunks/_/projectThreads.mjs +46 -0
- package/.output/server/chunks/_/projectThreads2.mjs +61 -0
- package/.output/server/chunks/_/projectsActions.mjs +1 -1
- package/.output/server/chunks/_/projectsPlugin.mjs +1 -1
- package/.output/server/chunks/_/restart.mjs +2 -312
- package/.output/server/chunks/_/reveal.mjs +2 -24
- package/.output/server/chunks/_/selfupdate.mjs +83 -0
- package/.output/server/chunks/_/updates.mjs +91 -0
- package/.output/server/chunks/_/worktrees.mjs +1 -1
- package/.output/server/chunks/_/ws.mjs +1 -1
- package/.output/server/chunks/nitro/nitro.mjs +2660 -1061
- package/.output/server/chunks/raw/bump-homebrew.mjs +1 -1
- package/.output/server/chunks/raw/herdr-plugin.mjs +1 -1
- package/.output/server/chunks/raw/release-ready.mjs +5 -0
- package/.output/server/chunks/routes/api/_..._.mjs +6 -2
- package/.output/server/chunks/routes/api/agents.post.mjs +6 -2
- package/.output/server/chunks/routes/api/ask-tab.post.mjs +6 -2
- package/.output/server/chunks/routes/api/attach.post.mjs +6 -2
- package/.output/server/chunks/routes/api/auth/disable.post.mjs +6 -2
- package/.output/server/chunks/routes/api/auth/lock-all.post.mjs +6 -2
- package/.output/server/chunks/routes/api/auth/lock.post.mjs +6 -2
- package/.output/server/chunks/routes/api/auth/login/options.post.mjs +6 -2
- package/.output/server/chunks/routes/api/auth/login/verify.post.mjs +6 -2
- package/.output/server/chunks/routes/api/auth/max-session.post.mjs +6 -2
- package/.output/server/chunks/routes/api/auth/register/options.post.mjs +6 -2
- package/.output/server/chunks/routes/api/auth/register/verify.post.mjs +6 -2
- package/.output/server/chunks/routes/api/auth/status.get.mjs +6 -2
- package/.output/server/chunks/routes/api/board.get.mjs +147 -0
- package/.output/server/chunks/routes/api/changes.get.mjs +7 -3
- package/.output/server/chunks/routes/api/chat/image.get.mjs +7 -3
- package/.output/server/chunks/routes/api/chat.get.mjs +7 -3
- package/.output/server/chunks/routes/api/choose.post.mjs +34 -4
- package/.output/server/chunks/routes/api/claude-statusline.post.mjs +7 -3
- package/.output/server/chunks/routes/api/close/status.get.mjs +7 -3
- package/.output/server/chunks/routes/api/close.post.mjs +6 -2
- package/.output/server/chunks/routes/api/codex-update.post.mjs +7 -3
- package/.output/server/chunks/routes/api/commands.get.mjs +7 -3
- package/.output/server/chunks/routes/api/config.get.mjs +8 -3
- package/.output/server/chunks/routes/api/dirs.get.mjs +7 -3
- package/.output/server/chunks/routes/api/dismiss-stopped.post.mjs +43 -0
- package/.output/server/chunks/routes/api/dismiss.post.mjs +7 -3
- package/.output/server/chunks/routes/api/effort.post.mjs +7 -3
- package/.output/server/chunks/routes/api/efforts.get.mjs +7 -3
- package/.output/server/chunks/routes/api/file.post.mjs +7 -3
- package/.output/server/chunks/routes/api/files/download.get.mjs +53 -0
- package/.output/server/chunks/routes/api/files/read.get.mjs +45 -0
- package/.output/server/chunks/routes/api/files.get.mjs +44 -0
- package/.output/server/chunks/routes/api/gitroot.get.mjs +7 -3
- package/.output/server/chunks/routes/api/health.get.mjs +36 -0
- package/.output/server/chunks/routes/api/index.get.mjs +6 -2
- package/.output/server/chunks/routes/api/input.post.mjs +18 -4
- package/.output/server/chunks/routes/api/interrupt.post.mjs +7 -3
- package/.output/server/chunks/routes/api/isgit.get.mjs +7 -3
- package/.output/server/chunks/routes/api/machine/awake.get.mjs +7 -3
- package/.output/server/chunks/routes/api/machine/awake.post.mjs +7 -3
- package/.output/server/chunks/routes/api/machine/order.get.mjs +6 -2
- package/.output/server/chunks/routes/api/machine/order.post.mjs +6 -2
- package/.output/server/chunks/routes/api/machine/rename.post.mjs +7 -3
- package/.output/server/chunks/routes/api/menu.post.mjs +7 -3
- package/.output/server/chunks/routes/api/model.post.mjs +7 -3
- package/.output/server/chunks/routes/api/models.get.mjs +7 -3
- package/.output/server/chunks/routes/api/nav.post.mjs +10 -5
- package/.output/server/chunks/routes/api/onboarding.get.mjs +6 -2
- package/.output/server/chunks/routes/api/onboarding.post.mjs +6 -2
- package/.output/server/chunks/routes/api/phone.get.mjs +6 -7
- package/.output/server/chunks/routes/api/phone.post.mjs +6 -7
- package/.output/server/chunks/routes/api/plugins/actions.get.mjs +7 -2
- package/.output/server/chunks/routes/api/plugins/invoke.post.mjs +7 -2
- package/.output/server/chunks/routes/api/plugins/profiles.get.mjs +7 -2
- package/.output/server/chunks/routes/api/plugins/projects.get.mjs +7 -3
- package/.output/server/chunks/routes/api/plugins/projects.post.mjs +7 -3
- package/.output/server/chunks/routes/api/plugins/thread-limits.get.mjs +7 -3
- package/.output/server/chunks/routes/api/plugins/thread-limits.post.mjs +7 -3
- package/.output/server/chunks/routes/api/project/inbox.get.mjs +43 -0
- package/.output/server/chunks/routes/api/project/inbox.post.mjs +43 -0
- package/.output/server/chunks/routes/api/project/memory.get.mjs +42 -0
- package/.output/server/chunks/routes/api/project/report.get.mjs +7 -3
- package/.output/server/chunks/routes/api/project/routines.get.mjs +43 -0
- package/.output/server/chunks/routes/api/project/settings.get.mjs +41 -0
- package/.output/server/chunks/routes/api/project/thread.get.mjs +44 -0
- package/.output/server/chunks/routes/api/project/thread.post.mjs +45 -0
- package/.output/server/chunks/routes/api/prompt.post.mjs +26 -4
- package/.output/server/chunks/routes/api/push/quiet.post.mjs +7 -3
- package/.output/server/chunks/routes/api/push/subscribe.post.mjs +7 -3
- package/.output/server/chunks/routes/api/push/test.post.mjs +7 -3
- package/.output/server/chunks/routes/api/push/unsubscribe.post.mjs +7 -3
- package/.output/server/chunks/routes/api/quotas.get.mjs +7 -3
- package/.output/server/chunks/routes/api/rename.post.mjs +6 -2
- package/.output/server/chunks/routes/api/requeue.post.mjs +7 -3
- package/.output/server/chunks/routes/api/restart.get.mjs +6 -2
- package/.output/server/chunks/routes/api/restart.post.mjs +6 -2
- package/.output/server/chunks/routes/api/reveal.post.mjs +7 -2
- package/.output/server/chunks/routes/api/screen-key.post.mjs +7 -3
- package/.output/server/chunks/routes/api/screen.get.mjs +10 -4
- package/.output/server/chunks/routes/api/search.get.mjs +7 -3
- package/.output/server/chunks/routes/api/seen.post.mjs +7 -3
- package/.output/server/chunks/routes/api/sessions.get.mjs +7 -3
- package/.output/server/chunks/routes/api/sessions.post.mjs +7 -3
- package/.output/server/chunks/routes/api/space.post.mjs +19 -15
- package/.output/server/chunks/routes/api/state.get.mjs +7 -3
- package/.output/server/chunks/routes/api/unqueue.post.mjs +7 -3
- package/.output/server/chunks/routes/api/update/status.get.mjs +38 -0
- package/.output/server/chunks/routes/api/update.get.mjs +12 -51
- package/.output/server/chunks/routes/api/update.post.mjs +41 -0
- package/.output/server/chunks/routes/api/upload.post.mjs +7 -3
- package/.output/server/chunks/routes/api/worktrees/remove.post.mjs +6 -2
- package/.output/server/chunks/routes/api/worktrees.get.mjs +6 -2
- package/.output/server/chunks/routes/favicon.ico.get.mjs +6 -2
- package/.output/server/chunks/routes/icons/_name_.get.mjs +7 -3
- package/.output/server/chunks/routes/renderer.mjs +8 -4
- package/.output/server/chunks/routes/uploads/_...name_.get.mjs +7 -3
- package/.output/server/chunks/routes/ws/_..._.mjs +7 -3
- package/.output/server/chunks/routes/ws/events.mjs +7 -3
- package/.output/server/chunks/routes/ws/term.mjs +9 -5
- package/.output/server/chunks/virtual/precomputed.mjs +1 -1
- package/.output/server/index.mjs +7 -3
- package/.output/server/package.json +1 -1
- package/README.md +440 -46
- package/bin/install-docker-skill.sh +20 -0
- package/bin/lib/commands.mjs +47 -9
- package/bin/lib/core.mjs +18 -2
- package/bin/lib/install-skill.sh +100 -0
- package/bin/lib/skill.mjs +16 -0
- package/bin/lib/tailnet.d.mts +12 -3
- package/bin/lib/tailnet.mjs +103 -25
- package/bin/lib/updater.mjs +320 -0
- package/bin/lib/verify-release.mjs +20 -0
- package/package.json +4 -2
- package/skills/wherdr/SKILL.md +180 -0
- package/.output/public/_nuxt/BDNMzG2s.js +0 -1
- package/.output/public/_nuxt/BMIe8p_3.js +0 -2
- package/.output/public/_nuxt/BpQH8Ho1.js +0 -1
- package/.output/public/_nuxt/BrAeJIZR.js +0 -30
- package/.output/public/_nuxt/C12eXl5z.js +0 -1
- package/.output/public/_nuxt/CXG-cOdh.js +0 -1
- package/.output/public/_nuxt/CYxHnMNH.js +0 -83
- package/.output/public/_nuxt/CctS2Xn6.js +0 -65
- package/.output/public/_nuxt/CiYar6hg.js +0 -6
- package/.output/public/_nuxt/DLLQgP0d.js +0 -1
- package/.output/public/_nuxt/Dwh-l2rQ.js +0 -17
- package/.output/public/_nuxt/bLP7Jj-b.js +0 -1
- package/.output/public/_nuxt/builds/meta/6466b0ab-7935-460c-abdf-2ea632dae6d0.json +0 -1
- package/.output/public/_nuxt/whFLy_Ne.js +0 -23
- package/.output/server/chunks/_/phone.mjs +0 -343
- package/.output/server/chunks/routes/ws/mirror.mjs +0 -157
package/README.md
CHANGED
|
@@ -7,13 +7,28 @@
|
|
|
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> · <
|
|
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
|
+
|
|
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>
|
|
11
13
|
|
|
12
14
|
<p align="center"><a href="https://github.com/afloury/wherdr/actions/workflows/ci.yml"><img src="https://github.com/afloury/wherdr/actions/workflows/ci.yml/badge.svg?branch=main" alt="CI"></a></p>
|
|
13
15
|
|
|
14
16
|
## Quick start
|
|
15
17
|
|
|
16
|
-
|
|
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:
|
|
17
32
|
|
|
18
33
|
```sh
|
|
19
34
|
curl -fsSL https://wherdr.dev/install | sh
|
|
@@ -36,6 +51,13 @@ saved on the server (`data/onboarding.json`), so your other devices do not show
|
|
|
36
51
|
it from Settings › About › **Setup guide**. On a phone that already opens wherdr through its
|
|
37
52
|
tailnet address, the phone step becomes Add to Home Screen.
|
|
38
53
|
|
|
54
|
+
**Passkeys are tied to the address they are created on.** Once wherdr's tailnet address is
|
|
55
|
+
published and answers, the guide opened on `localhost` shows **Continue on
|
|
56
|
+
<machine>.<tailnet>.ts.net**, which reopens it at the same step on that address, and its Security
|
|
57
|
+
step (like Settings › Security) sends the passkey lock there. Nothing redirects on its own:
|
|
58
|
+
`localhost` stays valid on the computer. The installer, the Herdr plugin and `wherdr open` open
|
|
59
|
+
that address too when it is already published.
|
|
60
|
+
|
|
39
61
|
wherdr is a small self-hosted web app that talks to the Herdr server on your machine. **On a
|
|
40
62
|
computer**, it can replace the Herdr terminal client day to day: your spaces, tabs and split panes
|
|
41
63
|
side by side, live conversations and real terminals, drag-and-drop layout, keyboard shortcuts
|
|
@@ -69,13 +91,32 @@ it on `localhost`, or from your other devices over Tailscale.
|
|
|
69
91
|
*Unofficial project. Not affiliated with or endorsed by Herdr, Anthropic or OpenAI. Claude,
|
|
70
92
|
Claude Code, Codex and other product names are trademarks of their respective owners.*
|
|
71
93
|
|
|
94
|
+
## Why wherdr
|
|
95
|
+
|
|
96
|
+
- **Herdr's splits, live.** A tab with several panes is drawn in Herdr's real layout, every pane
|
|
97
|
+
live; drag a pane to move it or a divider to resize, and the change goes to Herdr itself.
|
|
98
|
+
- **A passkey lock.** Face ID, Touch ID, Windows Hello or Android unlock the app; once a passkey
|
|
99
|
+
exists, nothing about your agents is served to a locked session.
|
|
100
|
+
- **The agent's diff.** Git status and diff of each agent's working folder, one click away from
|
|
101
|
+
its conversation.
|
|
102
|
+
- **The herdr-projects board.** A coordinator and its threads grouped under their project, with
|
|
103
|
+
the project's task lists as a live board and one-click replies.
|
|
104
|
+
- **Keyboard and global search.** One shortcut searches every agent and conversation; next
|
|
105
|
+
agent, new tab, pane swaps and `1`–`9` answers never need the mouse.
|
|
106
|
+
- **Real time, and private.** The real terminal over a WebSocket, a push when an agent needs
|
|
107
|
+
you, and your phone through Tailscale: nothing is on the Internet.
|
|
108
|
+
|
|
109
|
+
Details in [Features](#features) and [Security](#security).
|
|
110
|
+
|
|
72
111
|
## Contents
|
|
73
112
|
|
|
74
113
|
- [Quick start](#quick-start)
|
|
114
|
+
- [Why wherdr](#why-wherdr)
|
|
75
115
|
- [Features](#features)
|
|
76
116
|
- [How it works](#how-it-works)
|
|
77
117
|
- [Requirements](#requirements)
|
|
78
|
-
- [Installation](#installation): [
|
|
118
|
+
- [Installation](#installation): [ask your AI agent](#ask-your-ai-agent-1) ·
|
|
119
|
+
[or run the installer yourself](#the-one-command) ·
|
|
79
120
|
[which setup?](#which-setup) ·
|
|
80
121
|
[always-on server + Tailscale](#recommended-always-on-server--tailscale) ·
|
|
81
122
|
[other private networks](#other-private-networks) ·
|
|
@@ -99,16 +140,22 @@ Claude Code, Codex and other product names are trademarks of their respective ow
|
|
|
99
140
|
|
|
100
141
|
### Everywhere
|
|
101
142
|
|
|
102
|
-
- **Live agent list**, one line per Herdr space, grouped by state (your turn, working, ready)
|
|
103
|
-
|
|
104
|
-
question,
|
|
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.
|
|
105
149
|
- **Conversation view**: the agent's real transcript (Claude Code, Codex and omp), rendered as
|
|
106
150
|
Markdown, with grouped tool calls, images (full-screen viewer with pinch / wheel zoom and pan), timestamps, search and infinite scroll back to the
|
|
107
151
|
first message. Reading a conversation never touches the terminal, so it never resizes a pane.
|
|
108
152
|
A command the agent proposes (shell code block, or inline `! command`) can be copied without
|
|
109
153
|
its prompt, or run in the agent's shell mode (`!`, Claude Code, Codex and omp) after you
|
|
110
154
|
confirm the full command.
|
|
111
|
-
- **Terminal view**: the real terminal (xterm.js, WebGL or DOM renderer) with take-over.
|
|
155
|
+
- **Terminal view**: the real terminal (xterm.js, WebGL or DOM renderer) with take-over. Opening
|
|
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
|
|
157
|
+
(after 30 seconds when the connection just dropped, e.g. a locked phone), unless a Herdr
|
|
158
|
+
client attached meanwhile laid it out its own way. On a
|
|
112
159
|
computer, drag over the text on screen to select it: releasing the button copies it, as do
|
|
113
160
|
`⌘C` / `Ctrl+Shift+C`. The history is browsed with the wheel, not by dragging past the edge.
|
|
114
161
|
Links (OSC 8 hyperlinks and plain `http(s)://` URLs, even wrapped over several rows) open in a
|
|
@@ -116,10 +163,28 @@ Claude Code, Codex and other product names are trademarks of their respective ow
|
|
|
116
163
|
line wrapped by the width is copied in one piece, without the breaks between its rows. An image
|
|
117
164
|
pasted with `⌘V` (Mac), here or in a side-by-side terminal, goes to the agent's machine and its
|
|
118
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.
|
|
119
182
|
- **Composer**: send messages while the agent works (queued, cancellable), attach or paste
|
|
120
183
|
photos and the files the agent can read (Claude Code: PDFs, notebooks, text and code of any
|
|
121
184
|
extension; Codex: notebooks, text and code), run slash commands (`/compact`, `/clear`, `/context`, `/usage`…) and see the output
|
|
122
|
-
of local commands. Stop button while the agent works.
|
|
185
|
+
of local commands. Stop button while the agent works. A long pasted text (log, output) becomes
|
|
186
|
+
a "Pasted text · N lines" card, sent to the agent as it is and shown the same way in the
|
|
187
|
+
conversation, where it opens in full with Copy; long typed messages fold with Show more.
|
|
123
188
|
- **Codex updates and limits**: in a Codex conversation, a new Codex version shows above the
|
|
124
189
|
field with an **Update** button (runs Codex's official update command on that machine, after
|
|
125
190
|
confirmation), then **Restart to update** on the same conversation. When wherdr cannot run it
|
|
@@ -127,6 +192,20 @@ Claude Code, Codex and other product names are trademarks of their respective ow
|
|
|
127
192
|
resumes the same conversation (only while Codex is idle). Codex's own weekly-limit warning
|
|
128
193
|
(its footer gauge, or its startup heads-up) is repeated above the field, with its values, while
|
|
129
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.
|
|
130
209
|
- **Model and effort pickers** for Claude Code, Codex and omp (omp: its
|
|
131
210
|
"Switch Model" selector, `/switch` or `/model`, and its thinking level, changed with its own
|
|
132
211
|
⇧⇥ cycle). Changes apply **to the current session only**; wherdr never changes your default
|
|
@@ -134,6 +213,30 @@ Claude Code, Codex and other product names are trademarks of their respective ow
|
|
|
134
213
|
- **New agent**: pick an installed agent (or a plain terminal), a folder, optionally a separate
|
|
135
214
|
Git **worktree** and branch, resume the last conversation, and queue a first message.
|
|
136
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.
|
|
137
240
|
- **Several machines**: agents of the SSH machines registered in Herdr (`herdr machine add`)
|
|
138
241
|
appear in their own section; everything works the same on a remote agent.
|
|
139
242
|
- **Named Herdr sessions**, **quotas** (remaining Claude and Codex usage limits), **Herdr plugin
|
|
@@ -144,7 +247,10 @@ Claude Code, Codex and other product names are trademarks of their respective ow
|
|
|
144
247
|
### On a computer
|
|
145
248
|
|
|
146
249
|
- **Split panes, live**: a tab with several panes is drawn with Herdr's real layout; every pane
|
|
147
|
-
shows its conversation or terminal live
|
|
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.
|
|
148
254
|
- **Rearrange the layout**: drag a pane onto another to move it, drag a divider to resize
|
|
149
255
|
(arrow keys work on a focused divider); changes go to Herdr itself.
|
|
150
256
|
- **Spaces and tabs**: sidebar with every space, tabs at the top, active tab remembered per space.
|
|
@@ -153,7 +259,8 @@ Claude Code, Codex and other product names are trademarks of their respective ow
|
|
|
153
259
|
- **Keyboard shortcuts** (`Mod` is ⌘ on macOS, Ctrl elsewhere; `Mod+/` or `?` lists them all,
|
|
154
260
|
also in Settings › Computer):
|
|
155
261
|
- `Ctrl/⌘+K` global search across agents and conversations, `Alt+↑/↓` previous / next agent
|
|
156
|
-
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).
|
|
157
264
|
- `Mod+Alt+N` new agent in a new space, `Mod+Alt+T` new tab in the current space,
|
|
158
265
|
`Mod+Alt+W` close the current pane (after confirmation). They work from the terminal too.
|
|
159
266
|
- With [herdr-projects](#works-great-with-herdr-projects) on the agent's machine: `Mod+Alt+P`
|
|
@@ -170,6 +277,9 @@ Claude Code, Codex and other product names are trademarks of their respective ow
|
|
|
170
277
|
under their project, and a side panel with the project's task lists (to test, to decide,
|
|
171
278
|
to review, in progress, in queue, blocked, to do, backlog — each optional) and one-click
|
|
172
279
|
replies to the coordinator.
|
|
280
|
+
- **Board**: every agent, and with herdr-projects every project, thread and task, in four columns
|
|
281
|
+
(Blocked, Todo, Ongoing, Finished). Drag a task card to another column, or use its **Move
|
|
282
|
+
to…** menu, to ask the coordinator to move it.
|
|
173
283
|
- **Settings** in a sidebar, with desktop-only options such as the content width.
|
|
174
284
|
|
|
175
285
|
### On a phone
|
|
@@ -199,7 +309,10 @@ phone / laptop ──private network──> HTTPS (tailscale serve, private prox
|
|
|
199
309
|
|
|
200
310
|
wherdr runs on the same machine as the Herdr server (the "server" below). It uses Herdr's local
|
|
201
311
|
socket API and CLI, reads the agents' transcript files, and serves a client-only Nuxt app. Data
|
|
202
|
-
it keeps (VAPID keys, push subscriptions, passkeys, recent folders) lives in `data/`.
|
|
312
|
+
it keeps (VAPID keys, push subscriptions, passkeys, recent folders) lives in `data/`. So do the
|
|
313
|
+
long texts pasted into the message field, which the server keeps to show them as cards on every
|
|
314
|
+
device: `data/pastes.json`, in clear, readable by the server's user only (mode 600), at most the
|
|
315
|
+
last 100 texts and 2 MB, each one deleted 30 days after it was last sent.
|
|
203
316
|
|
|
204
317
|
Built with Nuxt 4, Nuxt UI 4, Tailwind 4 and TypeScript; the Herdr gateway (API, WebSockets,
|
|
205
318
|
Web Push, lock) runs in Nitro.
|
|
@@ -220,7 +333,20 @@ Web Push, lock) runs in Nitro.
|
|
|
220
333
|
|
|
221
334
|
## Installation
|
|
222
335
|
|
|
223
|
-
###
|
|
336
|
+
### Ask your AI agent
|
|
337
|
+
|
|
338
|
+
**Recommended.** Paste this into Claude Code, Codex or any coding agent: it installs and sets up wherdr for you.
|
|
339
|
+
|
|
340
|
+
```text
|
|
341
|
+
Read https://wherdr.dev/agent.md and help me set up wherdr. Check what is already installed first, and ask me before installing anything.
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
It follows [our setup guide for agents](https://wherdr.dev/agent.md): checks what you already have,
|
|
345
|
+
asks before installing anything, sets up your phone over Tailscale, never exposes wherdr to the Internet.
|
|
346
|
+
|
|
347
|
+
<a id="the-one-command"></a>
|
|
348
|
+
|
|
349
|
+
### Or run the installer yourself
|
|
224
350
|
|
|
225
351
|
On the computer that runs Herdr, as your user, on macOS or Linux:
|
|
226
352
|
|
|
@@ -243,7 +369,10 @@ The script ([read it first](https://wherdr.dev/install), source in
|
|
|
243
369
|
opens the setup guide in your browser (first install) and binds **prefix+i** to its panel;
|
|
244
370
|
5. on a computer **without a screen** (no `DISPLAY` on Linux, or an SSH session): opens nothing,
|
|
245
371
|
prints the local address, an `ssh -L` tunnel to reach it from your computer, and the phone
|
|
246
|
-
steps (`wherdr phone`: Tailscale state, the address, the QR code once it answers).
|
|
372
|
+
steps (`wherdr phone`: Tailscale state, the address, the QR code once it answers). With
|
|
373
|
+
Docker, it offers to run `tailscale serve` for you (asked first), and wherdr enables the
|
|
374
|
+
published address by itself: no browser is needed on the server. Run the command again at
|
|
375
|
+
any time to check the phone address.
|
|
247
376
|
|
|
248
377
|
Settings, as environment variables (`curl -fsSL https://wherdr.dev/install | WHERDR_PORT=7684 sh`):
|
|
249
378
|
|
|
@@ -254,7 +383,7 @@ Settings, as environment variables (`curl -fsSL https://wherdr.dev/install | WHE
|
|
|
254
383
|
| `WHERDR_MODE` | — | `native`: Node.js even when Docker is there. `docker`: no plugin, Docker Compose by hand in `WHERDR_DIR` (Linux; see below). |
|
|
255
384
|
| `WHERDR_YES` | — | `1` answers yes to every question (non-interactive use). |
|
|
256
385
|
| `WHERDR_NO_BROWSER` | — | `1` never opens a browser. |
|
|
257
|
-
| `WHERDR_REF` |
|
|
386
|
+
| `WHERDR_REF` | main | Git tag or branch of the plugin (or of `docker-compose.yml` with `WHERDR_MODE=docker`). |
|
|
258
387
|
| `WHERDR_PLUGIN` | `afloury/wherdr` | A local checkout to link and build instead (development, tests). |
|
|
259
388
|
|
|
260
389
|
**Docker by hand, with the script:** `curl -fsSL https://wherdr.dev/install | WHERDR_MODE=docker sh`
|
|
@@ -302,7 +431,7 @@ Edit `.env` (every value has a default; `HOST_HOME` defaults to your `$HOME`):
|
|
|
302
431
|
| `HOST_HOME` | `/home/alice` | Your home folder on the server (default: `$HOME`). Mounted at the same path, read-only. |
|
|
303
432
|
| `PUID` / `PGID` | `1000` | Your user and group IDs (`id -u`, `id -g`). |
|
|
304
433
|
| `PORT` | `7683` | Listening port, published on `127.0.0.1` only. |
|
|
305
|
-
| `APP_URL` | `
|
|
434
|
+
| `APP_URL` | `http://localhost:7683/` | Leave it with Tailscale: wherdr adopts the address of step 3 by itself. Set a private HTTPS address only for [another private network](#other-private-networks) (Web Push contact and allowed host; it then always wins). |
|
|
306
435
|
| `HOST_LABEL` | `server` | Name of this machine in the app. |
|
|
307
436
|
| `TZ` | `Europe/Paris` | Time zone for timestamps and logs. |
|
|
308
437
|
| `WHERDR_UPDATE_CHECK` | `off` | Disable the daily check for a new release (default `on`). |
|
|
@@ -340,11 +469,38 @@ tailscale serve --bg --https=7683 http://127.0.0.1:7683
|
|
|
340
469
|
```
|
|
341
470
|
|
|
342
471
|
Tailscale Serve listens on HTTPS port 7683 of your tailnet name, with a valid certificate, and
|
|
343
|
-
forwards to wherdr's local HTTP port. Only devices of your tailnet can reach it.
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
472
|
+
forwards to wherdr's local HTTP port. Only devices of your tailnet can reach it.
|
|
473
|
+
|
|
474
|
+
**wherdr enables that address by itself**, on a server without a screen too: at startup, every
|
|
475
|
+
30 seconds, and when an address it does not know yet is opened, it reads what `tailscale serve`
|
|
476
|
+
publishes on this machine and adopts the HTTPS address that points to its own port (allowed
|
|
477
|
+
host and `APP_URL`, saved in `data/app-url.json`; an HTTPS `APP_URL` in `.env` wins). An address
|
|
478
|
+
removed from `tailscale serve` is refused again. Nothing a request says can enable an address:
|
|
479
|
+
only Tailscale's own state on the machine does, and an address that `tailscale funnel` opens to
|
|
480
|
+
the Internet is never adopted. Without Docker, wherdr runs the `tailscale` command; in Docker
|
|
481
|
+
it reads Tailscale's socket, mounted by `docker-compose.yml` (`/var/run/tailscale`). After
|
|
482
|
+
Tailscale itself restarts (an update), restart the container.
|
|
483
|
+
|
|
484
|
+
What that mount gives: Tailscale's local API, with the rights of the host user the container
|
|
485
|
+
runs as. Anyone may read it; if that user is Tailscale's operator
|
|
486
|
+
(`tailscale set --operator=$USER`), the API also accepts changes from it (serve, funnel…), and
|
|
487
|
+
`:ro` on the folder does not prevent that. wherdr itself only sends `GET` requests. This is not
|
|
488
|
+
a new privilege: the container already drives Herdr, which is a shell of that same user. To do
|
|
489
|
+
without it, remove the line from `docker-compose.yml`: wherdr then no longer finds the address
|
|
490
|
+
by itself, and the one command (or the plugin's phone step) run after `tailscale serve` hands
|
|
491
|
+
it over.
|
|
492
|
+
|
|
493
|
+
**Settings › Phone** on the server (`http://localhost:7683/#/settings?section=phone`) shows the
|
|
494
|
+
state and the QR code; without Docker it also publishes wherdr itself: one button, asked first.
|
|
495
|
+
From a terminal, `wherdr phone` (npm, Homebrew) or the [one command](#the-one-command) run again
|
|
496
|
+
(Docker, Herdr plugin) checks the same thing, and
|
|
497
|
+
`curl -fsS http://127.0.0.1:7683/api/phone` prints the state as JSON. A container started from
|
|
498
|
+
an older `docker-compose.yml` has no Tailscale socket: paste the address in Settings › Phone,
|
|
499
|
+
or run the one command again, which sends it.
|
|
500
|
+
|
|
501
|
+
If the phone shows **"This address isn't enabled yet"** (403), the address it opened is not one
|
|
502
|
+
`tailscale serve` publishes for wherdr's port on that machine: the page gives the command to run
|
|
503
|
+
there.
|
|
348
504
|
|
|
349
505
|
**Why HTTPS matters.** Browsers only allow three things on `https://` (or on `localhost` itself):
|
|
350
506
|
|
|
@@ -384,8 +540,8 @@ works with any private network that gives it an **HTTPS address with a valid cer
|
|
|
384
540
|
- **`APP_URL` set to that address** (`.env` with Docker, or the environment of `wherdr` /
|
|
385
541
|
`npm start`), then restart wherdr. Its hostname is allowed automatically and it enables Web
|
|
386
542
|
Push. Add `HERDR_WEB_ALLOWED_HOSTS` only if you also open wherdr under another name. The
|
|
387
|
-
|
|
388
|
-
`APP_URL` in the environment always wins.
|
|
543
|
+
automatic adoption and the address check in **Settings › Phone** only know the `*.ts.net`
|
|
544
|
+
addresses of `tailscale serve`; an HTTPS `APP_URL` in the environment always wins.
|
|
389
545
|
- **Never exposed without authentication.** wherdr keeps listening on `127.0.0.1`; only the
|
|
390
546
|
proxy listens on the private network. Turn on the passkey lock as soon as another device can
|
|
391
547
|
reach it.
|
|
@@ -464,8 +620,8 @@ wherdr phone # phone state, the app's phone setup page, QR code o
|
|
|
464
620
|
| `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. |
|
|
465
621
|
| `wherdr status` | Address, process, service, data folder and log. |
|
|
466
622
|
| `wherdr logs` (`-f` to follow, `-n 100`) | The log, `~/wherdr/wherdr.log`. |
|
|
467
|
-
| `wherdr open` | Opens wherdr in the browser
|
|
468
|
-
| `wherdr phone` | Whether your phone can reach wherdr (Tailscale, `tailscale serve`, the address answering), the
|
|
623
|
+
| `wherdr open` | Opens wherdr in the browser: its tailnet address when published and answering, else `localhost`. |
|
|
624
|
+
| `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. |
|
|
469
625
|
| `wherdr service install` · `uninstall` | Start at login: a LaunchAgent on macOS (`~/Library/LaunchAgents/dev.wherdr.plist`), a `systemd --user` unit on Linux (`loginctl enable-linger` keeps it running while you are logged out). |
|
|
470
626
|
| `wherdr doctor` | Checks Node/Bun, Herdr and its socket, the port, the service, the data folder and `APP_URL`. |
|
|
471
627
|
|
|
@@ -553,8 +709,8 @@ setup by itself:
|
|
|
553
709
|
`~/wherdr` (`docker-compose.yml`, `.env`), the same files as `WHERDR_MODE=docker` of
|
|
554
710
|
[the one command](#the-one-command).
|
|
555
711
|
- **Node.js 22** everywhere else, and always on macOS (Docker Desktop cannot reach Herdr's
|
|
556
|
-
socket): the plugin downloads the prebuilt
|
|
557
|
-
|
|
712
|
+
socket): the plugin downloads the prebuilt package of its version from GitHub Releases and
|
|
713
|
+
verifies its SHA-256 checksum, copies it to `~/wherdr/app` and runs it detached from there, with
|
|
558
714
|
its pid and log (`wherdr.log`) in `~/wherdr`. Herdr builds plugins in a temporary folder and
|
|
559
715
|
then moves them, so the server never runs from the plugin folder. Bun works too when Node.js 22
|
|
560
716
|
is missing. Without either, the install stops and says so.
|
|
@@ -594,7 +750,7 @@ Without a key: `herdr plugin action invoke panel --plugin afloury.wherdr`. The p
|
|
|
594
750
|
| Action | What it does |
|
|
595
751
|
|---|---|
|
|
596
752
|
| `panel` | The **wherdr** panel (a popup) |
|
|
597
|
-
| `open` | Opens wherdr in the browser |
|
|
753
|
+
| `open` | Opens wherdr in the browser (its tailnet address when published and answering) |
|
|
598
754
|
|
|
599
755
|
Up to 1.2.0 the panel action was called `wherdr`: change a key bound to `afloury.wherdr.wherdr` to
|
|
600
756
|
`afloury.wherdr.panel` (Herdr has no action aliases; the install warns about such a key and
|
|
@@ -676,6 +832,45 @@ home screen and in Settings › About, with the release notes and the exact comm
|
|
|
676
832
|
Hide it until the next version with ×. Set `WHERDR_UPDATE_CHECK=off` to disable the check. The
|
|
677
833
|
installed version is shown in Settings › About.
|
|
678
834
|
|
|
835
|
+
GitHub release packages (including the bundled agent skill), Docker images, and Homebrew
|
|
836
|
+
updates are published without waiting for npm moderation. Native plugin installs and updates
|
|
837
|
+
use the GitHub `.tgz` and verify its SHA-256 checksum before extraction. A failed one-tap
|
|
838
|
+
download or checksum check leaves the running version in place. Plugin installation tries
|
|
839
|
+
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.
|
|
840
|
+
This also keeps older 1.3.x releases without GitHub archives installable with Node.js or Bun.
|
|
841
|
+
Packages predating the bundled skill retain the plugin checkout's commands and skill, so
|
|
842
|
+
skill refresh, installation and uninstallation remain available.
|
|
843
|
+
The installer fetches `main` explicitly unless you set `WHERDR_REF`.
|
|
844
|
+
|
|
845
|
+
The SHA-256 checksum detects damaged downloads. It is served beside the archive, so someone
|
|
846
|
+
who can replace both files can make them match; it does not prove the publisher’s identity
|
|
847
|
+
or protect against replacement of the archive and checksum together.
|
|
848
|
+
|
|
849
|
+
`npm install -g`, `npx`, `bunx` and `pnpm dlx` still need npm to serve the wherdr package.
|
|
850
|
+
Their banner waits for registry availability; Homebrew's banner waits for its formula.
|
|
851
|
+
Versions through 1.3.2 use GitHub's `latest` marker and an npm-based updater. That marker only
|
|
852
|
+
advances once npm **and** Homebrew are ready, so their existing Update button continues to work.
|
|
853
|
+
To update an older native plugin earlier, rerun the installer or press **U** in its Herdr panel.
|
|
854
|
+
See [Releasing](docs/RELEASING.md) for the publication order and recovery steps.
|
|
855
|
+
|
|
856
|
+
**Update in one tap.** When wherdr runs from the Herdr plugin (Node.js mode), a global npm install
|
|
857
|
+
or Homebrew, the banner has an **Update** button instead of the command, for a session opened on
|
|
858
|
+
this computer (`localhost`) or unlocked with a passkey. wherdr installs the new version in a
|
|
859
|
+
process of its own, restarts, and checks that `/api/health` reports the new version within 60
|
|
860
|
+
seconds; the app shows the progress and reloads on the new version. If the new version does not
|
|
861
|
+
answer, wherdr goes back to the previous one by itself (the plugin keeps the previous copy in
|
|
862
|
+
`~/wherdr/app.prev`, npm reinstalls the previous version, Homebrew points back to the previous keg)
|
|
863
|
+
and the app says so. Every step is logged in `~/wherdr/update.log`.
|
|
864
|
+
|
|
865
|
+
| Setup | What Update does |
|
|
866
|
+
| --- | --- |
|
|
867
|
+
| Herdr plugin, Node.js | Verifies and unpacks the GitHub release package of the new version into `~/wherdr/app`, keeps the old copy, restarts |
|
|
868
|
+
| `npm install -g wherdr` | `npm install -g wherdr@X.Y.Z`, then restarts (login service included) |
|
|
869
|
+
| Homebrew | `brew upgrade wherdr`, then `brew services restart wherdr` |
|
|
870
|
+
|
|
871
|
+
Docker shows the command instead: replacing its own container would need the Docker socket (root
|
|
872
|
+
on the host) inside it. `npx wherdr` runs from a temporary folder: run `npx wherdr@latest` again.
|
|
873
|
+
|
|
679
874
|
| Setup | Update command (in the wherdr folder) |
|
|
680
875
|
| --- | --- |
|
|
681
876
|
| Docker, published image (default) | `docker compose pull && docker compose up -d` |
|
|
@@ -734,8 +929,9 @@ All settings are environment variables (`.env` with Docker).
|
|
|
734
929
|
| --- | --- | --- |
|
|
735
930
|
| `PORT` | `7683` | Listening port. |
|
|
736
931
|
| `HOST` | `127.0.0.1` (`npm start`) | Listening address without Docker. Keep it on loopback. |
|
|
737
|
-
| `HOST_LABEL` | server hostname
|
|
738
|
-
| `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. |
|
|
932
|
+
| `HOST_LABEL` | server hostname | Name of this machine in the app (can be renamed in the app). In Docker the installer writes the host's short name; left empty, wherdr shows the name Tailscale gives the machine, else `wherdr`. |
|
|
933
|
+
| `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. |
|
|
934
|
+
| `TAILNET_REFRESH_MS` | `30000` | How often wherdr reads again what `tailscale serve` publishes for its port. |
|
|
739
935
|
| `HERDR_WEB_ALLOWED_HOSTS` | *(empty)* | Additional hostnames or IP addresses allowed to open the app, comma-separated. |
|
|
740
936
|
| `PASSKEY_USER` | `wherdr` | User name stored with the passkeys. |
|
|
741
937
|
| `DATA_DIR` | `./data` | VAPID keys, push subscriptions, passkeys, recent folders. |
|
|
@@ -756,6 +952,92 @@ All settings are environment variables (`.env` with Docker).
|
|
|
756
952
|
In the app, **Settings** holds per-device preferences: language, theme, notifications, terminal
|
|
757
953
|
text size and renderer, typing effect, what the home screen shows, and the passkey lock.
|
|
758
954
|
|
|
955
|
+
**Settings › Conversation › Reply style** chooses how an agent's reply offers to be quoted in
|
|
956
|
+
the field, question by question and point by point (a list item or a paragraph that asks
|
|
957
|
+
nothing), so that one message answers them all:
|
|
958
|
+
|
|
959
|
+
| Style | A question | A point |
|
|
960
|
+
| --- | --- | --- |
|
|
961
|
+
| **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. |
|
|
962
|
+
| **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. |
|
|
963
|
+
| **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. |
|
|
964
|
+
|
|
965
|
+
Every one of these is a button reachable with the keyboard (`Tab`, then `Enter`), and selecting a
|
|
966
|
+
passage still offers **Reply** on it. A quoted question or point shows `✓`.
|
|
967
|
+
|
|
968
|
+
**One syntax for every reference.** Whatever you reply to, the field gets one line that names it,
|
|
969
|
+
and your answer goes on the lines below:
|
|
970
|
+
|
|
971
|
+
```
|
|
972
|
+
↳ Quote message 11:37 ~k3f : I can merge the PR —
|
|
973
|
+
Go ahead.
|
|
974
|
+
↳ Quote point 11:37 ~k3f : Shall I tag the release today? —
|
|
975
|
+
Yes
|
|
976
|
+
↳ Quote decision 11:37 #3 ~k3f : Publish the release notes on the site? —
|
|
977
|
+
No
|
|
978
|
+
```
|
|
979
|
+
|
|
980
|
+
| Line | Written by |
|
|
981
|
+
| --- | --- |
|
|
982
|
+
| `↳ Quote message <time> ~<code> : <start of the message> —` | **Reply** under an agent message. |
|
|
983
|
+
| `↳ Quote point <time> ~<code> : <excerpt> —` | `↳` on a question or a point, **Reply** on a selected passage. |
|
|
984
|
+
| `↳ Quote decision <time> #<n> ~<code> : <question> —` | **Yes**, **No** or `↳` on a row of a decision table. |
|
|
985
|
+
| `↳ Quote decisions <time> #<rows> ~<code> : <questions> —` | **OK to all** on a decision table. |
|
|
986
|
+
| `↳ 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. |
|
|
987
|
+
|
|
988
|
+
- The time is the one shown on the agent's message, so an answer to an earlier message is never
|
|
989
|
+
read as an answer to the last one. The types are the same words in every language.
|
|
990
|
+
- The code after `~` is three characters wherdr derives from the message (and the rank of the
|
|
991
|
+
table, from the second table of a message on). It tells apart two messages of the same minute
|
|
992
|
+
and two tables of one message, whatever the excerpt shows. The field draws it dimmed, like
|
|
993
|
+
the words before the excerpt; the quote of a sent message leaves it out. The rows of **OK to
|
|
994
|
+
all** are the numbers the table really has: `#1-4`, or `#1,4` when rows 2 and 3 do not exist.
|
|
995
|
+
- A reference is a whole line: it starts with `↳` in the first column and ends with ` —` at the
|
|
996
|
+
end of the line, and only there, so an excerpt may hold dashes of its own. The excerpt is plain
|
|
997
|
+
text on one line; a long one is cut with `…` (a message keeps its start, a passage its start
|
|
998
|
+
and its end).
|
|
999
|
+
- Several references fit in one message, each followed by its answer.
|
|
1000
|
+
- Anything else is your own text: a `>` at the start of a line, a `↳` line of an unknown type or
|
|
1001
|
+
with words after its dash. Text you paste never becomes a reference either: a pasted line that
|
|
1002
|
+
reads like one gets a `\` before its `↳`. A long paste, shown as a **Pasted text** card, is
|
|
1003
|
+
sent exactly as it was pasted.
|
|
1004
|
+
- In the conversation, each reference of a sent message shows as a quote; tap it to see the
|
|
1005
|
+
message it names. Messages sent earlier with `> ` lines still show as quotes.
|
|
1006
|
+
|
|
1007
|
+
**Settings › Conversation › Quoted replies** chooses how the field shows these lines: **Tokens,
|
|
1008
|
+
native field** (default) draws each one as a token in the usual field, **Plain text** shows the
|
|
1009
|
+
same lines as text, a fallback if the tokens misbehave. The message sent is the same.
|
|
1010
|
+
|
|
1011
|
+
A **closed question**, one that yes or no answers in full, also gets **Yes** and **No** next to
|
|
1012
|
+
its `↳` (at the end of its row in the list style). A tap refers to the question and writes the
|
|
1013
|
+
answer under it, in the language of the interface, exactly as Reply and typing would; nothing is sent, so several questions can be
|
|
1014
|
+
answered in a row before sending. The keyboard stays down on a phone. Tapping the other answer
|
|
1015
|
+
replaces the first; words you typed under a quote are never replaced. The rule is cautious, and
|
|
1016
|
+
in doubt only Reply is offered: a single sentence that opens like a yes/no question (`Shall I…`,
|
|
1017
|
+
`Do you…`, `Is it…`, `Want me to…`, `Est-ce que…`, `Je lance… ?`, `On…`, `Dois-je…`) or ends
|
|
1018
|
+
with `, OK?` / `, d'accord ?`, with no alternative (`or`, `ou`), no interrogative word (`which`,
|
|
1019
|
+
`how`, `quel`, `comment`…) and no negation.
|
|
1020
|
+
|
|
1021
|
+
A **decision table**, a Markdown table whose rows are numbered questions as a coordinator writes
|
|
1022
|
+
them, gets a panel right under it: **OK to all** refers to the whole table and writes `OK to all`
|
|
1023
|
+
under it (a second tap takes it back), and each row has **Yes**, **No** and `↳`, which refer to
|
|
1024
|
+
the row by its number and write `Yes` or `No` under it, or nothing for an answer in words; a row
|
|
1025
|
+
that asks an open question has `↳` alone. Every answer names the message and the row, even for
|
|
1026
|
+
the last message: the agent may write another one before you send. In French: `OK tout`, `Oui`,
|
|
1027
|
+
`Non`. Here too everything is composed in the field and you send. A table qualifies when it has a
|
|
1028
|
+
number column (a header `#`, `N°`, `No`, `Num`, `ID` or `Q` over short numbers, each once) and a
|
|
1029
|
+
question column, known by its header (`Question`, `Decision`, `Choix`…), by cells that all end
|
|
1030
|
+
with `?`, or by an advice column next to it (`Avis`, `Recommendation`, `Suggestion`…). Any other
|
|
1031
|
+
table is left as it is.
|
|
1032
|
+
|
|
1033
|
+
Above the field, **N questions unanswered** counts the questions of the agent's last message
|
|
1034
|
+
(and the rows of its decision tables) that your draft does not answer yet; tap it to scroll to
|
|
1035
|
+
the first one. A question counts once it is quoted, a row once it is answered, quoted or covered
|
|
1036
|
+
by **OK to all**; when the message asks one thing only, any words you type answer it. The line
|
|
1037
|
+
goes when everything is answered and when you send, and it never shows for earlier messages,
|
|
1038
|
+
while the agent is working, or while it waits on a prompt. It hangs from the top edge of the
|
|
1039
|
+
field, so nothing moves when it comes or goes.
|
|
1040
|
+
|
|
759
1041
|
## Several machines (SSH)
|
|
760
1042
|
|
|
761
1043
|
wherdr also shows the agents of the **SSH machines registered in Herdr** — the ones the Herdr
|
|
@@ -838,14 +1120,15 @@ worktree. It is optional; with it installed, wherdr adds:
|
|
|
838
1120
|
grouped by repository (`Repo web-shop · 2 worktrees`), with their thread number and state.
|
|
839
1121
|
- **Project panel** next to the coordinator (a side panel on a computer, a tab on a phone). It
|
|
840
1122
|
reads the project's `TASKS.md` and shows the lists it has, always in this order, with the open
|
|
841
|
-
threads live (state, progress, report) and resolved threads under Done
|
|
1123
|
+
threads live (state, progress, report) and resolved threads under Done (**Tasks** tab; the
|
|
1124
|
+
**Threads**, **Inbox**, **Routines**, **Settings** and **Memory** tabs are described below):
|
|
842
1125
|
|
|
843
1126
|
| List | Meaning | Buttons |
|
|
844
1127
|
| --- | --- | --- |
|
|
845
1128
|
| **To test** | You confirm the work | Confirm, Problem, Question |
|
|
846
1129
|
| **To decide** | Only you can unblock it | Question, Answer |
|
|
847
1130
|
| **To review** | Pull requests for you | Reviewed, Comment |
|
|
848
|
-
| **In progress** | What threads are really doing | (live threads) |
|
|
1131
|
+
| **In progress** | What threads are really doing | (live threads) Add info |
|
|
849
1132
|
| **In queue** | Decided: the coordinator launches the first one as soon as a thread slot frees | Move up / down, Launch now, Clarify, Remove from queue |
|
|
850
1133
|
| **Blocked** | Waiting for someone or something external | Unblock, Clarify |
|
|
851
1134
|
| **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 |
|
|
@@ -856,9 +1139,76 @@ worktree. It is optional; with it installed, wherdr adds:
|
|
|
856
1139
|
project may only need Backlog, In progress and Done); any other `##` list shows in a neutral
|
|
857
1140
|
style after Backlog. French titles and common synonyms are recognized (À tester, En file,
|
|
858
1141
|
À faire, Plus tard…). Every button sends a ready-made message to the coordinator, which edits
|
|
859
|
-
`TASKS.md` (wherdr never writes it).
|
|
860
|
-
|
|
861
|
-
|
|
1142
|
+
`TASKS.md` (wherdr never writes it). **Add info**, on a working thread, opens a text field:
|
|
1143
|
+
what you type goes to the coordinator, which passes it on to that thread as is. The In queue
|
|
1144
|
+
header shows the thread slots in use (`max_parallel_threads` in `PROJECT.md`) and the next
|
|
1145
|
+
task, plus the machine's global limit when one is set
|
|
1146
|
+
(`2 of 2 thread slots in use on <machine> (all projects)`).
|
|
1147
|
+
- **Threads tab** of the Project panel: every thread of the project, resolved ones included.
|
|
1148
|
+
Open threads are grouped as herdr-projects groups them (Your turn, Ready for review, Working…),
|
|
1149
|
+
each with its machine and agent profile; resolved threads stay in their own folded section,
|
|
1150
|
+
shown by pages of 30. One filter covers both (ID, title, machine, profile). A tap opens the
|
|
1151
|
+
thread's record: state, its **Next** list, branch, dates, and these actions:
|
|
1152
|
+
|
|
1153
|
+
| Action | Command | Asks first |
|
|
1154
|
+
| --- | --- | --- |
|
|
1155
|
+
| **Acknowledge** | `thread ack`: you have seen its report | |
|
|
1156
|
+
| **Restart** | `thread restart`: bring back a thread whose pane is gone or whose start failed | |
|
|
1157
|
+
| **Stop** | `thread stop`: Escape in its agent's pane | Yes |
|
|
1158
|
+
| **Resolve** | `thread resolve`: final copy, then its worktree, merged branch and tab are cleaned up (report and library kept) | Yes |
|
|
1159
|
+
|
|
1160
|
+
Open agent, View report and Pull request are there too when they apply. wherdr only runs
|
|
1161
|
+
these `herdr-projects` commands on the coordinator's machine (and reads `thread show --json`);
|
|
1162
|
+
it writes no thread file itself, and herdr-projects has the last word (it refuses to restart a
|
|
1163
|
+
running thread, for instance): its answer is shown as is. With Docker, **Resolve** runs in
|
|
1164
|
+
the container, where the home folder is read-only: a thread of this machine is resolved and
|
|
1165
|
+
its open workspace removed through Herdr, but its merged branch, or a worktree whose workspace
|
|
1166
|
+
was already closed, may stay. herdr-projects lists what it kept, and
|
|
1167
|
+
`herdr-projects sweep <project>` on the host removes it.
|
|
1168
|
+
- **Inbox tab**: the project's unhandled inbox items, what herdr-projects tells the coordinator
|
|
1169
|
+
(a thread's new report, a routine due, a machine out of reach…), oldest first, up to 100. An
|
|
1170
|
+
item about a thread shows the thread's title and opens it. **Done** (✓) marks one item as
|
|
1171
|
+
handled with `herdr-projects inbox done`; a coordinator that has not read it yet will not see
|
|
1172
|
+
it any more. Summaries are shown as plain text.
|
|
1173
|
+
- **Routines tab**: each routine's schedule, whether it is enabled, its kind (prompt only, or a
|
|
1174
|
+
command and its approval) and its last and next run. Read-only: wherdr never approves,
|
|
1175
|
+
switches or runs a routine, and does not expose the plugin's safety settings.
|
|
1176
|
+
- **Settings tab**, read-only: what the project's `PROJECT.md` sets, the keys
|
|
1177
|
+
`herdr-projects set` changes (name, goal, coordinator and thread profiles,
|
|
1178
|
+
`max_parallel_threads`, `auto_resolve_days`, `nudge`, `mute`, repositories). A key the file
|
|
1179
|
+
leaves out shows the plugin's default, marked as such. Safety settings are not shown.
|
|
1180
|
+
- **Memory tab**, read-only: `MEMORY.md` (the index) and the `.md` files of `memory/`, with the
|
|
1181
|
+
title and hook the index gives them; a file the index does not mention is listed by name. A
|
|
1182
|
+
tap opens one, rendered as Markdown. The coordinator writes memory, wherdr never does.
|
|
1183
|
+
|
|
1184
|
+
With six tabs, the bar scrolls sideways on a phone and in a narrow side panel; a fade on its
|
|
1185
|
+
edge says there are more.
|
|
1186
|
+
|
|
1187
|
+
herdr-projects (0.2.34) has no JSON output for the inbox or the routines: wherdr reads the
|
|
1188
|
+
front matter of the project's `inbox/*.md` files, and the tab-separated lines of
|
|
1189
|
+
`herdr-projects routine list`, showing the run texts (`last … · next …`) as printed. No command
|
|
1190
|
+
prints a project's settings or memory either: those two tabs read the files named above.
|
|
1191
|
+
- **Board** (`H`, or the board button above the agent list): every project, thread, task and
|
|
1192
|
+
agent at a glance, in four columns. Agents outside projects show too. Each card opens what it
|
|
1193
|
+
stands for: a project or task opens its Project panel, a thread opens its agent (or its report
|
|
1194
|
+
once closed), an agent opens its conversation. A project card takes the most urgent column of
|
|
1195
|
+
its cards and counts them; Finished shows the 5 most recent threads and done tasks of each
|
|
1196
|
+
project, **Show all** the rest.
|
|
1197
|
+
|
|
1198
|
+
| Card | Blocked | Todo | Ongoing | Finished |
|
|
1199
|
+
| --- | --- | --- | --- | --- |
|
|
1200
|
+
| **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 |
|
|
1201
|
+
| **Thread** | Its agent is your turn, or *waiting on you* | *Ready for review* | Working, landing, idle | Resolved |
|
|
1202
|
+
| **Agent** | Your turn | | Working, starting, restarting | Done, ready |
|
|
1203
|
+
|
|
1204
|
+
Moving a **task** card (drag and drop on a computer, **Move to…** everywhere) sends the
|
|
1205
|
+
coordinator the Project panel's message when one says it (**Launch now** from To do or In
|
|
1206
|
+
queue, **Launch** from Backlog, **Unblock** from Blocked, **Tested** from To test, **Reviewed**
|
|
1207
|
+
from To review), otherwise `↳ Mark blocked: …`, `↳ Move to To do: …` or `↳ Mark done: …`. The
|
|
1208
|
+
card shows *Sent* until the coordinator has moved the line; only the allowed columns are
|
|
1209
|
+
offered, and To decide tasks wait for your answer. Thread, agent and project cards follow
|
|
1210
|
+
what they do and do not move. The server reads every project at once
|
|
1211
|
+
(`GET /api/board`); a project on an offline machine keeps its last read, marked as such.
|
|
862
1212
|
- **Max threads per machine**, across all projects: herdr-projects only limits threads per
|
|
863
1213
|
project, so three coordinators could still start a dozen threads on one small machine. Set a
|
|
864
1214
|
limit per machine in **Settings → Plugins → herdr-projects** (empty `—` = no global limit;
|
|
@@ -913,17 +1263,57 @@ worktree. It is optional; with it installed, wherdr adds:
|
|
|
913
1263
|
|
|
914
1264
|
The Project panel only works well when the coordinator follows its conventions: which lists
|
|
915
1265
|
mean what, the badges, `(agent → t-NNNN)`, and what to do with each message the buttons send
|
|
916
|
-
(`✓ Tested: …`,
|
|
1266
|
+
(`✓ Tested: …`, `↳ Queue: …`, `↳ Problem: … —` or `↳ Decision: … —` with the answer below it…). They are written once, as an agent skill:
|
|
917
1267
|
[`skills/wherdr/SKILL.md`](skills/wherdr/SKILL.md).
|
|
918
1268
|
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
1269
|
+
The npm package (also used by Homebrew) and Docker image include the skill from that
|
|
1270
|
+
release. Installation is best effort: a missing agent or an unwritable home never blocks
|
|
1271
|
+
wherdr. It links `~/.claude/skills/wherdr` (or `$CLAUDE_CONFIG_DIR/skills/wherdr`) only
|
|
1272
|
+
when the Claude configuration folder exists, and `~/.agents/skills/wherdr` only when
|
|
1273
|
+
`.agents`, `.codex` or `.omp` exists. Links point to a stable copy in
|
|
1274
|
+
`${WHERDR_DIR:-$HOME/wherdr}/skills/wherdr`. Existing skills from elsewhere are left alone.
|
|
1275
|
+
Relative `WHERDR_DIR` resolves from the working directory; relative `CLAUDE_CONFIG_DIR`
|
|
1276
|
+
resolves from HOME, including when saved in a login service. Unchanged content is not rewritten.
|
|
1277
|
+
A broken link is repaired only when local metadata proves wherdr created it.
|
|
1278
|
+
|
|
1279
|
+
| Install mode | Skill installation and refresh |
|
|
1280
|
+
| --- | --- |
|
|
1281
|
+
| npm / npx / Bun / pnpm | On `wherdr`, `wherdr run`, `wherdr start` or `wherdr service install`; after updating the package, the next start refreshes it. |
|
|
1282
|
+
| Homebrew | On `wherdr` startup, including the Homebrew service; restart the service after `brew upgrade`. |
|
|
1283
|
+
| 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. |
|
|
1284
|
+
| Herdr plugin, Node.js | On plugin installation / reinstallation, and on startup from its installed package. |
|
|
1285
|
+
| Herdr plugin, Docker | On plugin installation and Update, extracted from the pulled image on the host. |
|
|
1286
|
+
| One-command installer, Docker | After each pull, including reruns and `WHERDR_MODE=docker`; saves host helpers in `$WHERDR_DIR/skill-installer`. |
|
|
1287
|
+
| Docker by hand | Run the host-side command below after the initial pull and after each image update. |
|
|
1288
|
+
| 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. |
|
|
1289
|
+
|
|
1290
|
+
Docker cannot write the host's agent folders through its read-only home mount. From the
|
|
1291
|
+
repository checkout on the **host**, after pulling your image, run:
|
|
1292
|
+
|
|
1293
|
+
```sh
|
|
1294
|
+
sh bin/install-docker-skill.sh ghcr.io/afloury/wherdr:latest
|
|
1295
|
+
```
|
|
1296
|
+
|
|
1297
|
+
Pass your image tag if different. The helper creates a stopped temporary container, copies
|
|
1298
|
+
only `/app/skills/wherdr/SKILL.md` out of it, uses the local host installer, then removes
|
|
1299
|
+
the container. No host home is mounted into it. Repeat this command after each manual Docker update; Docker has no one-tap
|
|
1300
|
+
update in the app. Manual failures (including older images without the skill) return a
|
|
1301
|
+
nonzero status with diagnostics; plugin and one-command installation warn and continue. Without a checkout, use
|
|
1302
|
+
`sh "${WHERDR_DIR:-$HOME/wherdr}/skill-installer/bin/install-docker-skill.sh" <image>` after the one-command install.
|
|
1303
|
+
|
|
1304
|
+
Remove managed links with `sh bin/lib/install-skill.sh uninstall` (or
|
|
1305
|
+
`sh scripts/herdr-plugin.sh skill uninstall` in the plugin folder). Uninstall leaves
|
|
1306
|
+
`~/.local/state/wherdr/skill-disabled`: subsequent starts and updates respect it, even if
|
|
1307
|
+
`WHERDR_DIR` changes. To re-enable, explicitly run `sh bin/lib/install-skill.sh install`
|
|
1308
|
+
or the plugin's `skill install` (or the Docker host helper above). `WHERDR_SKILL=off`
|
|
1309
|
+
disables all installation and refresh, including explicit install; export it for interactive
|
|
1310
|
+
starts or set it when installing the login service to preserve it there.
|
|
1311
|
+
|
|
1312
|
+
Two limitations remain: rollback to an older package without the helper (such as 1.3.2)
|
|
1313
|
+
leaves the failed release's skill in place. With multiple wherdr versions sharing an account,
|
|
1314
|
+
the last one started supplies the skill; there is no version comparison.
|
|
1315
|
+
|
|
1316
|
+
You can also paste **Settings → Plugins → herdr-projects → Copy rules for the coordinator** to your agent.
|
|
927
1317
|
|
|
928
1318
|
## Herdr plugins
|
|
929
1319
|
|
|
@@ -969,7 +1359,9 @@ container talks to the Herdr server running on the host.
|
|
|
969
1359
|
(port forwarding, public reverse proxy, ngrok…); the only exception is a Cloudflare Tunnel
|
|
970
1360
|
behind Cloudflare Access, with its risks.
|
|
971
1361
|
- Requests are accepted only for `localhost`, loopback addresses, the runtime's hostname, the
|
|
972
|
-
hostname in `APP_URL`,
|
|
1362
|
+
hostname in `APP_URL`, the tailnet name `tailscale serve` publishes for wherdr's own port
|
|
1363
|
+
(read from Tailscale on the machine, never from a request, and only while it is published),
|
|
1364
|
+
and the runtime's network interface addresses (those of the container
|
|
973
1365
|
with Docker). Add other private names or IP addresses to `HERDR_WEB_ALLOWED_HOSTS`
|
|
974
1366
|
(comma-separated) before using them. An unlisted name returns HTTP 403 (`host` / "Host not
|
|
975
1367
|
allowed"); add it to `HERDR_WEB_ALLOWED_HOSTS`, then restart wherdr. This host check also
|
|
@@ -1017,8 +1409,10 @@ See [SECURITY.md](SECURITY.md) to report a vulnerability.
|
|
|
1017
1409
|
(`herdr integration install claude|codex|omp`) and start a new agent.
|
|
1018
1410
|
- **Passkeys or notifications unavailable**: the page must be served over HTTPS (or
|
|
1019
1411
|
`localhost`). On iPhone, notifications need the app installed on the home screen.
|
|
1020
|
-
- **HTTP 403
|
|
1021
|
-
|
|
1412
|
+
- **HTTP 403 "This address isn't enabled yet"**: for a tailnet address, run the command the
|
|
1413
|
+
page gives on the machine: it tells whether `tailscale serve` publishes wherdr's port there.
|
|
1414
|
+
For another private name, add the hostname or IP address to `HERDR_WEB_ALLOWED_HOSTS`, or use
|
|
1415
|
+
the hostname in `APP_URL`, then restart wherdr.
|
|
1022
1416
|
- **Remote machine offline**: `docker compose logs | grep machine` shows its state. Test SSH as
|
|
1023
1417
|
wherdr does, from the container:
|
|
1024
1418
|
`docker compose exec herdr-web ssh -o BatchMode=yes laptop '~/.local/bin/herdr status server'`.
|