Herdr FAQ
SkillAI & modelsLaunch and drive coding agents (codex, claude, agy) through the Herdr CLI; requires a herdr pane (HERDR_ENV=1). Use before starting or prompting a herdr subagent, and when a herdr command fails or an agent seems stuck or silently lost a prompt.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Herdr FAQ skill
What this skill tells your AI
The instructions your AI receives, as published by tenequm/skills in skills/herdr-faq/SKILL.md and read by ahel’s review.
Launch and drive coding agents through Herdr (>= 0.9.0) without losing prompts.
Syntax authority
herdr --skill (~13k chars) is the vendor reference: command model, IDs, lifecycle
states, prompt and wait mechanics, read sources, safety rules. Read it once per session
before your first herdr command - this file assumes it and repeats none of it. For
flags, run the command group bare (herdr agent, herdr pane) or --help; never bare
herdr (it launches the TUI). If a syntax question is not answered here, it is
answered there - go get it, never guess a flag.
When this lane
test "${HERDR_ENV:-}" = 1 # never drive herdr from outside a pane
Unset means this shell is not herdr-managed: no $HERDR_PANE_ID, no --current, and
an untargeted command lands on whatever pane the USER has focused. Use acpx instead
(acpx-faq). In-session fan-out stays on the harness's own subagent tool.
Invariants
- Exit 0 is submission, never completion - and
send-keyscan return{"type":"ok"}for keystrokes that never reach the pane. Confirm by effect: state moved, or the text is visible in the pane. - Screens no detection rule matches read as
idle. agy has no idle rule at all, so every agyidleis a guess. Read the screen before the first prompt, always. agent starttimeout = the child never launched (bad flag, PATH, or a wrapper process).pane readhas the real error;pane process-infoand herdr's own message do not.idleis not "finished". A claude turn that spawned background shells or a background MCP task ends and reportsidlewhile that work runs on;--waittracks lifecycle state, not turns.- The driving harness is a second gate. Dangerous passthrough flags
(
--dangerously-*,danger-full-access) get classifier-blocked, and so can ordinary brief content inlined into a shell command.sleep N; herdr ...polling is banned - use one backgroundedprompt, or wait on a file.
Per kind
Model defaults unless the task argues otherwise: codex gpt-5.6-sol at
reasoning_effort high (set via codex's own flags/config - check codex --help),
claude claude-opus-5, agy gemini-3.7-flash-medium (measured on par with Opus for
rubric-driven bulk work and far faster; gemini-3.8-flash-high measured worse on the
same task). One directory per agent, always.
codex
P=$(herdr pane split --current --direction right --cwd "$D" --no-focus | jq -r .result.pane.pane_id)
herdr agent start cx1 --kind codex --pane "$P" --timeout 90000 -- --approve-for-me --no-alt-screen
herdr agent read cx1 --source detection --lines 40 # ALWAYS, before the first prompt
herdr agent prompt cx1 "Carry out $D/brief.md." --wait --timeout 1800000 &
Never --full-auto: removed in 0.15x, it surfaces as a bare timeout and can wedge
the pane in startup-pending. The trust-directory and startup-update dialogs are
detected, so an untrusted dir fails fast with agent_not_ready rather than eating the
first prompt. The one-time post-integration install hooks-review gate is NOT
detected (WONTFIX) - answer it once per machine. Session ref binds at the first prompt
for a fresh start; an explicit -- resume <id> is persisted at launch.
claude (alias claude-code)
# Pre-trust first - the folder-trust dialog IS detected, so an untrusted dir fails the
# start. Trust is INHERITED: a new dir under an already-trusted parent needs nothing.
CFG=/tmp/agentcfg; mkdir -p "$CFG" # isolated from your real config
printf '{"projects":{"%s":{"hasTrustDialogAccepted":true}}}' "$D" > "$CFG/.claude.json"
P=$(herdr pane split --current --cwd "$D" --no-focus --env CLAUDE_CONFIG_DIR="$CFG" \
| jq -r .result.pane.pane_id)
herdr agent start cl1 --kind claude --pane "$P" --timeout 90000 -- --model claude-opus-5
herdr agent read cl1 --source detection --lines 40 # ALWAYS, before the first prompt
herdr agent prompt cl1 "Carry out $D/brief.md." --wait --timeout 1800000 &
- The safe key differs per dialog. The folder-trust dialog puts the cursor on
No, exit, so a bareenterkills the agent - senddown enter. The Bash-permission dialog puts the cursor on1. Yes. idlelies in a specific way here. Background shells end the turn and reportidlewhile they run; background agents and MCP tasks keep itworking, and a background MCP task can holdidlefor its whole 3-10 minute life.- Grey next-prompt-suggestion text reads as real unsubmitted text in a plain
read - disambiguate with
--format ansi(the suggestion carries the dim attributeESC[2m). - Session ref binds at launch. A Claude Code UI update can break detection
(
herdr server update-agent-manifests). Native-launcher installs run under a version-string process herdr cannot identify: launch viaHERDR_AGENT=claude exec <path>, thenagent rename. - Under a different
CLAUDE_CONFIG_DIRthe agent loads its own skills. Confirm they are current before its first turn - a running session has already snapshotted the old text.
agy (aliases antigravity, antigravity-cli)
Thinnest detection of the three: no idle rule at all (invariant 2), and nothing in the pre-flight is recoverable once the agent is up.
D=/abs/dir/for/this/agent # ONE dir per agent - agy reads sibling files
mkdir -p "$D"; : > "$D/report.md" # pre-create the output file
python3 - "$D" <<'PY' # pre-trust; the dialog is unanswerable (below)
import json, pathlib, sys
p = pathlib.Path.home() / ".gemini/antigravity-cli/settings.json"
d = json.loads(p.read_text()) if p.exists() else {}
tw = d.setdefault("trustedWorkspaces", []) # a list of exact paths, not a map
if sys.argv[1] not in tw: tw.append(sys.argv[1])
p.write_text(json.dumps(d, indent=2) + "\n")
PY
P=$(herdr tab create --workspace "$WS" --cwd "$D" --label ag1 --no-focus \
| jq -r .result.root_pane.pane_id) # one TAB per agent, never N panes in one tab
herdr agent start ag1 --kind agy --pane "$P" --timeout 120000 \
-- --model gemini-3.7-flash-medium --effort medium --mode accept-edits
herdr agent read ag1 --source detection --lines 15 # read the banner, not the status
herdr agent prompt ag1 "Carry out $D/brief.md. Write your report to $D/report.md." \
--wait --timeout 1800000 & # then poll for the file, not the state
- The trust dialog is unanswerable from this side.
agent startreturnsidle, the screen holdsDo you trust the contents of this project?, andsend-keys enterno-ops against it - repeatedly, silently, exit 0.--dangerously-skip-permissionsis classifier-blocked before it reaches herdr (invariant 5). Only a config entry written beforeagent startpre-empts it. - Trust lives in
trustedWorkspacesin~/.gemini/antigravity-cli/settings.json, NOT~/.gemini/trustedFolders.json(the Gemini CLI's file - observed ignored on agy 1.2.0). Pre-writing it is not confirmed end to end, and a harness classifier may refuse the edit as a trust-config change - when it does, drive agy through acpx instead (acpx-faq): its ACP server has no folder-trust dialog. - One tab per agent. Four agy panes in one tab leaves ~29 columns: the TUI stops rendering, input races swallow prompts, and detection sees only the pane's own rows, so the state you read is wrong too.
- Read the startup banner before blaming herdr.
<account> (Google AI Pro)means entitlement is reaching Code Assist. A bare address, orEligibility check failed: UNAVAILABLE (code 503), means dead on arrival however healthy the status looks - re-auth, do not re-prompt. not a valid artifact pathis agy-internal, not your filesystem.ArtifactMetadataon awrite_to_fileconfines the write to~/.gemini/antigravity-cli/brain/<session-id>/. It self-recovers by retrying asEdit; pre-creating the file empty skips the round trip.- agy reads sibling files unprompted - agents sharing a directory reproduce each
other's output. Own directory each, and
md5any rerun before believing an agreement number: byte-identical multi-KB prose is copying, not consensus. - Premature
donelasts up to ~50s mid-turn while the pane visibly streams - wait on the report file, never a settled state. A first prompt can be swallowed entirely withagent_prompt_stalledand no trace in the composer; re-prompt, neversend-keys. No session ref until the first prompt. Integration install target isantigravity-cli;~/.gemini/configmust exist (orANTIGRAVITY_CLI_CONFIG_DIR).
Integrations for all three are session-restore only - they never improve state
detection - and their hooks silently no-op without python3 on PATH.
integration status cannot see a codex-side disabled hook (WONTFIX); verify
agent_session is present after the first codex turn instead.
Launch and fleets
- Fleets: one tab per agent (
herdr tab create --workspace "$WS" --cwd "$D" --no-focus), own workspace,--no-focuseverywhere. Repeated splits leave panes narrow, and a TUI below its minimum width stops rendering, swallows input, and hides its state from detection (which sees only the pane's own rows; fallback 24). - Always
agent read --source detectionbefore the first prompt (invariant 2) and branch on it - never blind-fire a key at a dialog. After answering one, gate onagent wait <n> --until idle done --timeout 60000: a barewaitreturns the still-blockedstate within milliseconds, a no-op that looks like the key never landed. - Names die with the agent and freed names get recycled - namespace them
(
myproj-reviewer). After a killedagent start, oneherdr agent get <name>frees the reservation (reconciliation is lazy). An agent TARGET can be a bare pane id (agent prompt w1K:p1 '<text>') - how you reach an unnamed agent without renaming someone else's. - Test
-n "$P"after capturing a pane id: an empty one makes later parsers blame the wrong token.
Composing traps
agent readandpane readreturn raw pane text; the other agent/pane/workspace commands return JSON. Piping raw text tojqdies withparse error: Invalid numeric literaland you silently lose the read - usetail,grep -qF.pane read <id>takes the pane positionally and has no--paneat all (unknown option: --pane);pane closelikewise. When in doubt read theUsage:line - it names positionals in angle brackets.agent start --timeoutdefaults to 30000 and caps at 300000.agent prompt --timeouthas no cap (1800000 is fine) but is rejected with--timeout requires --waitwhen--waitis absent - and backgrounded, that failure is invisible and the prompt is never written. Fire-and-forget sends take no flags.agent listJSON is sparse:nameis absent (not null) for unnamed agents, and a pending start is{"agent_status":"unknown","launch_pending":true}. Null-guard every string op:select((.name // "") | startswith("myproj-")).- Env vars go in
--env KEY=VALUEat pane/tab/workspace creation, neverpane run 'export ...'(a subshell the agent never sees). Repeated flags go inline - zsh does not word-split an unquoted$E, soE="--env A=1 --env B=2"arrives as one bogus argument. - Bad flags print usage partly on stdout, so a
| jqpipeline turns it into a misleading parse error - check exit status before parsing.
Drive
- Wait on the artifact, not the state. End every non-trivial brief with "write
your full report to
<path>and reply with only the path", and poll for the file.idlearrives on interrupted turns, on fleet parents that dispatched children, and for the whole life of a claude background MCP task (invariant 4) - a watcher on!= workingfalse-alarms on every one of those. - Gate decisions on
agent_status, neverinteractive_ready(it stays true while blocked). - Long text is safe through
agent prompt(bracketed paste; 8 KB arrives intact); the 1024-byte macOS tty truncation applies topane send-textand keystrokes. Pass file paths anyway - it also keeps brief content out of the shell command (invariant 5). - Queue follow-ups behind a working agent freely (
promptrefuses blocked agents before writing anything) - but no--waiton a queued follow-up: it can be satisfied by the turn already running. - Slash commands that open dialogs trip the fixed 5s stall gate - verify those by
screen read, not
--wait. - Exit: confirm positively -
pane process-infoshows the shell back in the foreground - thenpane close. Never regex the prompt.
Failures
Triage first:
- Any start failure ->
herdr pane read <pane> --source visibleFIRST. Most common: the child launched, printederror: unknown option ..., and exited -process-infolooks innocent and herdr reports a baretimeout. Thenprocess-info: a foreign foreground process = busy/race; an agent under a wrapper (node, a bare version string) = relaunch viaHERDR_AGENT=<kind> exec <cmd>, thenagent rename; underdocker exec,podman exec, orssh -t= permanently undetectable (WONTFIX). - Any wrong state ->
agent explain <target> --verbose+agent read --source detection. Matched rule null +default_known_agent_idle_fallback= herdr is guessing. Stale manifest ->herdr server update-agent-manifests(no restart). Local rule patch:~/.config/herdr/agent-detection/<kind>.toml. Logs:~/.config/herdr/herdr-server.log,HERDR_LOG=herdr=debug. - After a binary update, do NOT reflexively
server stop- it kills every pane process and in-flight turn, unresumably. 0.9.0 leaves a compatible server and its agents untouched; trustherdr status(endpoint_compatible,restart_needed,server_binary_stale). A stale CLIENT inverts the picture: it calls the server "old" whilepane listcorrectly saysclient protocol N is older than server. - "herdr is stuck" is often the terminal emulator, not herdr - open a fresh tab before touching the server.
Catalog:
-
agent_not_ready(start) - a dialog is on screen; exit 1 but the agent is running and the name is bound. Read, answer viasend-keys(safe keys in Per kind), gate--until idle done, prompt. A blocked launch never times out (launch_pendingstays true until answered). agy's trust dialog is NOT detected and reads asidleinstead - see agy. -
timeout(start) - invariant 3; read the pane.command not foundin a non-login shell: set[terminal] shell_mode = "login", recreate the pane. Under--remote, panes inherit the SERVER's PATH, so a~/.local/binagent CLI gives a bare timeout. -
agent_name_taken/agent_launch_pending- reservations reconcile lazily: oneherdr agent get <name>frees an expired one. Still wedged: burn both - fresh pane, fresh name. -
agent_pane_busy- "available shell" = the shell itself, alone, in the foreground. (a) racy rc files (starship,direnv): herdr retries only 2s andpane getlooks identical ready vs not - retry with backoff, clean up orphaned tabs; (b) genuine occupant: split a new pane, never reclaim (killing the occupant cascades intopane_not_found). (Windows: pwsh chain-launch profiles nest shells - set[terminal] default_shell = "pwsh.exe".) -
agent_not_found- downstream symptom: failed start, exited agent, or a bad name earlier in the loop. A live pane can rarely lose registration while the TUI runs fine -agent rename <pane> <same-name>restores it. -
timeout(prompt --wait / wait) - usually the turn outlasted the timeout:agent getshowsworking. Use 1800000+, background it, never resend on timeout alone. -
agent_prompt_stalled- not proof of non-delivery; the text may have landed and been consumed. Causes in observed order: stale manifest; a dialog-opening prompt; a target-side paste modal swallowing Enter (omp's Large Paste Menu triggers on line count, not bytes - disable it in omp/settings). Never blind-resend and never recover with a lonesend-keys enter. Read the pane, then re-send with a freshagent prompt:for i in 1 2 3; do herdr agent prompt "$A" "$TEXT" --wait --timeout 60000 && break herdr agent read "$A" --source recent-unwrapped --lines 200 | grep -qF "${TEXT:0:80}" && break done -
agent_blocked(prompt) - refused before anything is written. Read detection, surface the dialog, answer via send-keys. -
invalid_agent_name-[a-z][a-z0-9_-]{0,31}; uppercase from shell loops cascades into a wall ofagent_not_founds. -
pane_not_found/workspace_not_found/unknown option: <valid-looking value>- IDs are runtime-only, never reused: re-list at session start, recreate only what is missing.unknown optionon a whole flag string is the zsh variable trap (see Composing traps); on a lone token it is usually an empty$P. -
workspace_group_close_required- closing a primary workspace with open worktree workspaces needsworkspace close --group;tab closecan likewise returnconfirmation_requiredfor a worktree group. -
Harness blocks - classifier denial on dangerous passthrough flags: put permissiveness in the child agent's own config ("Stage 2 classifier error" is transient - retry once). Allowlist the read-only commands (
agent get/read/list/wait/explain,pane read/list/process-info,workspace list) or every call prompts.
Silent failures (exit 0, no error): fallback-idle prompt swallowing (invariant 2);
send-keys returning ok without delivering; a bare agent prompt leaving text
unsubmitted in an out-of-view pane; a first turn going straight
unknown -> working -> idle skips done and its notification; a tall dialog partly
invisible in a short pane (detection sees only the pane's own rows);
pane wait-output matching the echoed command itself - never use it for readiness;
agent focus returning ok without moving the viewport in 0.9.0 - use tab focus.
Signals
- GitHub stars
- 36
- Forks
- 1
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
herdr-faq- Source
- github.com/tenequm/skills