HerdR plugin artisann.zed-herdr keeps the active HerdR workspace available in Zed without taking ownership of either application. It supports macOS and Linux, HerdR 0.7.3+ reporting protocol 16 or newer (tested through protocol 22, HerdR 0.9.3), Bun, Git, and Zed with its zed CLI available.
For contributor architecture and subsystem internals, see the documentation index.
Run plugin commands from a HerdR environment (HERDR_ENV=1), then build and link this checkout:
cd zed-herdr
bun install --frozen-lockfile
bun run build
herdr plugin link ImArtisann/zed-herdr
herdr plugin enable artisann.zed-herdrLinking makes the local checkout available to HerdR; enabling activates its declared hooks. The plugin starts automatically for workspace.created and workspace.focused events. Its hook opens its own unfocused Zed Workspace Sync tab only when no live plugin daemon is available.
For direct development, run the same daemon without the plugin host:
bun run dev
# or, without watch mode:
bun run startBoth commands require access to the current HerdR session socket. The built artifact can also be started directly with bun ./dist/index.js daemon.
Ask the daemon on the current session's control socket for its health:
bun dist/index.js healthA successful response is JSON shaped like:
{
"ok": true,
"daemon": {
"identity": "artisann.zed-herdr:daemon",
"paneId": "<pane-id>",
"pid": 1234,
"startedAt": "2026-01-01T00:00:00.000Z",
"protocol": 22,
"beyondTested": false
}
}identity identifies this plugin's owner-validated local daemon, paneId is the plugin pane that hosts it (or null when not injected by HerdR), and pid/startedAt identify that daemon instance. protocol is the last protocol accepted from HerdR, or null before negotiation; beyondTested is true when it is newer than protocol 22. Exit status 1 means no valid matching daemon answered; it does not start one.
Use the plugin registry and plugin log to inspect the installation:
herdr plugin list --plugin artisann.zed-herdr --json
herdr plugin log list --plugin artisann.zed-herdr --limit 100Use the paneId from health (or the response from a manual plugin-pane open) to inspect the daemon terminal:
herdr pane read <pane-id> --source recent-unwrapped --lines 100 --format textHerdR 0.7.3 exposes plugin-pane open, focus, and close operations; use the health response rather than relying on a plugin-pane listing command.
Set ZED_BIN to a non-empty executable path to select a Zed CLI explicitly:
export ZED_BIN=/absolute/path/to/zedWithout ZED_BIN, the daemon resolves zed from PATH; on macOS an executable-not-found result also tries Zed's standard application CLI path. It invokes only zed -e <absolute-git-root>.
For HerdR transport, HERDR_SOCKET_PATH takes precedence. Otherwise the socket is resolved as:
$XDG_CONFIG_HOME/herdr/sessions/$HERDR_SESSION/herdr.sockfor a named session, or~/.config/herdr/sessions/$HERDR_SESSION/herdr.sockwhenXDG_CONFIG_HOMEis unset.$XDG_CONFIG_HOME/herdr/herdr.sock, or~/.config/herdr/herdr.sock, when there is no named session.
The daemon reads HerdR snapshots and lifecycle events, then asks Zed to add/focus a validated Git root. It never sends a mutating HerdR request, kills a process, reuses an existing pane, replaces Zed window/project state, accesses Zed's private storage, or uses Zed's state-replacing CLI options. Non-worktree workspaces wait for the plugin hook's workspace cwd hint; ambiguous, inaccessible, or non-Git paths are skipped.
HerdR plugin manifests declare actions but do not install user keybindings. Add this command binding
to ~/.config/herdr/config.toml:
[[keys.command]]
key = "prefix+shift+z"
type = "plugin_action"
command = "artisann.zed-herdr.toggle"
description = "Toggle Zed workspace sync"Apply it to the running HerdR server:
herdr server reload-configThen press the HerdR prefix followed by Shift+Z. Disabling interrupts in-flight synchronization
and suppresses new Zed calls while HerdR remains authoritative. Re-enabling requests a fresh
snapshot for the current generation.
The same action is available from the built CLI:
bun dist/index.js toggleIt prints {"ok":true,"enabled":false} or {"ok":true,"enabled":true}. A newly started daemon
begins enabled. This runtime pause is separate from herdr plugin disable, which disables the
action target but leaves the user-configured keybinding in place.
- Protocol mismatch: HerdR must report protocol 16 or newer. A value below 16 is logged as
herdr_protocol_unsupportedand stops reconnecting rather than guessing or downgrading. Newer values are accepted; values above the highest tested protocol are reported byhealthwithbeyondTested: trueand logherdr_protocol_beyond_testedonce. - Socket or health failure: confirm
HERDR_SOCKET_PATH,HERDR_SESSION, andXDG_CONFIG_HOMEdescribe the intended session, then inspect the plugin log and daemon pane output above. Focusing or creating a workspace will run the activation hook again. - Zed errors: ensure
ZED_BINpoints to an executable, or thatzedis onPATH; inspect the daemon output for the failedzed -ecommand. The daemon leaves HerdR and existing Zed state unchanged when Zed rejects or times out.
For a linked checkout, stop future hook activation and remove the link:
herdr plugin disable artisann.zed-herdr
herdr plugin unlink artisann.zed-herdrFor a plugin installed from a remote source instead of linked from this checkout, use:
herdr plugin uninstall artisann.zed-herdr