aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-04-09 17:39:13 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-04-09 17:39:13 +0300
commitdacbfed01ebe9d6ec7f1e969ad8a29e86b6fad28 (patch)
tree1f86b49471063df431b1a132d165917c302acaf7
parent227f02c58b43d5e0a61feac8d5acfcf86f0657ef (diff)
docs: clarify automatic detection and socket integrations
-rw-r--r--INTEGRATIONS.md23
-rw-r--r--README.md14
-rw-r--r--src/detect.rs9
3 files changed, 35 insertions, 11 deletions
diff --git a/INTEGRATIONS.md b/INTEGRATIONS.md
index 2c5ccb72..b892a226 100644
--- a/INTEGRATIONS.md
+++ b/INTEGRATIONS.md
@@ -2,16 +2,23 @@
herdr works without any hook or plugin setup.
-out of the box, it detects supported agents by combining foreground process detection with screen heuristics. that is enough to give you workspace awareness with zero configuration.
+out of the box, it detects supported agents automatically by combining foreground process detection with screen heuristics. that is enough to give you workspace awareness with zero configuration.
-optional integrations improve the semantic signal on top of that.
+when an agent exposes hooks or plugins, the more robust path is to forward semantic state to herdr over the local socket api. the built-in integrations in this document do exactly that.
+
+if you want to inspect the exact files herdr installs, they are versioned in this repo:
+
+- [pi extension](./src/integration/assets/pi/herdr-agent-state.ts)
+- [claude code hook](./src/integration/assets/claude/herdr-agent-state.sh)
+- [codex hook](./src/integration/assets/codex/herdr-agent-state.sh)
+- [opencode plugin](./src/integration/assets/opencode/herdr-agent-state.js)
## how herdr uses integrations
herdr uses a hybrid model:
- **process detection** owns pane identity, liveness, and "the process is gone"
-- **agent integrations** report semantic state like `working`, `blocked`, and `idle` when the tool exposes those events
+- **agent integrations** report semantic state like `working`, `blocked`, and `idle` over the local socket api when the tool exposes those events
- **screen heuristics** remain the fallback for gaps, unsupported tools, or incomplete hook surfaces
that means hooks/plugins do **not** become the source of truth for pane ownership. they enrich state reporting; they do not replace process detection.
@@ -48,7 +55,9 @@ this writes the bundled pi extension to:
~/.pi/agent/extensions/herdr-agent-state.ts
```
-pi is the cleanest integration. it already has an authoritative hook model, so herdr can get direct state reports without guessing as much from the terminal.
+pi is the cleanest integration. it already has an authoritative hook model, so herdr can get direct state reports over the socket api without guessing as much from the terminal.
+
+bundled source: [`src/integration/assets/pi/herdr-agent-state.ts`](./src/integration/assets/pi/herdr-agent-state.ts)
uninstall:
@@ -75,6 +84,8 @@ this:
- writes the hook script to `~/.claude/hooks/herdr-agent-state.sh`
- updates `~/.claude/settings.json`
+bundled source: [`src/integration/assets/claude/herdr-agent-state.sh`](./src/integration/assets/claude/herdr-agent-state.sh)
+
current hook mapping:
- `UserPromptSubmit` → `working`
@@ -114,6 +125,8 @@ this:
- updates `~/.codex/hooks.json`
- ensures `codex_hooks = true` in `~/.codex/config.toml`
+bundled source: [`src/integration/assets/codex/herdr-agent-state.sh`](./src/integration/assets/codex/herdr-agent-state.sh)
+
current hook mapping:
- `SessionStart` → `idle`
@@ -156,6 +169,8 @@ this writes the bundled plugin to:
~/.config/opencode/plugins/herdr-agent-state.js
```
+bundled source: [`src/integration/assets/opencode/herdr-agent-state.js`](./src/integration/assets/opencode/herdr-agent-state.js)
+
current plugin mapping:
- `permission.asked` → `blocked`
diff --git a/README.md b/README.md
index 69d16f01..9d6ca60e 100644
--- a/README.md
+++ b/README.md
@@ -131,7 +131,9 @@ for that workflow, start with [`SKILL.md`](./SKILL.md) if you want a reusable ag
## supported agents
-herdr detects agent state by identifying the foreground process and reading terminal output patterns. the following agents have been tested:
+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 |
|-------|-------------|---------|---------|
@@ -154,7 +156,9 @@ for any other cli agent, herdr still works as a terminal-native multiplexer. you
## optional direct integrations
-herdr also supports optional direct integrations for tools that expose hooks or plugins:
+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.
+
+herdr ships one-command integrations for:
- [pi](./INTEGRATIONS.md#pi)
- [claude code](./INTEGRATIONS.md#claude-code)
@@ -179,7 +183,7 @@ herdr integration uninstall codex
herdr integration uninstall opencode
```
-these integrations improve semantic state reporting, but they do not replace herdr's core process detection model. for setup details, file locations, caveats, and uninstall behavior, see [`INTEGRATIONS.md`](./INTEGRATIONS.md).
+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.
@@ -290,7 +294,7 @@ use `--no-session` to start fresh.
## how agent detection works
-herdr does not require hooks or agent-side configuration for its built-in detection. it works by:
+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
@@ -298,6 +302,8 @@ herdr does not require hooks or agent-side configuration for its built-in detect
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
diff --git a/src/detect.rs b/src/detect.rs
index eace9f54..a026ddce 100644
--- a/src/detect.rs
+++ b/src/detect.rs
@@ -417,7 +417,11 @@ fn has_claude_blocked_prompt(content: &str, lower_content: &str) -> bool {
fn has_claude_yes_no_choice(content: &str) -> bool {
content.lines().any(|line| {
- let trimmed = line.trim().trim_start_matches('❯').trim_start().to_lowercase();
+ let trimmed = line
+ .trim()
+ .trim_start_matches('❯')
+ .trim_start()
+ .to_lowercase();
trimmed == "yes"
|| trimmed == "no"
|| trimmed.starts_with("1. yes")
@@ -700,8 +704,7 @@ mod tests {
#[test]
fn claude_waiting_selection_prompt() {
- let screen =
- "Do you want to proceed?\n❯ 1. Yes\n 2. No\n\nEsc to cancel · Tab to amend";
+ let screen = "Do you want to proceed?\n❯ 1. Yes\n 2. No\n\nEsc to cancel · Tab to amend";
assert_eq!(detect_claude(screen), AgentState::Blocked);
}