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.

HarnessModel tiersLaunch mapping
Claude Codehaiku, sonnet, opus--model <tier> --effort <effort>
Codexluna, terra, sol-m gpt-5.6-<tier> -c model_reasoning_effort="<effort>"
OpenCodedeepseek, glm, kimi--model opencode-go/<model>
Pideepseek, 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 snapshot
  • claude-quota.json, a normalized Claude Code status-line snapshot
  • routing.jsonl, the append-only redacted routing audit, unless --audit-path specifies 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.

Licensed under Apache License 2.0. See LICENSE and NOTICE.