Herdr Jev Router
September 20, 2026 ยท View on GitHub
Herdr Jev Router is the policy command for mandatory agent.spawn routing in
Herdr. It reads one structured spawn request, checks cached provider
capacity, asks Jev for typed choices, validates the result, and writes a
redacted audit record. Protocol v1 returns an allowlisted launch profile in one
call. Protocol v2 returns review data first, then authorizes the reviewed
selection without calling Jev again. Herdr starts the selected child only after
the applicable policy flow succeeds.
The enforcement boundary is Herdr's patched agent.spawn path. This router
does not control a process that starts codex, claude, opencode, pi, or
another agent directly from an unrestricted shell. It does not reroute an
already running agent or aggregate quota across machines.
Status
This project is experimental and mandatory routing is not complete. Treat the
enforcement claims as unproven. PLAN.md section 18 records each of the
fifteen release conditions as verified or not verified, with the evidence it
rests on.
Harnesses
Four harnesses are routable. The caller still cannot choose one.
| Harness | Model tiers | Launch mapping |
|---|---|---|
| Claude Code | haiku, sonnet, opus | --model <tier> --effort <effort> |
| Codex | luna, terra, sol | -m gpt-5.6-<tier> -c model_reasoning_effort="<effort>" |
| OpenCode | deepseek, glm, kimi | --model opencode-go/<model> |
| Pi | deepseek, glm, kimi | --provider opencode-go --model <model> --thinking <effort> |
OpenCode's interactive TUI does not accept a reasoning-effort flag, so its
effort is decided and audited but not passed on the command line. Pi receives
it as --thinking. OpenCode and Pi have no local subscription-quota source;
they are reported as unknown capacity and remain eligible with the
deterministic penalty. The matched Herdr build must approve the new harnesses
through approved_launch; see docs/multi-harness-routing.md.
Installation
Requirements are macOS or Linux, Python 3.11 or newer, uv, and the compatible
Herdr build. The first release uses POSIX file locking and does not support
Windows.
The current compatibility target is Herdr v0.9.1 with the agent.spawn
mandatory-routing patch, built from the public fork at commit
2c75df59341d97f73a2e0b60af713ade55d9eaef plus
docs/herdr-multi-harness.patch. The plugin
manifest declares min_herdr_version = "0.9.1".
Install the plugin from this repository using the normal Herdr plugin installation flow. Its build command is:
uv sync --frozen --no-dev
The installed command is herdr-jev-router route. Set the Jev credential in
the environment inherited by the policy command:
export TYPESAFE_API_KEY='your-key'
Set the key only in the Herdr server launch environment or a dedicated policy
wrapper. Do not export it from .zshrc, .bashrc, or another pane shell
startup file. A shell startup file can deliberately add the variable again
after Herdr removes it, which would expose it to commands and agents in that
shell. Do not put the key in a request, Herdr task text, an audit record, or a
quota cache.
Build the compatible Herdr fork before enabling mandatory routing. Apply the multi-harness patch to the pinned fork commit first, then keep the current executable and configuration until the routed spawn test passes:
git -C /path/to/herdr apply /path/to/herdr-jev-router/docs/herdr-multi-harness.patch
cargo build --release --locked
cp "$(command -v herdr)" "$HOME/.local/bin/herdr.pre-jev-router"
cp "$HOME/.config/herdr/config.toml" "$HOME/.config/herdr/config.toml.pre-jev-router"
install -m 755 target/release/herdr "$HOME/.local/bin/herdr"
If the running server supports live handoff, the new executable can import its panes without stopping them:
herdr server live-handoff --import-exe "$HOME/.local/bin/herdr"
Enable mandatory routing only after that handoff. Adding or removing
agent_routing.policy_env requires a full Herdr restart because an existing
pane environment cannot be scrubbed retroactively.
To roll back, restore both backups, remove the [agent_routing] section from
the active configuration by restoring the configuration backup, then perform a
full Herdr restart:
install -m 755 "$HOME/.local/bin/herdr.pre-jev-router" "$HOME/.local/bin/herdr"
install -m 600 "$HOME/.config/herdr/config.toml.pre-jev-router" "$HOME/.config/herdr/config.toml"
Do not delete either backup until herdr status reports a compatible running
server after the rollback test.
Mandatory Herdr configuration
Configure the patched Herdr server with an absolute policy command and pass only the required credential into its environment:
[agent_routing]
mode = "mandatory"
review = "required" # or "auto" to allow spawns with no foreground TUI
policy_command = ["/absolute/path/to/herdr-jev-router", "route"]
policy_env = ["TYPESAFE_API_KEY"]
policy_timeout_ms = 30000
review = "required" (the default) fails a routed spawn closed unless a
focused foreground TUI approves it. review = "auto" still uses that TUI when
one is present, but when none is it authorizes the recommendation itself and
records approval: "automatic" and human_approved: false in the audit. Use
auto only where an unattended parent agent must spawn children: it removes
the human check, so any process that can reach the socket can spawn without
oversight. See
docs/herdr-headless-auto-review.patch
for the matched Herdr change.
policy_env removes the named variables from environments inherited by panes
and agents. It cannot override a shell startup script that re-exports them, so
keeping policy credentials out of interactive shell configuration is a
deployment requirement.
In mandatory mode, agent.spawn is the managed child-start path and
agent.start is rejected before terminal input is sent. A missing key, bad
configuration, policy timeout, Jev failure, invalid decision, or audit write
failure denies any operation that needs it. V2 authorization needs no Jev key,
but still fails closed on invalid review data or audit failure. Herdr must wait
for the target pane to be ready for the selected harness, then deliver the task
once. A readiness failure does not cause a second delivery.
State and audit files
The default state directory is $XDG_STATE_HOME/herdr-jev-router, or
~/.local/state/herdr-jev-router when XDG_STATE_HOME is unset. Set
HERDR_JEV_ROUTER_STATE_DIR to choose another directory. The directory is
created owner-only and contains:
codex-quota.json, a normalized Codex quota snapshotclaude-quota.json, a normalized Claude Code status-line snapshotrouting.jsonl, the append-only redacted routing audit, unless--audit-pathspecifies another path
Quota and audit files are written with mode 0600. They never contain the
request task, credentials, provider response bodies, transcript paths, session
IDs, working directories, or raw Jev usage.
The audit contains one record for every schema-valid routing recommendation or authorization that reaches the router, including safe denials such as exhausted capacity, Jev failure, invalid model output, and rejected overrides. Input that cannot be parsed or validated is rejected before it becomes a routing attempt and is not audited. CLI usage, request-validation, and configuration failures are outer-boundary denials and are not router audit events. Herdr remains the source of truth for those failures.
Spawning an agent
The Herdr CLI supplies the request to the router. The caller describes the work and constraints, but cannot choose a harness, model, effort, executable, raw arguments, or working directory:
herdr agent spawn security-reviewer \
--pane w1:p2 \
--task 'Review the authentication redesign for security risks.' \
--role reviewer
Herdr constructs the versioned request and authoritative pane context. The
router accepts roles worker, reviewer, debugger, and researcher, plus
the boolean constraints read_only, worktree, and network_required.
It writes exactly one JSON response. A successful v1 route or v2 authorization
returns a supported Herdr kind and allowlisted arguments. A successful v2
recommendation returns review data and no launch profile. Failure returns a
stable denial code and no launch profile.
Human review and overrides
Protocol v2 splits a reviewed spawn into two policy calls. recommend checks
capacity, calls Jev once, durably audits the recommendation, and returns the
recommendation, capacity snapshot, and allowlisted choices to Herdr without a
launch profile. The flow starts when a routed agent.spawn request arrives.
The server requires a live API caller and a focused foreground TUI, then sends
the review to that TUI before any child starts.
After the person confirms a selection, Herdr sends authorize with the exact
reviewed recommendation and capacity snapshot. Authorization does not call Jev
again and does not require a Jev credential. It strictly validates the selected
harness, model, and effort, writes the authorization audit record, and only then
returns the launch profile. Selecting an exhausted provider requires a second,
explicit confirmation in the UI.
Override authority belongs only to the foreground TUI connection to which the server bound the review. It is not a public socket capability. The public API and CLI do not accept override fields, launch arguments, or another way to inject a reviewed selection. Unknown or noncanonical fields in either v2 operation are rejected. Any invalid review data, missing confirmation, policy failure, or mandatory audit failure denies the spawn and returns no launch profile.
Only one review may be pending server-wide. A concurrent routed spawn is denied as busy. A review also fails closed if its API caller or bound TUI disconnects, the TUI loses foreground focus or its active surface, focus moves to another TUI, the 60-second review deadline expires, or the server shuts down or begins a live handoff. Reviews do not survive restart and are never transferred to a new foreground connection.
Protocol v1 remains accepted as the rollback-compatible, single-call path. It
calls Jev and returns the audited recommendation directly, with no human
override. Reverting Herdr to v1 without reverting this router only works when
the Herdr build can launch the selected harness; a pre-multi-harness Herdr
cannot launch opencode or pi, so keep the matched four-harness build or
constrain the router to claude and codex.
Quota inputs
Codex quota comes from the local codex app-server --listen stdio://
protocol, using account/read and account/rateLimits/read. API-key Codex
accounts are not treated as subscription capacity. Claude Code quota comes
from the configured status-line JSON feed, using rate_limits.five_hour,
rate_limits.seven_day, and rate_limits.spend_limit when present. See
docs/quota-sources.md for field validation, cache
freshness, and collector usage.
Missing or malformed input is unknown, never exhausted. A valid zero
remaining window or explicit reached signal is exhausted and removed before
Jev. Unknown providers remain eligible with a deterministic penalty. If no
provider remains, the route is denied without calling Jev.
Refresh Codex quota on demand with:
herdr-jev-quota-codex --state-dir ~/.local/state/herdr-jev-router
Configure Claude Code's status line to invoke the Claude collector. Claude passes its status-line JSON on standard input, and the collector writes only a normalized owner-only cache:
{
"statusLine": {
"type": "command",
"command": "/absolute/path/to/herdr-jev-quota-claude --state-dir /absolute/state/herdr-jev-router",
"refreshInterval": 1800
}
}
Inspect normalized capacity and validate the local installation without printing credentials or private paths:
herdr-jev-router usage --state-dir ~/.local/state/herdr-jev-router
herdr-jev-router doctor --state-dir ~/.local/state/herdr-jev-router
doctor reads TYPESAFE_API_KEY from its own environment, so run it with the
key available (for example
TYPESAFE_API_KEY=$(cat /run/secrets/typesafe_api_key) herdr-jev-router doctor)
or expect checks.credential.ok to be false. Herdr itself supplies the key to
the policy command through policy_env, not to an interactive shell.
Developer gate
uv sync
uv run pytest
uv run ruff check .
uv run ruff format --check .
uv run ty check src
git diff --check
Docker clean-room verification
The clean-room harness builds the router from this checkout, clones and builds
the public Herdr fork at commit
2c75df59341d97f73a2e0b60af713ade55d9eaef, runs the router gate and Herdr's
focused mandatory-routing tests, then makes one real Jev v2 recommendation.
The TypeSafe key is mounted as a read-only runtime file. It is not passed as a
Docker build argument, stored in an image layer, or printed by the harness.
With Docker running and TYPESAFE_API_KEY set, run:
./scripts/test-docker-cleanroom.sh
Success ends with two JSON lines whose events are
jev_v2_recommendation_ok and clean_room_ok. Docker cannot prove native
terminal focus, render the human approval UI as a real foreground application,
or launch a host-authenticated Codex or Claude Code process. Those behaviors
remain native Herdr end-to-end checks. The clean-room test does not add an
approval bypass.
The project uses test-driven development. Keep changes narrow, never log
credentials or private task data, and verify the complete agent.spawn path
against a real patched Herdr session before claiming mandatory enforcement.
Security boundaries are documented in SECURITY.md. The design details are in docs/herdr-enforcement-design.md.