feat(herdr): unlock agent-state detection by naming the container client after the agent - #28
Conversation
…ent after the agent herdr assigns pane identity from the host process tree only — on macOS the argv0 basename via sysctl(KERN_PROCARGS2) — and that identity gates its screen-content state detection (idle/working/blocked). pall8t exec-replaces itself with `container`, which herdr doesn't recognize, so a sandboxed pane's state was never tracked (the gap README documented after #23). The pane's terminal shows the agent's real UI, so detection works the moment the pane has the right identity. `pall8t run` now execs the container client with argv[0] set to the sandboxed agent's name: the first token of the run command that herdr recognizes (KNOWN_AGENTS allowlist mirroring herdr's identify_agent; launchers like env/npx/uv and pkg@version specs are looked through, and only the first token may be a path so argument paths and VAR=VAL assignments can never mislabel the pane), falling back to HERDR_AGENT when the command contains no recognized name — herdr's own env hint is Linux-only (/proc environ), so pall8t honors it on macOS. Unrecognized names are never asserted: no hint means no argv0 override and no display report, and a note is printed when a derived name shadows a differing HERDR_AGENT. The sidebar display report now interpolates the derived agent, `pall8t herdr doctor` reports HERDR_AGENT, and `pall8t exec` never hints (an ambient HERDR_AGENT would mislabel a debug shell). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rgv[0] Live testing found the argv0 agent hint never reached the long-lived client process: Homebrew installs `container` as a bash wrapper (`CONTAINER_INSTALL_ROOT="…" exec "<cellar>/libexec/container" "$@"`) whose inner exec rewrites argv[0] to the full Cellar path — confirmed via ps, and confirmed as the only broken link by rebuilding herdr 0.7.3 from source and replaying the captured claude byte stream through it (idle→working→idle transitions work once the pane is identified; the titles also verifiably reach the host PTY). When an agent hint exists, pall8t now resolves `container` on PATH and, if it is a strict pass-through exec wrapper, execs the wrapper's target binary directly with the wrapper's env assignments applied, so argv[0] survives. Anything unparseable (real binary, symlink, wrapper with extra logic) falls back to the previous behavior. The client process also gets HERDR_AGENT set, so a future herdr macOS env hint could carry the name even where argv0 cannot. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Live testing revealed the argv0 hint was being destroyed one hop after pall8t set it: Homebrew installs Everything else was verified working along the way:
New commit: when an agent hint exists, pall8t resolves Remaining live verification (first true test of the Cellar binary running under a foreign argv[0] — the wrapper had shielded it until now): rebuild from this branch and run under herdr; confirm (1) the container still launches, (2) 🤖 Generated with Claude Code |
|
Live verification complete on a Homebrew apple/container install: the Cellar binary launches normally under the foreign argv[0], 🤖 Generated with Claude Code |
Summary
Follow-up to #23, fixing the gap it documented: herdr never tracked agent state (idle/working/blocked) for a pall8t-sandboxed pane. Confirmed from herdr's source (
ogulcancelik/herdr): pane identity comes exclusively from the host process tree — on macOS the argv0 basename viasysctl(KERN_PROCARGS2)(platform/macos.rs::process_argv0_name, preferred bydetect::normalized_process_name) — and that identity is what gates herdr's screen-content state detection. pall8t exec-replaces itself withcontainer, which herdr doesn't recognize, so detection never ran; the pane's PTY shows the agent's real TUI, so identity was the only missing piece. herdr's ownHERDR_AGENTenv hint is Linux-only (/proc/<pid>/environ; the macOSprocess_agent_hintis a stub), and its Claude integration hooks needHERDR_*env plus the host socket, neither reachable inside the VM.The fix:
pall8t runexecs the container client withargv[0]set to the agent's name (CommandExt::arg0— binary resolution still findscontaineron PATH). Guardrails, shaped by four review rounds:KNOWN_AGENTS, mirroring herdr'sidentify_agentaliases) is used; launchers (env FOO=1 claude,npx -y codex,uv run claude) andpkg@version/@scope/pkgspecs are looked through. Only the first token may be a path, so argument paths andVAR=VALassignments (env HOME=/home/claude codex) can never mislabel the pane. Anything unrecognized yields no hint — never a guess.HERDR_AGENTis the fallback, honored by pall8t on macOS for commands with no recognizable name (wrapper scripts,sh -c …). A name found in the command wins over it — an env var baked into a shell function is ambient — and pall8t prints a note when it ignores one. The README'sp8()example no longer hardcodes it.containerand no display report is sent (status quo of herdr integration (Phase 1) + pall8t ls status-parsing fix #23). With a hint, the sidebar report becomes--display-agent "<agent> (pall8t)"instead of hardcoded claude. Verified against herdr's metadata guards that the report (sent without--agent) is unaffected by the argv0 change.pall8t execnever hints — an ambientHERDR_AGENTwould mislabel a one-off debug shell.pall8t herdr doctornow reportsHERDR_AGENT(informational).Known accepted residuals: a bare agent-named argument before the real program (e.g.
tmux … -s claude codexpassed explicitly) can still match — it has no syntactic tell;KNOWN_AGENTSmay drift behind herdr — drift is safe (no hint,HERDR_AGENTcovers it). Upstream, implementing herdr'sprocess_agent_hinton macOS (theKERN_PROCARGS2buffer already contains the environment) would makeHERDR_AGENTwork natively; worth filing.Test plan
cargo test(131 tests, incl. new derivation/precedence/no-guess tables),cargo clippy --all-targets -- -D warningson bothaarch64-unknown-linux-gnuandaarch64-apple-darwin,cargo fmt --checkherdr agent start … -- pall8t runin this repo — confirm (1) the run still works end to end with argv0 spoofed, i.e. Apple'scontainerCLI doesn't misbehave when its argv[0] isclaude(Swift ArgumentParser uses it for usage text only, but this is the one assumption not verifiable from inside the sandbox); (2) the herdr sidebar shows working/idle/blocked transitions for the sandboxed claude; (3)psshows the client process asclaude(cosmetic, expected)🤖 Generated with Claude Code