diff --git a/plugins/herdr/README.md b/plugins/herdr/README.md new file mode 100644 index 000000000..5a24f23c7 --- /dev/null +++ b/plugins/herdr/README.md @@ -0,0 +1,163 @@ +# herdr plugin + +This plugin adds completion, aliases, an interactive session picker and a prompt +function for [herdr](https://herdr.dev), the runtime your +coding agents live on. herdr keeps agent terminals running in the background across +projects and machines, so you can close your terminal, reconnect later, and pick up +where the agents left off. + +To use it, add `herdr` to the plugins array in your zshrc file: + +```zsh +plugins=(... herdr) +``` + +Install herdr first if you have not already: + +```sh +curl -fsSL https://herdr.dev/install.sh | sh # or: brew install herdr +``` + +## Learning herdr from the terminal + +The fastest way to explore herdr is tab completion. Every command group and flag shows a +short description, so you can discover what is available without leaving the shell: + +``` +$ herdr +agent -- Control and inspect agent panes +session -- Manage named persistent sessions +workspace -- Manage workspaces over the socket API +worktree -- Manage Git worktree-backed workspaces +... +$ herdr agent +list -- List agents +prompt -- Submit a prompt to an agent +start -- Start a supported interactive agent in an existing pane +wait -- Wait until an agent reaches one of the requested states +... +``` + +A few other ways to learn as you go: + +- `herdr ` with no subcommand prints that group's help, for example `herdr pane`. +- `herdr --skill` prints the instructions herdr gives to agents that drive it. It is a + good tour of the full command surface. +- Most control commands return JSON, so you can pipe them into `jq` in scripts. + +## Common workflows + +### Start and reconnect + +```sh +herdr # launch, or attach to the default session +herdr --session work # use or create a named session +herdr session list # see running and stopped sessions +herdr session attach work # reconnect to a named session +herdr status # check the local client and running server +herdr update # install the latest release +``` + +### Organize work into workspaces and tabs + +```sh +herdr workspace list +herdr workspace create --cwd ~/projects/app +herdr tab create +herdr pane split --direction right +herdr worktree create --branch feature/login # open a Git worktree in its own workspace +``` + +### Run and watch agents + +```sh +herdr agent list # what is running, and is it idle, working or blocked +herdr agent start reviewer --kind claude --pane w1:p2 +herdr agent prompt reviewer "review the last commit" --wait +herdr agent read reviewer # read the agent's terminal output +herdr agent wait reviewer --until idle +herdr agent attach reviewer # jump straight into that terminal +``` + +### Work across machines + +```sh +herdr --remote user@build-box # attach through SSH with your local keybindings +``` + +### Keep the server healthy + +```sh +herdr config check # validate config.toml +herdr server reload-config # apply config changes without restarting panes +herdr server stop +herdr channel set preview # switch between stable and preview releases +herdr integration status # which agent CLIs have herdr hooks installed +``` + +See the [CLI reference](https://herdr.dev/docs/cli-reference/) for every command and flag. + +## Aliases + +| Alias | Command | +| ------- | ----------------------------- | +| `hrdr` | `herdr` | +| `hrdrst` | `herdr status` | +| `hrdrup` | `herdr update` | +| `hrdrsl` | `herdr session list` | +| `hrdrsa` | `herdr session attach` | +| `hrdrr` | `herdr --remote` | +| `hrdral` | `herdr agent list` | +| `hrdrwl` | `herdr workspace list` | +| `hrdrwc` | `herdr workspace create` | +| `hrdrwt` | `herdr worktree create` | +| `hrdrps` | `herdr pane split` | +| `hrdrrc` | `herdr server reload-config` | + +Tab completion works through the aliases too, so `hrdr agent ` completes the same +way `herdr agent ` does. + +## Session picker + +`hrdrs` lists your herdr sessions and attaches to the one you pick. It uses +[fzf](https://github.com/junegunn/fzf) when it is installed and falls back to a numbered +menu otherwise, so it works everywhere. + +``` +$ hrdrs +name status directory +1) default running /Users/me/.config/herdr +2) work stopped /Users/me/projects/app +Attach to session: 2 +``` + +## Prompt + +This plugin provides the `herdr_prompt_info` function to show the current pane ID in +your prompt when the shell is running inside herdr. It reads environment variables only, +so it adds no cost to prompt rendering. + +For example: +``` +PROMPT="%~$ " +RPROMPT='$(herdr_prompt_info)' +``` +changes your prompt inside a herdr pane to: +``` +~/projects/app$ ▋ w1:p4 +``` +and shows nothing outside herdr. + +Wrap it with `ZSH_THEME_HERDR_PROMPT_PREFIX` and `ZSH_THEME_HERDR_PROMPT_SUFFIX`, for +example: +``` +ZSH_THEME_HERDR_PROMPT_PREFIX="%{$fg[cyan]%}[herdr " +ZSH_THEME_HERDR_PROMPT_SUFFIX="]%{$reset_color%}" +``` + +## Cache + +This plugin caches the completion script and automatically updates it when the plugin is +loaded, which is usually when you start a new terminal emulator. + +The cache is stored at `$ZSH_CACHE_DIR/completions/_herdr`. diff --git a/plugins/herdr/herdr.plugin.zsh b/plugins/herdr/herdr.plugin.zsh new file mode 100644 index 000000000..e5d12eed6 --- /dev/null +++ b/plugins/herdr/herdr.plugin.zsh @@ -0,0 +1,68 @@ +# Aliases, helpers and completion for herdr (https://herdr.dev), the runtime for coding agents. + +# PROMPT +# Defined before the herdr check so themes can reference it on machines without herdr. +function herdr_prompt_info { + [[ "$HERDR_ENV" == 1 ]] || return + echo "${ZSH_THEME_HERDR_PROMPT_PREFIX}${HERDR_PANE_ID:gs/%/%%}${ZSH_THEME_HERDR_PROMPT_SUFFIX}" +} + +if (( ! $+commands[herdr] )); then + return +fi + +# ALIASES +alias hrdr='herdr' +alias hrdrst='herdr status' +alias hrdrup='herdr update' +alias hrdrsl='herdr session list' +alias hrdrsa='herdr session attach' +alias hrdrr='herdr --remote' +alias hrdral='herdr agent list' +alias hrdrwl='herdr workspace list' +alias hrdrwc='herdr workspace create' +alias hrdrwt='herdr worktree create' +alias hrdrps='herdr pane split' +alias hrdrrc='herdr server reload-config' + +# FUNCTIONS +# Pick a session and attach to it, with fzf if available or a numbered menu otherwise. +function hrdrs { + setopt localoptions extendedglob + local -a lines + lines=("${(@f)$(herdr session list 2>/dev/null)}") + lines=("${(@)lines%%[[:space:]]#[^[:space:]]#}") # drop the socket column + if (( $#lines < 2 )); then + print "hrdrs: no herdr sessions found" >&2 + return 1 + fi + + local choice + if (( $+commands[fzf] )); then + choice=$(print -l -- "${lines[@]}" | fzf --header-lines=1 --prompt='herdr session> ') || return + else + print -- "${lines[1]}" + local PS3="Attach to session: " + select choice in "${lines[@]:1}"; do + [[ -n "$choice" ]] && break + done + fi + [[ -n "$choice" ]] || return 1 + + herdr session attach "${${(z)choice}[1]}" +} + +# COMPLETION +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `herdr`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_herdr" ]]; then + typeset -g -A _comps + autoload -Uz _herdr + _comps[herdr]=_herdr +fi + +zmodload -F zsh/files b:zf_mv +() { + local TMPPREFIX="$ZSH_CACHE_DIR/completions/_herdr" + zf_mv -f -- =( herdr completion zsh < /dev/null 2> /dev/null ) "$TMPPREFIX" +} &|