aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-04-21 17:14:40 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-04-21 17:14:40 +0300
commit8a4571198d013451743d1238f80a6bd69d67b32d (patch)
tree6c682d650211083da60a5d5bb412ebd09daf2f80
parentf99d51e42e2bcb5f18f6eb962a4a08d6b05cceda (diff)
docs: revert readme and website before persistent sessions
-rw-r--r--README.md341
-rw-r--r--website/assets/sidebar-agents.pngbin10434 -> 5900 bytes
-rw-r--r--website/assets/sidebar-workspaces.pngbin7466 -> 5344 bytes
-rw-r--r--website/css/style.css719
-rw-r--r--website/index.html1626
5 files changed, 1193 insertions, 1493 deletions
diff --git a/README.md b/README.md
index fa32e165..20c3539d 100644
--- a/README.md
+++ b/README.md
@@ -1,23 +1,40 @@
-# herdr
-
-
<p align="center">
- <img src="assets/logo.png" alt="herdr" width="100" />
+ <img src="assets/logo.png" alt="herdr" width="120" />
</p>
+<h1 align="center">herdr</h1>
+
+<p align="center"><strong>supervise multiple coding agents in one terminal.</strong></p>
+
+<p align="center">herd your agents.</p>
+
<p align="center">
- <a href="https://herdr.dev">herdr.dev</a> · <a href="#install">install</a> · <a href="#quick-start">quick start</a> · <a href="#supported-agents">supported agents</a> · <a href="./INTEGRATIONS.md">integrations</a> · <a href="./CONFIGURATION.md">configuration</a> · <a href="./SOCKET_API.md">socket api</a>
+ <a href="https://herdr.dev">herdr.dev</a> · <a href="#install">install</a> · <a href="#quick-start">quick start</a> · <a href="#supported-agents">supported agents</a> · <a href="./INTEGRATIONS.md">integrations</a> · <a href="./CONFIGURATION.md">configuration</a> · <a href="./SKILL.md">agent skill</a> · <a href="./SOCKET_API.md">socket api</a>
</p>
---
+herdr is a terminal-native workspace manager for coding agents.
+
+run Claude Code, Codex, pi, opencode, droid, amp and plain shells side by side in your existing terminal. herdr gives you workspaces, tabs, panes, automatic agent detection, and notification alerts so you can see which agent is blocked, done, or still working without leaving the command line.
+
+it runs inside ghostty, alacritty, kitty, wezterm, and even inside tmux. it is a single Rust binary, not a separate GUI window, electron wrapper, or web dashboard.
+
https://github.com/user-attachments/assets/043ec09f-4bdd-41d5-aee0-8fda6b83e267
-**agent multiplexer that lives in your terminal.**
+## why herdr
-workspaces, tabs, panes. mouse-native: click, drag, split. every agent at a glance: blocked, working, done. detach and reattach, agents keep running. no gui app, no electron, no mac-only native wrapper. you see the agent's own terminal, not someone's interpretation of it.
+running one coding agent is easy. running several in parallel gets messy fast.
----
+most tools in this space either replace your environment or give you panes without any awareness of what those panes are doing. herdr stays inside your terminal and adds the missing layer: supervision.
+
+with herdr you can:
+
+- run multiple coding agents in parallel in one terminal-native workspace
+- scan workspaces quickly and see which one needs attention
+- spot whether an agent is blocked, finished, working, or idle
+- jump between repos, tabs, and panes without losing context
+- let agents create panes, spawn helpers, read output, and wait on each other through the local api
## install
@@ -25,11 +42,15 @@ workspaces, tabs, panes. mouse-native: click, drag, split. every agent at a glan
curl -fsSL https://herdr.dev/install.sh | sh
```
-or download the binary from [releases](https://github.com/ogulcancelik/herdr/releases). requires linux or macos.
+or download the binary directly from [releases](https://github.com/ogulcancelik/herdr/releases).
+
+requirements: linux or macos.
### update
-herdr notifies you when a new version is available. run manually to update:
+herdr checks for updates automatically in the background. when a new version is ready, you'll see a notification in the ui. restart to apply it.
+
+for a manual update:
```bash
herdr update
@@ -37,102 +58,82 @@ herdr update
## quick start
+launch herdr:
+
```bash
herdr
```
-by default herdr launches or attaches to a background session server. `ctrl+b q` detaches the client. agents keep running. use `herdr server stop` to stop the server. use `--no-session` for the old single-process mode.
+then do this:
1. press `n` to create a workspace
2. run an agent in the root pane
3. press `ctrl+b` to enter navigate mode
4. use `v` or `-` to split panes, or `c` to create a new tab
-5. watch the sidebar for blocked, working, and done states
+5. run more agents side by side
+6. watch the sidebar to see which workspace or agent needs attention
-on first run herdr opens a short onboarding flow. after that, restored sessions land in terminal mode; fresh sessions start in **navigate mode**.
+on first run, herdr opens a short onboarding flow so you can choose your notification style. after that, if a session is restored you'll land in terminal mode; otherwise you'll start in **navigate mode**.
-## how it compares
+## what you get
-| | tmux | gui managers | herdr |
-|--------------------------|------|--------------|-------|
-| persistent sessions | ✓ | — | ✓ |
-| detach / reattach | ✓ | — | ✓ |
-| panes, tabs, workspaces | ✓ | ✓ | ✓ |
-| agent awareness | — | ✓ | ✓ |
-| lives in your terminal | ✓ | — | ✓ |
-| real terminal views | ✓ | — | ✓ |
-| mouse-native | — | ✓ | ✓ |
-| lightweight binary | ✓ | — | ✓ |
-| agents can orchestrate | ? | ? | ✓ |
+### workspaces, tabs, and panes
-tmux gives you persistence and panes, but it was built before agents existed. gui managers show agent state, but they make you leave your terminal and use their wrapped view. herdr is persistence and awareness in one tool that stays out of your way.
+herdr is organized around workspaces. each workspace can contain multiple tabs, and each tab can contain multiple panes.
-## persistence
+workspaces open immediately as real terminal contexts. the first pane in a workspace is the **root pane**. it anchors the workspace and gives it its default identity:
-start herdr on your desktop or server. run your agents, split panes, do your work. press `ctrl+b q` to detach. close your terminal, close your laptop; your agents keep running. open a new terminal, run `herdr`, you're back. same session, same panes, same agents.
+- if the root pane is inside a git repo, the workspace label defaults to the repo name
+- otherwise it falls back to the current folder name
+- manual rename is supported, but the default model is repo or folder first
-### from anywhere
+this keeps workspaces lightweight. they are project contexts first, labels second.
-need to check on your agents from your phone? just ssh in and run herdr. any ssh client works. no app to download, no account to create.
+### awareness and notifications
-```
-ssh you@yourserver
-herdr
-```
+the sidebar is split into two layers:
-same session, same agents, same state.
+- **top:** workspaces, each with one aggregate state dot
+- **bottom:** detected agents inside the selected workspace, or across all workspaces when you switch the agent panel scope
-## agent awareness
+herdr automatically detects running agents by looking at the foreground process and reading terminal output. workspace rollups surface the most urgent thing happening in each workspace so you can scan the full list quickly.
-the sidebar shows which agents are blocked, working, or done. workspaces roll up to their most urgent state so you can scan the full list at a glance.
+in expanded view, the workspace list and agent list have their own resizable sections. in collapsed view, you still get compact per-pane agent indicators.
-states:
+states map to:
- 🔴 **blocked** — agent needs input or approval
+- 🔵 **done** — work finished and you have not looked at it yet
- 🟡 **working** — agent is actively running
-- 🔵 **done** — work finished, you have not looked at it yet
-- 🟢 **idle** — done and seen
-
-detection works by reading foreground process and terminal output. zero config, no hooks required. for agents that expose hooks, the socket api integration gives more robust state reporting.
-
-## lives in your terminal
+- 🟢 **idle** — done, seen, and calm
-not a gui window, not a web dashboard, not electron. herdr runs inside whatever terminal you already use. single rust binary, no dependencies. works inside tmux.
+rollups prefer the most urgent state in a workspace: blocked first, then unseen finished work, then working, then idle.
-## what you get
-
-- **workspaces** — organized around git repos or folder names, each with its own tabs and panes
-- **tabs** — first-class in the socket api and cli
-- **mouse-native** — click panes, drag borders, select text to copy; not keyboard-only
-- **notifications** — sounds and toasts for background events; tab-aware suppression
-- **9 built-in themes** — catppuccin (default), tokyo night, dracula, nord, gruvbox, one dark, solarized, kanagawa, rosé pine
-- **session persistence** — pane processes survive client detach; sessions restore after full restart
+plain shells still matter to the workspace itself, but the sidebar stays focused on actual agents.
-## agents can use herdr too
+if ambient sidebar awareness is not enough, herdr can also play sounds or show top-right toast notifications for background events. notification suppression is tab-aware: the active tab stays quiet, but background tabs in the same workspace can still alert.
-the local unix socket lets agents create workspaces, split panes, spawn helpers, read output, and wait for state changes.
+### agents can use herdr too
-```bash
-# create a workspace and tab
-herdr workspace create --cwd ~/project --label "api"
-herdr tab create --label "logs"
+herdr is not only for humans supervising agents. it is also becoming a shared control surface for the agents themselves.
-# split a pane and run
-herdr pane split 1-1 --direction right
-herdr pane run 1-2 "npm test"
+agents running inside herdr can use the local socket api and cli wrappers to:
-# wait for an agent
-herdr wait agent-status 1-1 --status done
-
-# read output
-herdr pane read 1-2 --source recent --lines 50
-```
+- create new workspaces for parallel tasks
+- create, focus, rename, and close tabs
+- split panes for servers, logs, tests, or scratch work
+- spawn other agents in sibling panes
+- read pane output or wait for output matches
+- send text and keys into other panes
+- wait for another agent to finish before continuing
-full reference: [`SOCKET_API.md`](./SOCKET_API.md) and [`SKILL.md`](./SKILL.md).
+for that workflow, start with [`SKILL.md`](./SKILL.md) if you want a reusable agent skill, or [`SOCKET_API.md`](./SOCKET_API.md) if you want the low-level socket protocol and cli wrapper reference.
## supported agents
-automatic detection works out of the box. process name matching plus terminal output heuristics.
+herdr detects supported agents automatically with zero setup. it identifies the foreground process in each pane and reads the live bottom of the terminal buffer to infer agent state. for agents that expose hooks or plugins, direct integrations are the more robust path because they forward semantic state to herdr over the local socket api.
+
+the following agents have been tested:
| agent | idle / done | working | blocked |
|-------|-------------|---------|---------|
@@ -143,13 +144,30 @@ automatic detection works out of the box. process name matching plus terminal ou
| [amp](https://ampcode.com) | ✓ | ✓ | ✓ |
| [opencode](https://github.com/anomalyco/opencode) | ✓ | ✓ | ✓ |
-detected but not fully tested: gemini cli, cursor agent, cline, kimi, github copilot cli.
+heuristics also exist for these agents but have not been fully tested yet:
+
+- [gemini cli](https://github.com/google-gemini/gemini-cli)
+- [cursor agent](https://cursor.com/cli)
+- [cline](https://github.com/cline/cline)
+- [kimi](https://kimi.ai)
+- [github copilot cli](https://cli.github.com)
+
+for any other cli agent, herdr still works as a terminal-native multiplexer. you still get workspaces, panes, tiling, and notifications even when richer state detection is not available yet.
+
+for agents outside the built-in list, herdr also supports custom hook or plugin integrations over the local socket api. a custom integration can report any non-empty agent label, and that label will appear in pane info, events, and the sidebar without needing first-party built-in detection. see [`SOCKET_API.md`](./SOCKET_API.md) for the raw api surface.
+
+## optional direct integrations
-for agents outside the built-in list, herdr still works as a terminal multiplexer with workspaces, panes, and tiling. custom integrations can report agent labels over the socket api. see [`SOCKET_API.md`](./SOCKET_API.md).
+automatic detection works out of the box. if an agent exposes hooks or plugins, the better path is to let it report state to herdr over the local socket api.
-### direct integrations
+herdr ships one-command integrations for:
-the built-in pi, claude code, codex, and opencode integrations forward semantic state to herdr over the socket api. install with:
+- [pi](./INTEGRATIONS.md#pi)
+- [claude code](./INTEGRATIONS.md#claude-code)
+- [codex](./INTEGRATIONS.md#codex)
+- [opencode](./INTEGRATIONS.md#opencode)
+
+install them with:
```bash
herdr integration install pi
@@ -158,45 +176,170 @@ herdr integration install codex
herdr integration install opencode
```
-see [`INTEGRATIONS.md`](./INTEGRATIONS.md) for setup details.
+remove them with:
+
+```bash
+herdr integration uninstall pi
+herdr integration uninstall claude
+herdr integration uninstall codex
+herdr integration uninstall opencode
+```
+
+these integrations forward semantic state to herdr over the local socket api. that gives you more robust status reporting, but it does not replace herdr's core process detection model. for setup details, installed file locations, caveats, and the exact bundled hook or plugin source files, see [`INTEGRATIONS.md`](./INTEGRATIONS.md).
+
+known codex caveat: codex currently renders hook lifecycle lines in its own tui when hooks are enabled. that noise is upstream codex behavior, not herdr-specific.
+
+## usage
+
+### navigate mode
+
+navigate mode is the workspace control layer. press `ctrl+b` to enter it.
+
+movement actions stay in navigate mode. mutating actions like split, close, new workspace, new tab, and sidebar toggle return you to terminal mode.
-## keybindings
+common defaults:
-press `ctrl+b` to enter navigate mode.
+- `n` new workspace
+- `shift+n` rename workspace
+- `d` close workspace
+- `c` new tab
+- `v` / `-` split pane
+- `x` close pane
+- `f` fullscreen
+- `r` resize mode
+- `b` toggle sidebar
+
+optional direct bindings are available but **unset by default**. you can bind workspace, tab, and pane switching directly in terminal mode without going through the prefix first.
+
+prefix mode also supports custom commands with `[[keys.command]]`. that lets you launch detached shell helpers or temporary overlay panes. two common examples are opening `lazygit` in a pane and running your own script with the active herdr ids and cwd.
+
+example:
+
+```toml
+[keys]
+previous_workspace = "ctrl+alt+["
+next_workspace = "ctrl+alt+]"
+previous_tab = "alt+["
+next_tab = "alt+]"
+focus_pane_left = "alt+h"
+focus_pane_down = "alt+j"
+focus_pane_up = "alt+k"
+focus_pane_right = "alt+l"
+
+[[keys.command]]
+key = "g"
+type = "pane"
+command = "lazygit"
+
+[[keys.command]]
+key = "o"
+command = "~/bin/herdr-open-current \"$HERDR_ACTIVE_WORKSPACE_ID\" \"$HERDR_ACTIVE_TAB_ID\" \"$HERDR_ACTIVE_PANE_ID\" \"$HERDR_ACTIVE_PANE_CWD\""
+```
+
+full keybinding and config reference: [`CONFIGURATION.md`](./CONFIGURATION.md)
+
+### resize mode
| key | action |
|-----|--------|
-| `n` | new workspace |
-| `shift+n` | rename workspace |
-| `shift+d` | close workspace |
-| `c` | new tab |
-| `v` / `-` | split pane |
-| `x` | close pane |
-| `b` | toggle sidebar |
-| `f` | fullscreen pane |
-| `r` | resize mode |
-| `q` | detach (quit client) |
+| `h` `l` | resize width |
+| `j` `k` | resize height |
+| `esc` | exit resize mode |
+
+### mouse
-resize mode: `h`/`l` resize width, `j`/`k` resize height, `esc` exit.
+mouse support is built in. herdr is not keyboard-only.
-mouse is supported throughout. full reference: [`CONFIGURATION.md`](./CONFIGURATION.md).
+- click a workspace in the sidebar to switch
+- click tabs to switch within the active workspace
+- click the tab-bar `<` / `>` buttons to scroll overflowing tabs
+- drag tabs to reorder them
+- click a pane to focus it
+- drag split borders to resize
+- drag in a pane to select text; release to copy it to your system clipboard
+- right-click a workspace for a context menu
+- scroll in the sidebar to navigate workspaces
+- click `«` / `»` at the sidebar bottom to collapse or expand it
+
+text copy uses OSC 52, so it depends on your terminal's clipboard support.
+
+### terminal mode
+
+terminal mode is a real terminal. your shell, vim, htop, ssh, and other full-screen tools work normally. press the prefix key (`ctrl+b`) to go back to navigate mode.
+
+## docs map
+
+use the dedicated docs for detailed setup and automation work:
+
+- [`CONFIGURATION.md`](./CONFIGURATION.md) — config file, keybindings, themes, notifications, onboarding, ui options, and environment variables
+- [`INTEGRATIONS.md`](./INTEGRATIONS.md) — install and behavior notes for pi, Claude Code, Codex, and opencode integrations
+- [`SKILL.md`](./SKILL.md) — reusable agent skill for agents already running inside herdr
+- [`SOCKET_API.md`](./SOCKET_API.md) — canonical socket protocol and the `herdr workspace`, `herdr tab`, `herdr pane`, and `herdr wait` cli wrappers
## configuration
config file: `~/.config/herdr/config.toml`
+print the full default config with:
+
```bash
-herdr --default-config # print full default config
+herdr --default-config
```
-in-app settings screen for theme, sound, and toast preferences. full reference: [`CONFIGURATION.md`](./CONFIGURATION.md).
+### themes
+
+herdr ships with 9 built-in themes: catppuccin (default), tokyo night, dracula, nord, gruvbox, one dark, solarized, kanagawa, and rosé pine.
+
+```toml
+[theme]
+name = "tokyo-night"
+```
+
+you can also override individual color tokens on top of any base theme. see [`CONFIGURATION.md`](./CONFIGURATION.md) for the full token reference.
+
+for day-to-day changes, you do not have to edit the config by hand. herdr also has an in-app settings screen for theme, sound, and toast preferences.
+
+## session persistence
+
+herdr saves your workspaces, tabs, pane layouts, pane working directories, and focused tab or pane automatically as you work, then restores them on restart. sessions are stored at `~/.config/herdr/session.json`.
+
+through the socket api, tabs are first-class too. raw integrations and cli wrappers can list, create, focus, rename, and close tabs directly while pane ids stay workspace-scoped.
+
+use `--no-session` to start fresh.
+
+## how agent detection works
+
+herdr does not require hooks or agent-side configuration for built-in detection. automatic detection works by:
+
+1. identifying the foreground process of each pane's pty via `/proc` on linux or `proc_pidinfo` on macos
+2. matching the process name against known agents
+3. reading the live bottom of the terminal buffer and applying per-agent heuristics to determine state
+
+this means detection works with any supported agent, installed any way, with zero setup. if it runs in a terminal, herdr can see it.
+
+when an agent exposes hooks or plugins, the more robust option is to forward state to herdr over the local socket api. that is what the built-in pi, claude code, codex, and opencode integrations do.
+
+the heuristics are matched against each agent's real terminal output: prompt boxes, spinners, waiting-for-input messages, and tool execution indicators. detection runs on a separate async task per pane, polled every 300 to 500 ms, decoupled from terminal rendering.
+
+## cli wrappers
+
+herdr's workspace, tab, pane, and wait commands are documented in [`SOCKET_API.md`](./SOCKET_API.md) together with the socket methods they wrap.
+
+both `workspace create` and `tab create` support optional `--label` flags, so scripts and agents can name contexts immediately instead of renaming them after creation. both create commands also return the created root pane in their json response, so clients can act on the new pane without an extra lookup.
+
+workspace ids are compact public ids like `1`, `2`, `3`.
+tab ids are compact public ids like `1:1`, `1:2`, `2:1`.
+pane ids are compact public ids like `1-1`, `1-2`, `2-1`.
+
+even with tabs enabled, pane ids remain workspace-scoped public ids rather than `workspace-tab-pane` triples. both tab ids and pane ids are positional within the current live session, so numbering compacts when tabs, workspaces, or panes are closed.
+
+## built with agents
+
+i had never written Rust before starting this project. herdr was built almost entirely through ai coding agents, the same ones it is designed to multiplex. i supervised the architecture and specs. agents wrote the code.
-## docs
+that is part of the point here. herdr is a useful tool, but it is also a proof of what current coding agents can build when they are directed carefully inside a real workflow.
-- [`CONFIGURATION.md`](./CONFIGURATION.md) — keybindings, themes, notifications, environment variables
-- [`INTEGRATIONS.md`](./INTEGRATIONS.md) — pi, claude code, codex, opencode integrations
-- [`SKILL.md`](./SKILL.md) — reusable agent skill
-- [`SOCKET_API.md`](./SOCKET_API.md) — socket protocol and cli reference
+there will be rough edges. if you hit one, [open an issue](https://github.com/ogulcancelik/herdr/issues).
## building from source
@@ -210,10 +353,10 @@ cargo build --release
## testing
```bash
-just test # unit tests
-just test-all # full local test suite
+just test # unit tests
+just test-all # full local test suite
```
## license
-AGPL-3.0: free to use, modify, and distribute. modified versions must be open-sourced under the same license.
+AGPL-3.0: free to use, modify, and distribute. if you distribute a modified version, you must open-source your changes under the same license.
diff --git a/website/assets/sidebar-agents.png b/website/assets/sidebar-agents.png
index 06e03fb2..1d5c5041 100644
--- a/website/assets/sidebar-agents.png
+++ b/website/assets/sidebar-agents.png
Binary files differ
diff --git a/website/assets/sidebar-workspaces.png b/website/assets/sidebar-workspaces.png
index 2d5aa629..a8160f1e 100644
--- a/website/assets/sidebar-workspaces.png
+++ b/website/assets/sidebar-workspaces.png
Binary files differ
diff --git a/website/css/style.css b/website/css/style.css
deleted file mode 100644
index 54061ec9..00000000
--- a/website/css/style.css
+++ /dev/null
@@ -1,719 +0,0 @@
-*,
-*::before,
-*::after {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
- scrollbar-width: thin;
- scrollbar-color: var(--border-bright) var(--mantle);
-}
-
-*::-webkit-scrollbar {
- width: 10px;
- height: 10px;
-}
-
-*::-webkit-scrollbar-track {
- background: var(--mantle);
-}
-
-*::-webkit-scrollbar-thumb {
- background: var(--border-bright);
- border: 2px solid var(--mantle);
- border-radius: 999px;
-}
-
-*::-webkit-scrollbar-thumb:hover {
- background: var(--text-dim);
-}
-
-*::-webkit-scrollbar-corner {
- background: var(--mantle);
-}
-
-:root {
- --base: #11111b;
- --surface: #1e1e2e;
- --mantle: #181825;
- --overlay: #262637;
- --border: #313244;
- --border-bright: #45475a;
- --white: #cdd6f4;
- --text: #a6adc8;
- --text-dim: #6c7086;
- --text-faint: #45475a;
- --green: #a6e3a1;
- --blue: #89b4fa;
- --red: #f38ba8;
- --yellow: #f9e2af;
- --mauve: #cba6f7;
- --max-w: 880px;
-}
-
-html {
- background: var(--base);
- color: var(--text);
- font-family: "JetBrains Mono", monospace;
- font-size: 17px;
- -webkit-font-smoothing: antialiased;
- scroll-behavior: smooth;
-}
-
-body {
- overflow-x: clip;
-}
-
-a {
- color: var(--text);
- text-decoration: none;
- border-bottom: 1px solid var(--border);
- transition:
- color 0.15s,
- border-color 0.15s;
-}
-a:hover {
- color: var(--green);
- border-color: var(--green);
-}
-
-::selection {
- background: var(--overlay);
- color: var(--white);
-}
-
-/* ── State dots ── */
-.dot {
- display: inline-block;
- width: 8px;
- height: 8px;
- border-radius: 50%;
- flex-shrink: 0;
-}
-.dot-blocked {
- background: var(--red);
-}
-.dot-working {
- background: var(--yellow);
-}
-.dot-done {
- background: var(--blue);
-}
-.dot-idle {
- background: var(--green);
-}
-
-.text-blocked {
- color: var(--red);
-}
-.text-working {
- color: var(--yellow);
-}
-.text-done {
- color: var(--blue);
-}
-.text-idle {
- color: var(--green);
-}
-
-/* ── Sections ── */
-.section {
- max-width: var(--max-w);
- margin: 0 auto;
- padding: 0 2rem;
-}
-
-.section-rule {
- border: none;
- border-top: 1px solid var(--border);
- max-width: var(--max-w);
- margin: 0 auto;
-}
-
-.gap {
- height: 5rem;
-}
-.gap-lg {
- height: 7rem;
-}
-.gap-sm {
- height: 3rem;
-}
-
-.section-heading {
- display: flex;
- align-items: center;
- gap: 0.65rem;
- margin-bottom: 2rem;
-}
-
-.section-heading h2 {
- font-size: 0.75rem;
- font-weight: 600;
- text-transform: uppercase;
- letter-spacing: 0.15em;
- color: var(--text-dim);
-}
-
-/* ── Hero ── */
-.hero {
- position: relative;
- max-width: var(--max-w);
- margin: 0 auto;
- padding: 6rem 2rem 0;
- overflow: hidden;
-}
-
-.hero-pasture {
- position: absolute;
- inset: 0;
- overflow: hidden;
- pointer-events: none;
- z-index: 0;
-}
-
-.hero > *:not(.hero-pasture) {
- position: relative;
- z-index: 1;
-}
-
-.hero .sheep-el {
- position: absolute;
- font-family: "JetBrains Mono", monospace;
- line-height: 1.15;
- white-space: pre;
- pointer-events: none;
- user-select: none;
- will-change: transform;
-}
-
-.hero-logo {
- width: 56px;
- height: 56px;
- border-radius: 14px;
- margin-right: 1rem;
- vertical-align: middle;
-}
-
-.hero-name {
- font-size: 1.5rem;
- font-weight: 500;
- text-transform: lowercase;
- letter-spacing: 0.05em;
- color: var(--white);
- margin-bottom: 2rem;
- display: inline-block;
-}
-
-.hero-tagline {
- font-size: 2.75rem;
- font-weight: 700;
- color: var(--white);
- letter-spacing: -0.03em;
- line-height: 1.1;
- margin-bottom: 1.5rem;
-}
-
-.hero-dots {
- display: flex;
- gap: 0.6rem;
- margin-bottom: 3rem;
-}
-
-.hero-dots .dot {
- width: 10px;
- height: 10px;
-}
-
-.manifesto {
- font-size: 1rem;
- line-height: 1.9;
- color: var(--text-dim);
- margin-bottom: 3rem;
-}
-
-.manifesto p + p {
- margin-top: 1rem;
-}
-.manifesto strong {
- color: var(--white);
- font-weight: 500;
-}
-
-.install-row {
- display: flex;
- align-items: center;
- gap: 0.75rem;
- margin-bottom: 1rem;
- flex-wrap: wrap;
-}
-
-.install-box {
- display: inline-flex;
- align-items: center;
- gap: 0.5rem;
- background: var(--mantle);
- border: 1px solid var(--border);
- border-radius: 6px;
- padding: 0.55rem 0.9rem;
- font-size: 0.875rem;
- max-width: 100%;
-}
-
-.install-box .prompt {
- color: var(--green);
-}
-.install-box code {
- color: var(--text);
- white-space: normal;
- overflow-wrap: anywhere;
- word-break: break-word;
-}
-
-.copy-btn {
- background: none;
- border: 1px solid var(--border);
- border-radius: 4px;
- color: var(--text-dim);
- font-family: inherit;
- font-size: 0.75rem;
- padding: 0.35rem 0.6rem;
- cursor: pointer;
- transition:
- color 0.15s,
- border-color 0.15s;
-}
-.copy-btn:hover {
- border-color: var(--text-dim);
- color: var(--text);
-}
-.copy-btn.copied {
- border-color: var(--green);
- color: var(--green);
-}
-
-.hero-meta {
- font-size: 0.7rem;
- color: var(--text-faint);
- overflow-wrap: anywhere;
-}
-
-.hero-meta a {
- color: var(--text-dim);
- border: none;
-}
-.hero-meta a:hover {
- color: var(--green);
-}
-
-/* ── Demo ── */
-.demo {
- max-width: var(--max-w);
- margin: 0 auto;
- padding: 0 2rem;
-}
-
-.demo-frame {
- border: 1px solid var(--border);
- border-radius: 8px;
- overflow: hidden;
-}
-
-.demo-frame video {
- display: block;
- width: 100%;
- height: auto;
-}
-
-/* ── Comparison ── */
-.position-table {
- width: 100%;
- border-collapse: collapse;
- font-size: 0.875rem;
-}
-
-.position-table th {
- text-align: left;
- font-size: 0.75rem;
- font-weight: 600;
- text-transform: uppercase;
- letter-spacing: 0.1em;
- color: var(--text-faint);
- padding: 0.6rem 1rem;
- border-bottom: 1px solid var(--border);
- background: var(--mantle);
-}
-
-.position-table th.herdr-col {
- color: var(--green);
-}
-
-.position-table td {
- padding: 0.5rem 1rem;
- color: var(--text-dim);
- line-height: 1.55;
- border-bottom: 1px solid var(--border);
- vertical-align: top;
-}
-
-.position-table tr:last-child td {
- border-bottom: none;
-}
-.position-table td:first-child {
- width: 11rem;
- color: var(--text);
- font-weight: 500;
-}
-.position-table td.herdr-col {
- color: var(--text);
-}
-
-.mark {
- color: var(--text-faint);
-}
-.mark-yes {
- color: var(--green);
-}
-
-/* ── Prose block ── */
-.prose-block {
- font-size: 0.875rem;
- line-height: 1.85;
- color: var(--text-dim);
-}
-
-.prose-block strong {
- color: var(--white);
- font-weight: 500;
-}
-
-/* ── Detach flow ── */
-.detach-flow {
- background: var(--mantle);
- border: 1px solid var(--border);
- border-radius: 6px;
- padding: 1.75rem 2rem;
-}
-
-.detach-line {
- font-size: 0.875rem;
- line-height: 2.2;
- color: var(--text-dim);
-}
-
-.detach-line .prompt {
- color: var(--green);
-}
-.detach-line .cmd {
- color: var(--white);
-}
-.detach-line .key {
- color: var(--blue);
-}
-.detach-line .comment {
- color: var(--text-faint);
-}
-.detach-line .dim {
- color: var(--text-faint);
-}
-
-/* ── Awareness ── */
-.awareness-split {
- display: grid;
- grid-template-columns: 1fr;
- gap: 1.5rem;
- margin-bottom: 1.5rem;
-}
-
-.awareness-panel {
- display: flex;
- gap: 1.25rem;
- align-items: flex-start;
-}
-
-.awareness-panel-img {
- flex-shrink: 0;
- width: 240px;
- border: 1px solid var(--border);
- border-radius: 4px;
- overflow: hidden;
-}
-
-.awareness-panel-img img {
- display: block;
- width: 100%;
- height: auto;
- image-rendering: auto;
-}
-
-.awareness-panel-text h3 {
- font-size: 0.875rem;
- font-weight: 500;
- color: var(--white);
- margin-bottom: 0.35rem;
-}
-
-.awareness-panel-text p {
- font-size: 0.875rem;
- color: var(--text-dim);
- line-height: 1.65;
-}
-
-.state-bar {
- display: flex;
- gap: 2rem;
- padding: 0.5rem 0 0;
-}
-
-.state-bar-item {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- font-size: 0.875rem;
- color: var(--text-dim);
-}
-
-/* ── Terminal ── */
-.terminal-block {
- background: var(--mantle);
- border: 1px solid var(--border);
- border-radius: 6px;
- padding: 1.75rem 2rem;
-}
-
-.terminal-block p {
- font-size: 0.875rem;
- line-height: 1.85;
- color: var(--text-dim);
-}
-
-.terminal-block strong {
- color: var(--white);
- font-weight: 500;
-}
-
-.term-pills {
- display: flex;
- gap: 0.4rem;
- flex-wrap: wrap;
- margin-top: 1.25rem;
-}
-
-.term-pill {
- font-size: 0.75rem;
- color: var(--text-dim);
- background: var(--base);
- padding: 0.2rem 0.6rem;
- border: 1px solid var(--border);
- border-radius: 4px;
-}
-
-/* ── Comparison ── */
-.table-wrap {
- width: 100%;
- border: 1px solid var(--border);
- border-radius: 6px;
- overflow-x: auto;
- overflow-y: hidden;
- -webkit-overflow-scrolling: touch;
-}
-
-.agents-table {
- width: 100%;
- border-collapse: collapse;
- font-size: 0.875rem;
-}
-
-.agents-table th {
- text-align: left;
- padding: 0.6rem 1rem;
- color: var(--text-faint);
- font-weight: 600;
- font-size: 0.75rem;
- text-transform: uppercase;
- letter-spacing: 0.1em;
- background: var(--mantle);
- border-bottom: 1px solid var(--border);
-}
-
-.agents-table td {
- padding: 0.5rem 1rem;
- border-bottom: 1px solid var(--border);
- color: var(--text-dim);
-}
-
-.agents-table tr:last-child td {
- border-bottom: none;
-}
-.agents-table td:first-child {
- color: var(--text);
- font-weight: 500;
-}
-
-.agents-table a {
- border-bottom: 1px solid var(--border-bright);
-}
-.agents-table a:hover {
- border-color: var(--green);
-}
-
-.check {
- color: var(--green);
-}
-.partial {
- color: var(--yellow);
-}
-.untested {
- color: var(--text-faint);
- font-size: 0.75rem;
-}
-
-/* ── API ── */
-.api-grid {
- display: grid;
- grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
- gap: 2rem;
- align-items: start;
-}
-
-.api-grid > * {
- min-width: 0;
-}
-
-.api-text p {
- font-size: 0.875rem;
- color: var(--text-dim);
- line-height: 1.85;
- margin-bottom: 0.75rem;
-}
-
-.api-text strong {
- color: var(--white);
- font-weight: 500;
-}
-
-.api-links {
- display: flex;
- gap: 0.5rem;
- margin-top: 0.75rem;
- flex-wrap: wrap;
-}
-
-.api-links a {
- font-size: 0.75rem;
- color: var(--text-dim);
- padding: 0.3rem 0.65rem;
- border: 1px solid var(--border);
- border-radius: 4px;
- transition:
- color 0.15s,
- border-color 0.15s;
-}
-.api-links a:hover {
- border-color: var(--green);
- color: var(--green);
-}
-
-.code-block {
- background: var(--mantle);
- border: 1px solid var(--border);
- border-radius: 6px;
- padding: 1.25rem 1.5rem;
- overflow-x: auto;
- -webkit-overflow-scrolling: touch;
-}
-
-.code-block pre {
- font-size: 0.72rem;
- line-height: 1.9;
- color: var(--text-dim);
-}
-
-.code-block .comment {
- color: var(--text-faint);
-}
-.code-block .cmd {
- color: var(--green);
-}
-.code-block .flag {
- color: var(--blue);
-}
-.code-block .str {
- color: var(--yellow);
-}
-
-/* ── Footer ── */
-.footer {
- max-width: var(--max-w);
- margin: 0 auto;
- padding: 2rem 2rem 4rem;
- text-align: center;
-}
-
-.footer p {
- font-size: 0.7rem;
- color: var(--text-faint);
- line-height: 2;
-}
-
-.footer a {
- color: var(--text-dim);
- border: none;
-}
-.footer a:hover {
- color: var(--green);
-}
-
-/* ── Responsive ── */
-@media (max-width: 768px) {
- .hero,
- .section,
- .demo,
- .footer {
- padding-left: 1.25rem;
- padding-right: 1.25rem;
- }
- .hero {
- padding-top: 4rem;
- }
- .hero-tagline {
- font-size: 2rem;
- }
- .manifesto {
- font-size: 0.875rem;
- }
- .awareness-panel {
- flex-direction: column;
- align-items: flex-start;
- }
- .awareness-panel-img {
- width: min(100%, 220px);
- }
- .api-grid {
- grid-template-columns: 1fr;
- }
- .state-bar {
- gap: 1.25rem;
- flex-wrap: wrap;
- }
- .position-table {
- min-width: 42rem;
- }
- .agents-table {
- min-width: 38rem;
- }
- .position-table td:first-child {
- width: 11rem;
- }
-}
-
-@media (max-width: 480px) {
- .hero {
- padding-top: 3rem;
- }
- .hero-tagline {
- font-size: 1.7rem;
- }
- .manifesto {
- font-size: 0.875rem;
- }
-}
diff --git a/website/index.html b/website/index.html
index e639d355..f73c66ec 100644
--- a/website/index.html
+++ b/website/index.html
@@ -1,702 +1,978 @@
-<!doctype html>
+<!DOCTYPE html>
<html lang="en">
- <head>
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <title>herdr — tmux for agents</title>
- <meta
- name="description"
- content="Persistent terminal multiplexer for coding agents. Detach and reattach, agents keep running. Built-in awareness for blocked, done, and working states. Lives inside your terminal."
- />
- <meta name="theme-color" content="#11111b" />
- <link rel="canonical" href="https://herdr.dev/" />
-
- <meta property="og:type" content="website" />
- <meta property="og:site_name" content="herdr" />
- <meta property="og:title" content="herdr — tmux for agents" />
- <meta
- property="og:description"
- content="Persistent terminal multiplexer for coding agents. Detach, reattach, agents keep running."
- />
- <meta property="og:url" content="https://herdr.dev/" />
- <meta
- property="og:image"
- content="https://herdr.dev/assets/og-card.png"
- />
- <meta property="og:image:width" content="1200" />
- <meta property="og:image:height" content="630" />
-
- <meta name="twitter:card" content="summary_large_image" />
- <meta name="twitter:title" content="herdr — tmux for agents" />
- <meta
- name="twitter:description"
- content="Persistent terminal multiplexer for coding agents. Detach, reattach, agents keep running."
- />
- <meta
- name="twitter:image"
- content="https://herdr.dev/assets/og-card.png"
- />
-
- <link rel="icon" type="image/png" href="/assets/logo.png" />
- <link rel="apple-touch-icon" href="/assets/logo.png" />
- <link rel="preconnect" href="https://fonts.googleapis.com" />
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
- <link
- href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;600;700&display=swap"
- rel="stylesheet"
- />
- <link rel="stylesheet" href="/css/style.css" />
- </head>
- <body>
- <!-- ── Hero ── -->
- <section class="hero" id="hero">
- <div class="hero-pasture" aria-hidden="true"></div>
- <img src="/assets/logo.png" alt="herdr" class="hero-logo" />
- <span class="hero-name">herdr</span>
- <p class="hero-tagline">tmux for agents.</p>
- <div class="hero-dots">
- <span class="dot dot-blocked"></span>
- <span class="dot dot-working"></span>
- <span class="dot dot-done"></span>
- <span class="dot dot-idle"></span>
- </div>
- <div class="manifesto">
- <p>
- <strong
- >herdr is an agent multiplexer that lives in your
- terminal.</strong
- >
- </p>
- <p>
- workspaces, tabs, panes. mouse-native: click, drag, split.
- every agent at a glance:
- <span class="text-blocked">blocked</span>,
- <span class="text-working">working</span>,
- <span class="text-done">done</span>. detach and reattach,
- agents keep running. no gui app, no electron, no mac-only
- native wrapper. you see the agent's own terminal, not
- someone's interpretation of it.
- </p>
- </div>
- <div class="install-row">
- <div class="install-box">
- <span class="prompt">$</span>
- <code id="install-cmd"
- >curl -fsSL https://herdr.dev/install.sh | sh</code
- >
- </div>
- <button class="copy-btn" id="copy-btn">copy</button>
- </div>
- <div class="hero-meta">
- <a href="https://github.com/ogulcancelik/herdr">github</a> ·
- <a
- href="https://github.com/ogulcancelik/herdr/blob/master/CONFIGURATION.md"
- >docs</a
- >
- ·
- <a
- href="https://github.com/ogulcancelik/herdr/blob/master/SOCKET_API.md"
- >api</a
- >
- · linux · macos · agpl-3.0
- </div>
- </section>
-
- <div class="gap-lg"></div>
-
- <!-- ── Demo ── -->
- <div class="demo">
- <div class="demo-frame">
- <video
- autoplay
- muted
- loop
- playsinline
- preload="auto"
- poster="/assets/hero-screenshot.png"
- >
- <source src="/assets/demo.mp4" type="video/mp4" />
- </video>
- </div>
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>herdr — supervise multiple coding agents in one terminal</title>
+ <meta name="description" content="Run Claude Code, Codex, pi, opencode, droid, and amp side by side in your existing terminal. Workspaces, panes, agent detection, and notifications for blocked, done, and working states.">
+ <meta name="theme-color" content="#0d1117">
+ <link rel="canonical" href="https://herdr.dev/">
+
+ <!-- Open Graph -->
+ <meta property="og:type" content="website">
+ <meta property="og:site_name" content="herdr">
+ <meta property="og:title" content="herdr — supervise multiple coding agents in one terminal">
+ <meta property="og:description" content="Run Claude Code, Codex, pi, opencode, droid, and amp side by side in your existing terminal. Workspaces, panes, agent detection, and notifications for blocked, done, and working states.">
+ <meta property="og:url" content="https://herdr.dev/">
+ <meta property="og:image" content="https://herdr.dev/assets/og-card.png">
+ <meta property="og:image:width" content="1200">
+ <meta property="og:image:height" content="630">
+
+ <!-- Twitter / X -->
+ <meta name="twitter:card" content="summary_large_image">
+ <meta name="twitter:title" content="herdr — supervise multiple coding agents in one terminal">
+ <meta name="twitter:description" content="Run Claude Code, Codex, pi, opencode, droid, and amp side by side in your existing terminal with workspaces, panes, and agent state detection.">
+ <meta name="twitter:image" content="https://herdr.dev/assets/og-card.png">
+
+ <link rel="icon" type="image/png" href="/assets/logo.png">
+ <link rel="apple-touch-icon" href="/assets/logo.png">
+ <link rel="preconnect" href="https://fonts.googleapis.com">
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+ <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
+ <style>
+ *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
+
+ :root {
+ --bg: #0d1117;
+ --bg-raised: #161b22;
+ --bg-surface: #1c2129;
+ --border: #21262d;
+ --border-bright: #30363d;
+ --text: #e6edf3;
+ --text-muted: #8b949e;
+ --text-dim: #484f58;
+ --green: #4ade80;
+ --green-dim: rgba(74, 222, 128, 0.12);
+ --red: #f87171;
+ --blue: #60a5fa;
+ --yellow: #fbbf24;
+ --max-w: 1080px;
+ }
+
+ html {
+ background: var(--bg);
+ color: var(--text);
+ font-family: 'JetBrains Mono', 'Fira Code', 'SF Mono', monospace;
+ -webkit-font-smoothing: antialiased;
+ scroll-behavior: smooth;
+ }
+
+ body { overflow-x: hidden; }
+
+ /* ── Hero ── */
+ .hero {
+ position: relative;
+ max-width: var(--max-w);
+ margin: 0 auto;
+ padding: 4rem 2rem 0;
+ text-align: center;
+ overflow: hidden;
+ }
+
+ .hero-pasture {
+ position: absolute;
+ inset: 0;
+ overflow: hidden;
+ pointer-events: none;
+ z-index: 0;
+ }
+
+ .hero > *:not(.hero-pasture) {
+ position: relative;
+ z-index: 1;
+ }
+
+ .hero .sheep-el {
+ position: absolute;
+ font-family: 'JetBrains Mono', monospace;
+ line-height: 1.15;
+ white-space: pre;
+ pointer-events: none;
+ user-select: none;
+ will-change: transform;
+ }
+
+ .hero-logo {
+ width: 80px;
+ height: 80px;
+ border-radius: 18px;
+ margin-bottom: 1.25rem;
+ }
+
+ .hero h1 {
+ font-size: 3rem;
+ font-weight: 700;
+ letter-spacing: -0.03em;
+ color: #fff;
+ }
+
+ .hero-tagline {
+ font-size: 1.1rem;
+ color: var(--green);
+ margin: 0.25rem 0 1.25rem;
+ }
+
+ .hero-desc {
+ font-size: 0.875rem;
+ color: var(--text-muted);
+ line-height: 1.8;
+ max-width: 640px;
+ margin: 0 auto 2rem;
+ }
+
+ .hero-desc p + p { margin-top: 0.6rem; }
+
+ /* install box */
+ .install-box {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.75rem;
+ background: var(--bg-raised);
+ border: 1px solid var(--border);
+ border-radius: 8px;
+ padding: 0.65rem 1rem;
+ font-size: 0.825rem;
+ margin-bottom: 0.75rem;
+ transition: border-color 0.2s;
+ }
+
+ .install-box:hover { border-color: var(--border-bright); }
+ .install-box .prompt { color: var(--green); }
+ .install-box code { color: var(--text); }
+
+ .copy-btn {
+ background: none;
+ border: 1px solid var(--border);
+ color: var(--text-dim);
+ font-family: inherit;
+ font-size: 0.7rem;
+ padding: 0.2rem 0.5rem;
+ border-radius: 4px;
+ cursor: pointer;
+ transition: all 0.2s;
+ }
+ .copy-btn:hover { border-color: var(--green); color: var(--green); }
+ .copy-btn.copied { border-color: var(--green); color: var(--green); }
+
+ .hero-links {
+ display: flex;
+ justify-content: center;
+ gap: 1.5rem;
+ margin-top: 0.5rem;
+ font-size: 0.8rem;
+ }
+ .hero-links a {
+ color: var(--text-dim);
+ text-decoration: none;
+ transition: color 0.2s;
+ }
+ .hero-links a:hover { color: var(--green); }
+
+ /* screenshot */
+ .hero-screenshot {
+ max-width: var(--max-w);
+ margin: 3rem auto 0;
+ padding: 0 2rem;
+ }
+
+ .screenshot-frame {
+ position: relative;
+ border-radius: 12px;
+ overflow: hidden;
+ border: 1px solid var(--border);
+ box-shadow:
+ 0 0 0 1px rgba(0,0,0,0.3),
+ 0 24px 80px rgba(0,0,0,0.5),
+ 0 0 120px rgba(74, 222, 128, 0.03);
+ }
+
+ .screenshot-frame img,
+ .screenshot-frame video {
+ display: block;
+ width: 100%;
+ height: auto;
+ }
+
+ .screenshot-label {
+ text-align: center;
+ font-size: 0.7rem;
+ color: var(--text-dim);
+ margin-top: 1rem;
+ }
+
+ /* ── Divider ── */
+ .section-gap { height: 5rem; }
+
+ /* ── Two-column features ── */
+ .features {
+ max-width: var(--max-w);
+ margin: 0 auto;
+ padding: 0 2rem;
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 2rem;
+ }
+
+ .feature-card {
+ background: var(--bg-raised);
+ border: 1px solid var(--border);
+ border-radius: 10px;
+ padding: 2rem;
+ }
+
+ .feature-card h2 {
+ font-size: 1rem;
+ font-weight: 700;
+ margin-bottom: 0.25rem;
+ color: #fff;
+ }
+
+ .feature-card .subtitle {
+ font-size: 0.75rem;
+ color: var(--green);
+ margin-bottom: 1.25rem;
+ }
+
+ .feature-list {
+ list-style: none;
+ }
+
+ .feature-list li {
+ font-size: 0.8rem;
+ color: var(--text-muted);
+ line-height: 1.7;
+ padding-left: 1.2rem;
+ position: relative;
+ }
+
+ .feature-list li::before {
+ content: '›';
+ position: absolute;
+ left: 0;
+ color: var(--text-dim);
+ }
+
+ .feature-list li + li { margin-top: 0.4rem; }
+
+ /* ── Awareness section ── */
+ .awareness {
+ max-width: var(--max-w);
+ margin: 0 auto;
+ padding: 0 2rem;
+ }
+
+ .awareness-header {
+ margin-bottom: 1.5rem;
+ }
+
+ .awareness-header h2 {
+ font-size: 1rem;
+ font-weight: 700;
+ color: #fff;
+ margin-bottom: 0.3rem;
+ }
+
+ .awareness-desc {
+ font-size: 0.8rem;
+ color: var(--text-muted);
+ line-height: 1.7;
+ }
+
+ .awareness-dual {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 2rem;
+ margin-bottom: 1.5rem;
+ }
+
+ .awareness-panel {
+ background: var(--bg-raised);
+ border: 1px solid var(--border);
+ border-radius: 10px;
+ padding: 1.5rem;
+ display: flex;
+ gap: 1.25rem;
+ align-items: flex-start;
+ }
+
+ .awareness-panel-img {
+ flex-shrink: 0;
+ border: 1px solid var(--border);
+ border-radius: 6px;
+ overflow: hidden;
+ }
+
+ .awareness-panel-img img {
+ display: block;
+ height: auto;
+ width: auto;
+ max-height: 120px;
+ image-rendering: auto;
+ }
+
+ .awareness-panel-text h3 {
+ font-size: 0.85rem;
+ font-weight: 700;
+ color: #fff;
+ margin-bottom: 0.4rem;
+ }
+
+ .awareness-panel-text p {
+ font-size: 0.75rem;
+ color: var(--text-muted);
+ line-height: 1.7;
+ }
+
+ .state-bar {
+ display: flex;
+ justify-content: center;
+ gap: 2rem;
+ padding: 1rem 0 0;
+ }
+
+ .state-bar-item {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ font-size: 0.75rem;
+ color: var(--text-muted);
+ }
+
+ .state-dot {
+ flex-shrink: 0;
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ display: inline-block;
+ }
+
+ .state-dot.red { background: var(--red); box-shadow: 0 0 8px rgba(248,113,113,0.4); }
+ .state-dot.blue { background: var(--blue); box-shadow: 0 0 8px rgba(96,165,250,0.4); }
+ .state-dot.yellow { background: var(--yellow); box-shadow: 0 0 8px rgba(251,191,36,0.3); }
+ .state-dot.green { background: var(--green); opacity: 0.5; }
+
+ /* ── Agents table ── */
+ .agents-section {
+ max-width: var(--max-w);
+ margin: 0 auto;
+ padding: 0 2rem;
+ }
+
+ .agents-section h2 {
+ font-size: 1rem;
+ font-weight: 700;
+ color: #fff;
+ margin-bottom: 0.3rem;
+ }
+
+ .agents-section .section-desc {
+ font-size: 0.775rem;
+ color: var(--text-muted);
+ margin-bottom: 1.25rem;
+ line-height: 1.6;
+ }
+
+ .agents-table-wrap {
+ border: 1px solid var(--border);
+ border-radius: 10px;
+ overflow: hidden;
+ }
+
+ .agents-table {
+ width: 100%;
+ border-collapse: collapse;
+ font-size: 0.8rem;
+ }
+
+ .agents-table th {
+ text-align: left;
+ padding: 0.7rem 1rem;
+ color: var(--text-muted);
+ font-weight: 500;
+ font-size: 0.7rem;
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+ background: var(--bg-surface);
+ border-bottom: 1px solid var(--border);
+ }
+
+ .agents-table td {
+ padding: 0.6rem 1rem;
+ border-bottom: 1px solid var(--border);
+ color: var(--text-muted);
+ }
+
+ .agents-table tr:last-child td { border-bottom: none; }
+
+ .agents-table td:first-child {
+ color: var(--text);
+ font-weight: 500;
+ }
+
+ .agents-table a {
+ color: inherit;
+ text-decoration: none;
+ border-bottom: 1px solid var(--border);
+ transition: all 0.2s;
+ }
+ .agents-table a:hover { color: var(--green); border-color: var(--green); }
+
+ .check { color: var(--green); }
+ .partial { color: var(--yellow); }
+ .untested { color: var(--text-dim); font-size: 0.7rem; }
+
+ /* ── How it works ── */
+ .how-section {
+ max-width: var(--max-w);
+ margin: 0 auto;
+ padding: 0 2rem;
+ }
+
+ .how-section h2 {
+ font-size: 1rem;
+ font-weight: 700;
+ color: #fff;
+ margin-bottom: 1.25rem;
+ }
+
+ .how-grid {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 1.5rem;
+ }
+
+ .how-step {
+ background: var(--bg-raised);
+ border: 1px solid var(--border);
+ border-radius: 10px;
+ padding: 1.5rem;
+ }
+
+ .how-step .step-num {
+ font-size: 0.7rem;
+ color: var(--green);
+ margin-bottom: 0.5rem;
+ }
+
+ .how-step h3 {
+ font-size: 0.85rem;
+ font-weight: 700;
+ color: #fff;
+ margin-bottom: 0.4rem;
+ }
+
+ .how-step p {
+ font-size: 0.75rem;
+ color: var(--text-muted);
+ line-height: 1.65;
+ }
+
+ .how-step code {
+ font-size: 0.725rem;
+ background: var(--bg);
+ padding: 0.15rem 0.35rem;
+ border-radius: 3px;
+ color: var(--text);
+ }
+
+ /* ── API teaser ── */
+ .api-section {
+ max-width: var(--max-w);
+ margin: 0 auto;
+ padding: 0 2rem;
+ }
+
+ .api-card {
+ background: var(--bg-raised);
+ border: 1px solid var(--border);
+ border-radius: 10px;
+ padding: 2rem;
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 2rem;
+ align-items: start;
+ }
+
+ .api-card h2 {
+ font-size: 1rem;
+ font-weight: 700;
+ color: #fff;
+ margin-bottom: 0.3rem;
+ }
+
+ .api-card .subtitle {
+ font-size: 0.75rem;
+ color: var(--green);
+ margin-bottom: 1rem;
+ }
+
+ .api-card p {
+ font-size: 0.8rem;
+ color: var(--text-muted);
+ line-height: 1.7;
+ }
+
+ .api-card p + p { margin-top: 0.6rem; }
+
+ .api-doc-links {
+ display: flex;
+ gap: 0.75rem;
+ margin-top: 1.25rem;
+ }
+
+ .api-doc-links a {
+ font-size: 0.75rem;
+ color: var(--text);
+ text-decoration: none;
+ padding: 0.4rem 0.75rem;
+ border: 1px solid var(--border);
+ border-radius: 6px;
+ transition: all 0.2s;
+ }
+ .api-doc-links a:hover { border-color: var(--green); color: var(--green); }
+
+ .code-block {
+ background: var(--bg);
+ border: 1px solid var(--border);
+ border-radius: 8px;
+ padding: 1.25rem;
+ overflow-x: auto;
+ }
+
+ .code-block pre {
+ font-size: 0.725rem;
+ line-height: 1.8;
+ color: var(--text-muted);
+ }
+
+ .code-block .comment { color: var(--text-dim); }
+ .code-block .cmd { color: var(--green); }
+ .code-block .flag { color: var(--blue); }
+ .code-block .str { color: var(--yellow); }
+
+ /* ── Footer ── */
+ .footer {
+ max-width: var(--max-w);
+ margin: 0 auto;
+ padding: 4rem 2rem 3rem;
+ text-align: center;
+ }
+
+ .footer-line {
+ border: none;
+ border-top: 1px solid var(--border);
+ margin-bottom: 2rem;
+ }
+
+ .footer p {
+ font-size: 0.75rem;
+ color: var(--text-dim);
+ line-height: 1.8;
+ }
+
+ .footer a {
+ color: var(--text-muted);
+ text-decoration: none;
+ transition: color 0.2s;
+ }
+ .footer a:hover { color: var(--green); }
+
+ /* ── Responsive ── */
+ @media (max-width: 768px) {
+ .hero { padding-top: 3rem; }
+ .hero h1 { font-size: 2.25rem; }
+ .features { grid-template-columns: 1fr; }
+ .how-grid { grid-template-columns: 1fr; }
+ .api-card { grid-template-columns: 1fr; }
+ .awareness-dual { grid-template-columns: 1fr; }
+ .state-bar { gap: 1rem; flex-wrap: wrap; }
+ .hero-screenshot { padding: 0 1rem; }
+ .state-grid { grid-template-columns: 1fr 1fr; }
+ }
+
+ @media (max-width: 480px) {
+ .hero h1 { font-size: 1.75rem; }
+ .install-box { font-size: 0.7rem; padding: 0.5rem 0.75rem; }
+ .state-grid { grid-template-columns: 1fr; }
+ }
+ </style>
+</head>
+<body>
+
+ <!-- ── Hero ── -->
+ <section class="hero" id="hero">
+ <img src="/assets/logo.png" alt="herdr" class="hero-logo">
+ <h1>herdr</h1>
+ <p class="hero-tagline">supervise multiple coding agents in one terminal.</p>
+ <div class="hero-desc">
+ <p>run Claude Code, Codex, pi, opencode, droid, amp, and plain shells side by side in your existing terminal. see which agent is blocked, done, or still working without leaving the command line.</p>
+ <p>workspaces, tabs, panes, automatic agent detection, and notifications. no electron, no web dashboard, no separate gui window.</p>
</div>
+ <div class="install-box">
+ <span class="prompt">$</span>
+ <code id="install-cmd">curl -fsSL https://herdr.dev/install.sh | sh</code>
+ <button class="copy-btn" id="copy-btn">copy</button>
+ </div>
+ <div class="hero-links">
+ <a href="https://github.com/ogulcancelik/herdr">github</a>
+ <a href="https://github.com/ogulcancelik/herdr/blob/master/CONFIGURATION.md">docs</a>
+ <a href="https://github.com/ogulcancelik/herdr/blob/master/SOCKET_API.md">api</a>
+ </div>
+ </section>
+
+ <!-- ── Demo ── -->
+ <div class="hero-screenshot">
+ <div class="screenshot-frame">
+ <video autoplay muted loop playsinline preload="auto" poster="/assets/hero-screenshot.png">
+ <source src="/assets/demo.mp4" type="video/mp4">
+ </video>
+ </div>
+ </div>
+
+ <div class="section-gap"></div>
+
+ <!-- ── For you / For your agents ── -->
+ <section class="features">
+ <div class="feature-card">
+ <h2>for you</h2>
+ <p class="subtitle">supervise, triage, act</p>
+ <ul class="feature-list">
+ <li>one place to see all running agents across workspaces</li>
+ <li>sidebar rolls up each workspace to its most urgent state</li>
+ <li>switch contexts instantly — click or keyboard</li>
+ <li>sound alerts and toast notifications for background events</li>
+ <li>mouse-native: click panes, drag borders, select text to copy</li>
+ <li>session persistence — close and reopen, everything restores</li>
+ <li>9 built-in themes, full color token overrides</li>
+ </ul>
+ </div>
+ <div class="feature-card">
+ <h2>for your agents</h2>
+ <p class="subtitle">orchestrate, spawn, wait</p>
+ <ul class="feature-list">
+ <li>create workspaces and split panes programmatically</li>
+ <li>spawn other agents in sibling panes</li>
+ <li>read output from any pane in the session</li>
+ <li>send text and keys into other panes</li>
+ <li>wait for output patterns or agent state changes</li>
+ <li>subscribe to real-time events over the socket</li>
+ <li>ship an agent skill or use the socket API directly</li>
+ </ul>
+ </div>
+ </section>
- <div class="gap-lg"></div>
- <hr class="section-rule" />
- <div class="gap"></div>
-
- <!-- ── Comparison ── -->
- <section class="section">
- <div class="section-heading">
- <span class="dot dot-idle"></span>
- <h2>how it compares</h2>
- </div>
- <div class="table-wrap">
- <table class="position-table">
- <thead>
- <tr>
- <th></th>
- <th>tmux</th>
- <th>gui managers</th>
- <th class="herdr-col">herdr</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>persistent sessions</td>
- <td><span class="mark-yes">✓</span></td>
- <td><span class="mark">—</span></td>
- <td class="herdr-col">
- <span class="mark-yes">✓</span>
- </td>
- </tr>
- <tr>
- <td>detach / reattach</td>
- <td><span class="mark-yes">✓</span></td>
- <td><span class="mark">—</span></td>
- <td class="herdr-col">
- <span class="mark-yes">✓</span>
- </td>
- </tr>
- <tr>
- <td>panes, tabs, workspaces</td>
- <td><span class="mark-yes">✓</span></td>
- <td><span class="mark-yes">✓</span></td>
- <td class="herdr-col">
- <span class="mark-yes">✓</span>
- </td>
- </tr>
- <tr>
- <td>agent awareness</td>
- <td><span class="mark">—</span></td>
- <td><span class="mark-yes">✓</span></td>
- <td class="herdr-col">
- <span class="mark-yes">✓</span>
- </td>
- </tr>
- <tr>
- <td>lives in your terminal</td>
- <td><span class="mark-yes">✓</span></td>
- <td><span class="mark">—</span></td>
- <td class="herdr-col">
- <span class="mark-yes">✓</span>
- </td>
- </tr>
- <tr>
- <td>real terminal views</td>
- <td><span class="mark-yes">✓</span></td>
- <td><span class="mark">—</span></td>
- <td class="herdr-col">
- <span class="mark-yes">✓</span>
- </td>
- </tr>
- <tr>
- <td>mouse-native</td>
- <td><span class="mark">—</span></td>
- <td><span class="mark-yes">✓</span></td>
- <td class="herdr-col">
- <span class="mark-yes">✓</span>
- </td>
- </tr>
- <tr>
- <td>lightweight binary</td>
- <td><span class="mark-yes">✓</span></td>
- <td><span class="mark">—</span></td>
- <td class="herdr-col">
- <span class="mark-yes">✓</span>
- </td>
- </tr>
- <tr>
- <td>agents can orchestrate</td>
- <td><span class="mark">?</span></td>
- <td><span class="mark">?</span></td>
- <td class="herdr-col">
- <span class="mark-yes">✓</span>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- </section>
-
- <div class="gap"></div>
- <hr class="section-rule" />
- <div class="gap"></div>
-
- <!-- ── Persistence ── -->
- <section class="section">
- <div class="section-heading">
- <span class="dot dot-done"></span>
- <h2>persistence</h2>
- </div>
- <div class="prose-block">
- <p>
- start herdr on your desktop or server. run your agents,
- split panes, do your work. press
- <strong>ctrl+b q</strong> to detach. close your terminal,
- close your laptop; your agents keep running. open a new
- terminal, run <strong>herdr</strong>, you're back. same
- session, same panes, same agents.
- </p>
- </div>
- </section>
-
- <div class="gap"></div>
- <hr class="section-rule" />
- <div class="gap"></div>
+ <div class="section-gap"></div>
- <!-- ── From anywhere ── -->
- <section class="section">
- <div class="section-heading">
- <span class="dot dot-done"></span>
- <h2>from anywhere</h2>
- </div>
- <div class="prose-block">
- <p>
- need to check on your agents from your phone? just ssh in
- and run herdr. any ssh client works. no app to download, no
- account to create.
- </p>
- </div>
- <div class="detach-flow" style="margin-top: 1.5rem">
- <div class="detach-line">
- <span class="prompt">$</span> <span class="cmd">ssh</span>
- <span class="comment">you@yourserver</span>
- </div>
- <div class="detach-line">
- <span class="prompt">$</span> <span class="cmd">herdr</span>
+ <!-- ── Awareness ── -->
+ <section class="awareness">
+ <div class="awareness-header">
+ <h2>ambient awareness</h2>
+ <p class="awareness-desc">the sidebar is split into two layers. scan the workspace list for the most urgent signal, then drill into the agents causing it in the selected workspace or across all workspaces.</p>
+ </div>
+ <div class="awareness-dual">
+ <div class="awareness-panel">
+ <div class="awareness-panel-img">
+ <img src="/assets/sidebar-workspaces.png" alt="herdr sidebar workspace list">
</div>
- <div class="detach-line">
- <span class="dim">
- same session, same agents, same state.</span
- >
+ <div class="awareness-panel-text">
+ <h3>workspaces</h3>
+ <p>each workspace shows one aggregate dot — the most urgent state across all its agents. yellow means something is working. you scan the full list in a glance.</p>
</div>
</div>
- </section>
-
- <div class="gap"></div>
- <hr class="section-rule" />
- <div class="gap"></div>
-
- <!-- ── Awareness ── -->
- <section class="section">
- <div class="section-heading">
- <span class="dot dot-working"></span>
- <h2>agent awareness</h2>
- </div>
- <div class="awareness-split">
- <div class="awareness-panel">
- <div class="awareness-panel-img">
- <img
- src="/assets/sidebar-workspaces.png"
- alt="workspaces"
- />
- </div>
- <div class="awareness-panel-text">
- <h3>workspaces</h3>
- <p>
- each workspace rolls up to its most urgent state.
- scan the full list in a glance.
- </p>
- </div>
+ <div class="awareness-panel">
+ <div class="awareness-panel-img">
+ <img src="/assets/sidebar-agents.png" alt="herdr sidebar agent list">
</div>
- <div class="awareness-panel">
- <div class="awareness-panel-img">
- <img src="/assets/sidebar-agents.png" alt="agents" />
- </div>
- <div class="awareness-panel-text">
- <h3>agents</h3>
- <p>
- see which agents are running, blocked, or finished.
- no checking panes one by one.
- </p>
- </div>
+ <div class="awareness-panel-text">
+ <h3>agents</h3>
+ <p>the bottom section shows which specific agents are running in the selected workspace, or across all workspaces when you switch the panel scope. pi is working, droid is idle.</p>
</div>
</div>
- <div class="state-bar">
- <div class="state-bar-item">
- <span class="dot dot-blocked"></span> blocked
- </div>
- <div class="state-bar-item">
- <span class="dot dot-working"></span> working
- </div>
- <div class="state-bar-item">
- <span class="dot dot-done"></span> done
- </div>
- <div class="state-bar-item">
- <span class="dot dot-idle"></span> idle
- </div>
- </div>
- </section>
-
- <div class="gap"></div>
- <hr class="section-rule" />
- <div class="gap"></div>
-
- <!-- ── Terminal ── -->
- <section class="section">
- <div class="section-heading">
- <span class="dot dot-idle"></span>
- <h2>lives in your terminal</h2>
+ </div>
+ <div class="state-bar">
+ <div class="state-bar-item"><span class="state-dot red"></span> blocked</div>
+ <div class="state-bar-item"><span class="state-dot blue"></span> done</div>
+ <div class="state-bar-item"><span class="state-dot yellow"></span> working</div>
+ <div class="state-bar-item"><span class="state-dot green"></span> idle</div>
+ </div>
+ </section>
+
+ <div class="section-gap"></div>
+
+ <!-- ── How it works ── -->
+ <section class="how-section">
+ <h2>how it works</h2>
+ <div class="how-grid">
+ <div class="how-step">
+ <div class="step-num">01</div>
+ <h3>install and launch</h3>
+ <p>one binary, no dependencies. run <code>herdr</code> in your terminal. onboarding takes 10 seconds.</p>
</div>
- <div class="terminal-block">
- <p>
- not a gui window. not a web dashboard. not electron.
- <strong
- >herdr runs inside whatever terminal you already
- use.</strong
- >
- a single rust binary, no dependencies, nothing to configure.
- it even works inside tmux.
- </p>
- <div class="term-pills">
- <span class="term-pill">ghostty</span>
- <span class="term-pill">alacritty</span>
- <span class="term-pill">kitty</span>
- <span class="term-pill">wezterm</span>
- <span class="term-pill">iterm2</span>
- <span class="term-pill">tmux</span>
- </div>
+ <div class="how-step">
+ <div class="step-num">02</div>
+ <h3>create workspaces</h3>
+ <p>press <code>n</code> to create a workspace. it opens as a terminal context, labels itself from git repo or folder name.</p>
</div>
- </section>
-
- <div class="gap"></div>
- <hr class="section-rule" />
- <div class="gap"></div>
-
- <!-- ── Agents ── -->
- <section class="section">
- <div class="section-heading">
- <span class="dot dot-blocked"></span>
- <h2>supported agents</h2>
+ <div class="how-step">
+ <div class="step-num">03</div>
+ <h3>launch agents</h3>
+ <p>start your agents in panes like you normally would. herdr detects them automatically — no hooks, no config.</p>
</div>
- <div class="table-wrap">
- <table class="agents-table">
- <thead>
- <tr>
- <th>agent</th>
- <th>idle / done</th>
- <th>working</th>
- <th>blocked</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td><a href="https://pi.dev">pi</a></td>
- <td><span class="check">✓</span></td>
- <td><span class="check">✓</span></td>
- <td><span class="partial">partial</span></td>
- </tr>
- <tr>
- <td>
- <a
- href="https://docs.anthropic.com/en/docs/claude-code"
- >claude code</a
- >
- </td>
- <td><span class="check">✓</span></td>
- <td><span class="check">✓</span></td>
- <td><span class="check">✓</span></td>
- </tr>
- <tr>
- <td>
- <a href="https://github.com/openai/codex"
- >codex</a
- >
- </td>
- <td><span class="check">✓</span></td>
- <td><span class="check">✓</span></td>
- <td><span class="check">✓</span></td>
- </tr>
- <tr>
- <td><a href="https://factory.ai">droid</a></td>
- <td><span class="check">✓</span></td>
- <td><span class="check">✓</span></td>
- <td><span class="check">✓</span></td>
- </tr>
- <tr>
- <td><a href="https://ampcode.com">amp</a></td>
- <td><span class="check">✓</span></td>
- <td><span class="check">✓</span></td>
- <td><span class="check">✓</span></td>
- </tr>
- <tr>
- <td>
- <a href="https://github.com/anomalyco/opencode"
- >opencode</a
- >
- </td>
- <td><span class="check">✓</span></td>
- <td><span class="check">✓</span></td>
- <td><span class="check">✓</span></td>
- </tr>
- <tr>
- <td>
- <a
- href="https://github.com/google-gemini/gemini-cli"
- >gemini cli</a
- >
- </td>
- <td colspan="3">
- <span class="untested"
- >detected, not fully tested</span
- >
- </td>
- </tr>
- <tr>
- <td>
- <a href="https://cursor.com/cli"
- >cursor agent</a
- >
- </td>
- <td colspan="3">
- <span class="untested"
- >detected, not fully tested</span
- >
- </td>
- </tr>
- <tr>
- <td>
- <a href="https://github.com/cline/cline"
- >cline</a
- >
- </td>
- <td colspan="3">
- <span class="untested"
- >detected, not fully tested</span
- >
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- </section>
+ </div>
+ </section>
+
+ <div class="section-gap"></div>
+
+ <!-- ── Supported agents ── -->
+ <section class="agents-section">
+ <h2>supported agents</h2>
+ <p class="section-desc">herdr detects agents by reading foreground process and terminal output patterns. zero config required.</p>
+ <div class="agents-table-wrap">
+ <table class="agents-table">
+ <thead>
+ <tr>
+ <th>agent</th>
+ <th>idle / done</th>
+ <th>working</th>
+ <th>blocked</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><a href="https://pi.dev">pi</a></td>
+ <td><span class="check">✓</span></td>
+ <td><span class="check">✓</span></td>
+ <td><span class="partial">partial</span></td>
+ </tr>
+ <tr>
+ <td><a href="https://docs.anthropic.com/en/docs/claude-code">claude code</a></td>
+ <td><span class="check">✓</span></td>
+ <td><span class="check">✓</span></td>
+ <td><span class="check">✓</span></td>
+ </tr>
+ <tr>
+ <td><a href="https://github.com/openai/codex">codex</a></td>
+ <td><span class="check">✓</span></td>
+ <td><span class="check">✓</span></td>
+ <td><span class="check">✓</span></td>
+ </tr>
+ <tr>
+ <td><a href="https://factory.ai">droid</a></td>
+ <td><span class="check">✓</span></td>
+ <td><span class="check">✓</span></td>
+ <td><span class="check">✓</span></td>
+ </tr>
+ <tr>
+ <td><a href="https://ampcode.com">amp</a></td>
+ <td><span class="check">✓</span></td>
+ <td><span class="check">✓</span></td>
+ <td><span class="partial">partial</span></td>
+ </tr>
+ <tr>
+ <td><a href="https://github.com/anomalyco/opencode">opencode</a></td>
+ <td><span class="check">✓</span></td>
+ <td><span class="check">✓</span></td>
+ <td><span class="check">✓</span></td>
+ </tr>
+ <tr>
+ <td><a href="https://github.com/google-gemini/gemini-cli">gemini cli</a></td>
+ <td colspan="3"><span class="untested">detected, not fully tested</span></td>
+ </tr>
+ <tr>
+ <td><a href="https://cursor.com/cli">cursor agent</a></td>
+ <td colspan="3"><span class="untested">detected, not fully tested</span></td>
+ </tr>
+ <tr>
+ <td><a href="https://github.com/cline/cline">cline</a></td>
+ <td colspan="3"><span class="untested">detected, not fully tested</span></td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </section>
- <div class="gap"></div>
- <hr class="section-rule" />
- <div class="gap"></div>
+ <div class="section-gap"></div>
- <!-- ── API ── -->
- <section class="section">
- <div class="section-heading">
- <span class="dot dot-done"></span>
+ <!-- ── API ── -->
+ <section class="api-section">
+ <div class="api-card">
+ <div>
<h2>socket api</h2>
- </div>
- <div class="api-grid">
- <div class="api-text">
- <p>
- <strong>agents can use herdr too.</strong> the local
- unix socket lets agents create workspaces, split panes,
- spawn other agents, read output, and wait for state
- changes.
- </p>
- <p>
- available as CLI commands or as a reusable agent skill.
- </p>
- <div class="api-links">
- <a
- href="https://github.com/ogulcancelik/herdr/blob/master/SOCKET_API.md"
- >socket api →</a
- >
- <a
- href="https://github.com/ogulcancelik/herdr/blob/master/SKILL.md"
- >agent skill →</a
- >
- </div>
+ <p class="subtitle">agents can use herdr too</p>
+ <p>herdr exposes a local unix socket that agents can talk to directly. create workspaces and tabs, split panes, spawn agents, read output, and wait for state changes.</p>
+ <p>the same surface is available as CLI commands (<code>herdr workspace</code>, <code>herdr tab</code>, <code>herdr pane</code>, <code>herdr wait</code>) and as a reusable agent skill.</p>
+ <div class="api-doc-links">
+ <a href="https://github.com/ogulcancelik/herdr/blob/master/SOCKET_API.md">socket api docs →</a>
+ <a href="https://github.com/ogulcancelik/herdr/blob/master/SKILL.md">agent skill →</a>
</div>
- <div class="code-block">
- <pre><span class="comment"># create a workspace and tab</span>
-<span class="cmd">herdr</span> workspace create <span class="flag">--cwd</span> <span class="str">~/project</span> <span class="flag">--label</span> <span class="str">"api"</span>
-<span class="cmd">herdr</span> tab create <span class="flag">--label</span> <span class="str">"logs"</span>
+ </div>
+ <div class="code-block">
+ <pre><span class="comment"># create a workspace with a label</span>
+<span class="cmd">herdr</span> workspace create <span class="flag">--cwd</span> <span class="str">~/project</span> <span class="flag">--label</span> <span class="str">"api server"</span>
-<span class="comment"># split a pane and run</span>
+<span class="comment"># split a pane and run a command</span>
<span class="cmd">herdr</span> pane split <span class="str">1-1</span> <span class="flag">--direction</span> <span class="str">right</span>
<span class="cmd">herdr</span> pane run <span class="str">1-2</span> <span class="str">"npm test"</span>
-<span class="comment"># wait for an agent</span>
+<span class="comment"># wait for an agent to finish</span>
<span class="cmd">herdr</span> wait agent-status <span class="str">1-1</span> <span class="flag">--status</span> <span class="str">done</span>
-<span class="comment"># read output</span>
-<span class="cmd">herdr</span> pane read <span class="str">1-2</span> <span class="flag">--source</span> <span class="str">recent</span> <span class="flag">--lines</span> <span class="str">50</span></pre>
- </div>
+<span class="comment"># read pane output</span>
+<span class="cmd">herdr</span> pane read <span class="str">1-2</span> <span class="flag">--source</span> <span class="str">recent-unwrapped</span> <span class="flag">--lines</span> <span class="str">50</span></pre>
</div>
- </section>
-
- <div class="gap-lg"></div>
-
- <!-- ── Footer ── -->
- <footer class="footer">
- <p>
- <a href="https://github.com/ogulcancelik/herdr">github</a> ·
- <a
- href="https://github.com/ogulcancelik/herdr/blob/master/CONFIGURATION.md"
- >configuration</a
- >
- ·
- <a
- href="https://github.com/ogulcancelik/herdr/blob/master/SOCKET_API.md"
- >api</a
- >
- ·
- <a
- href="https://github.com/egithub.com/ogulcancelik/herdr/releases"
- >releases</a
- >
- </p>
- </footer>
-
- <script>
- (function () {
- "use strict";
-
- var hero = document.getElementById("hero");
- var pasture = hero.querySelector(".hero-pasture");
-
- var SR = [
- [" ,ww", " wWWWWWWW_)", " `WWWWWW'", " II II"],
- [" ,ww", " wWWWWWWW_)", " `WWWWWW'", " II II"],
- ];
- var SL = [
- [" ww,", "(_WWWWWWWw", " 'WWWWWW`", " II II"],
- [" ww,", "(_WWWWWWWw", " 'WWWWWW`", " II II"],
- ];
-
- var heroW = hero.offsetWidth;
- var heroH = hero.offsetHeight;
- var heroRect = hero.getBoundingClientRect();
- var mx = -9999,
- my = -9999;
-
- document.addEventListener("mousemove", function (e) {
- mx = e.clientX - heroRect.left;
- my = e.clientY - heroRect.top;
- });
- document.addEventListener("mouseleave", function () {
- mx = -9999;
- my = -9999;
- });
-
- window.addEventListener("resize", function () {
- heroW = hero.offsetWidth;
- heroH = hero.offsetHeight;
- heroRect = hero.getBoundingClientRect();
- });
- window.addEventListener("scroll", function () {
- heroRect = hero.getBoundingClientRect();
- });
-
- var flock = [];
- var count = window.matchMedia("(max-width: 640px)").matches
- ? 3
- : 5;
-
- for (var i = 0; i < count; i++) {
- var el = document.createElement("pre");
- el.className = "sheep-el";
- var opacity = 0.04 + Math.random() * 0.035;
- var size = 9 + Math.random() * 3;
- el.style.cssText =
- "font-size:" +
- size +
- "px;color:rgba(203,166,247," +
- opacity +
- ")";
- pasture.appendChild(el);
-
- flock.push({
- el: el,
- x: Math.random() * heroW,
- y: 30 + Math.random() * (heroH - 80),
- dir: Math.random() > 0.5 ? 1 : -1,
- speed: 0.1 + Math.random() * 0.2,
- frame: 0,
- ft: 0,
- fi: 400 + Math.random() * 300,
- svx: 0,
- svy: 0,
- });
- }
-
- var last = 0;
- function tick(ts) {
- var dt = Math.min(ts - last, 100);
- last = ts;
- for (var i = 0; i < flock.length; i++) {
- var s = flock[i];
- s.ft += dt;
- if (s.ft > s.fi) {
- s.ft = 0;
- s.frame ^= 1;
- }
-
- var dx = s.x - mx,
- dy = s.y - my;
- var d = Math.sqrt(dx * dx + dy * dy);
- if (d < 120 && d > 1) {
- var f = (1 - d / 120) * 0.4;
- s.svx += (dx / d) * f;
- s.svy += (dy / d) * f;
- }
- s.x += s.svx;
- s.y += s.svy;
- s.svx *= 0.97;
- s.svy *= 0.97;
-
- s.x += s.dir * s.speed * (dt / 16);
- if (s.dir > 0 && s.x > heroW + 100) s.x = -100;
- if (s.dir < 0 && s.x < -100) s.x = heroW + 100;
- if (s.y < -40) s.y = heroH + 20;
- if (s.y > heroH + 40) s.y = -20;
- var frames = s.dir > 0 ? SR : SL;
- s.el.textContent = frames[s.frame].join("\n");
- s.el.style.transform =
- "translate3d(" + s.x + "px," + s.y + "px,0)";
- }
- requestAnimationFrame(tick);
- }
- requestAnimationFrame(function (ts) {
- last = ts;
- tick(ts);
- });
-
- // Copy
- var copyBtn = document.getElementById("copy-btn");
- var installCmd = document.getElementById("install-cmd");
-
- function fallbackCopy(text) {
- var ta = document.createElement("textarea");
- ta.value = text;
- ta.style.cssText = "position:fixed;left:-9999px";
- document.body.appendChild(ta);
- ta.select();
- document.execCommand("copy");
- document.body.removeChild(ta);
- }
-
- function showCopied() {
- copyBtn.textContent = "copied!";
- copyBtn.classList.add("copied");
- setTimeout(function () {
- copyBtn.textContent = "copy";
- copyBtn.classList.remove("copied");
- }, 2000);
+ </div>
+ </section>
+
+ <div class="section-gap"></div>
+
+ <!-- ── Footer ── -->
+ <footer class="footer">
+ <hr class="footer-line">
+ <p>
+ <a href="https://github.com/ogulcancelik/herdr">github</a> ·
+ <a href="https://github.com/ogulcancelik/herdr/blob/master/CONFIGURATION.md">configuration</a> ·
+ <a href="https://github.com/ogulcancelik/herdr/blob/master/SOCKET_API.md">api</a> ·
+ <a href="https://github.com/ogulcancelik/herdr/releases">releases</a>
+ </p>
+ <p style="margin-top: 0.75rem;">linux · macos · agpl-3.0</p>
+ </footer>
+
+ <script>
+ (function() {
+ 'use strict';
+
+ // ── Sheep ──
+ var hero = document.getElementById('hero');
+ var pasture = document.createElement('div');
+ pasture.className = 'hero-pasture';
+ pasture.setAttribute('aria-hidden', 'true');
+ hero.prepend(pasture);
+
+ var SR = [
+ [' ,ww',' wWWWWWWW_)'," `WWWWWW'",' II II'],
+ [' ,ww',' wWWWWWWW_)'," `WWWWWW'",' II II']
+ ];
+ var SL = [
+ [' ww,','(_WWWWWWWw'," 'WWWWWW`",' II II'],
+ [' ww,','(_WWWWWWWw'," 'WWWWWW`",' II II']
+ ];
+
+ var heroW = hero.offsetWidth;
+ var heroH = hero.offsetHeight;
+ var heroRect = hero.getBoundingClientRect();
+ var mx = -9999, my = -9999;
+
+ document.addEventListener('mousemove', function(e) {
+ mx = e.clientX - heroRect.left;
+ my = e.clientY - heroRect.top;
+ });
+ document.addEventListener('mouseleave', function() { mx = -9999; my = -9999; });
+
+ window.addEventListener('resize', function() {
+ heroW = hero.offsetWidth;
+ heroH = hero.offsetHeight;
+ heroRect = hero.getBoundingClientRect();
+ });
+ window.addEventListener('scroll', function() {
+ heroRect = hero.getBoundingClientRect();
+ });
+
+ var flock = [];
+ var count = window.matchMedia('(max-width: 640px)').matches ? 4 : 8;
+
+ for (var i = 0; i < count; i++) {
+ var el = document.createElement('pre');
+ el.className = 'sheep-el';
+ var opacity = 0.04 + Math.random() * 0.035;
+ var size = 10 + Math.random() * 4;
+ el.style.cssText = 'font-size:' + size + 'px;color:rgba(255,255,255,' + opacity + ')';
+ pasture.appendChild(el);
+
+ flock.push({
+ el: el,
+ x: Math.random() * heroW,
+ y: 30 + Math.random() * (heroH - 80),
+ dir: Math.random() > 0.5 ? 1 : -1,
+ speed: 0.15 + Math.random() * 0.3,
+ frame: 0,
+ ft: 0,
+ fi: 400 + Math.random() * 300,
+ svx: 0,
+ svy: 0
+ });
+ }
+
+ var last = 0;
+ function tick(ts) {
+ var dt = Math.min(ts - last, 100);
+ last = ts;
+ for (var i = 0; i < flock.length; i++) {
+ var s = flock[i];
+ s.ft += dt;
+ if (s.ft > s.fi) { s.ft = 0; s.frame ^= 1; }
+
+ // mouse scatter
+ var dx = s.x - mx, dy = s.y - my;
+ var d = Math.sqrt(dx * dx + dy * dy);
+ if (d < 120 && d > 1) {
+ var f = (1 - d / 120) * 0.6;
+ s.svx += (dx / d) * f;
+ s.svy += (dy / d) * f;
}
-
- copyBtn.addEventListener("click", function () {
- var text = installCmd.textContent;
- if (navigator.clipboard && navigator.clipboard.writeText) {
- navigator.clipboard
- .writeText(text)
- .then(showCopied)
- .catch(function () {
- fallbackCopy(text);
- showCopied();
- });
- } else {
- fallbackCopy(text);
- showCopied();
- }
+ s.x += s.svx;
+ s.y += s.svy;
+ s.svx *= 0.97;
+ s.svy *= 0.97;
+
+ s.x += s.dir * s.speed * (dt / 16);
+ if (s.dir > 0 && s.x > heroW + 100) s.x = -100;
+ if (s.dir < 0 && s.x < -100) s.x = heroW + 100;
+ if (s.y < -40) s.y = heroH + 20;
+ if (s.y > heroH + 40) s.y = -20;
+ var frames = s.dir > 0 ? SR : SL;
+ s.el.textContent = frames[s.frame].join('\n');
+ s.el.style.transform = 'translate3d(' + s.x + 'px,' + s.y + 'px,0)';
+ }
+ requestAnimationFrame(tick);
+ }
+ requestAnimationFrame(function(ts) { last = ts; tick(ts); });
+
+ // ── Copy ──
+ var copyBtn = document.getElementById('copy-btn');
+ var installCmd = document.getElementById('install-cmd');
+
+ function fallbackCopy(text) {
+ var ta = document.createElement('textarea');
+ ta.value = text;
+ ta.style.cssText = 'position:fixed;left:-9999px';
+ document.body.appendChild(ta);
+ ta.select();
+ document.execCommand('copy');
+ document.body.removeChild(ta);
+ }
+
+ function showCopied() {
+ copyBtn.textContent = 'copied!';
+ copyBtn.classList.add('copied');
+ setTimeout(function() {
+ copyBtn.textContent = 'copy';
+ copyBtn.classList.remove('copied');
+ }, 2000);
+ }
+
+ copyBtn.addEventListener('click', function() {
+ var text = installCmd.textContent;
+ if (navigator.clipboard && navigator.clipboard.writeText) {
+ navigator.clipboard.writeText(text).then(showCopied).catch(function() {
+ fallbackCopy(text);
+ showCopied();
});
- })();
- </script>
- </body>
+ } else {
+ fallbackCopy(text);
+ showCopied();
+ }
+ });
+ })();
+ </script>
+</body>
</html>