Skip to content

fix(herdr): plugin panes fail to spawn (relative program path) - #100

Merged
pgebheim merged 3 commits into
mainfrom
pgebheim/herdr-pane-spawn-path
Aug 5, 2026
Merged

pgebheim merged 3 commits into
mainfrom
pgebheim/herdr-pane-spawn-path

Conversation

@pgebheim

@pgebheim pgebheim commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

The herdr plugin's box/agent/boxes panes never opened as shipped — every one failed with plugin_pane_open_failed: … No viable candidates found in PATH. Root cause: the pane commands used ["bin/lilbox-herdr", <sub>], but herdr's pane spawner resolves argv[0] against PATH — unlike its action runner, it does not honour the plugin dir as the program's lookup root. So the relative path was never found. The one-shot actions (status/expose/kill/…) worked because they take the action code path; only the panes — the plugin's headline feature — were broken.

Fix: launch the three panes via sh -c and reach the shim by absolute path through herdr's injected $HERDR_PLUGIN_ROOT:

# before — fails: relative program, PATH-searched
command = ["bin/lilbox-herdr", "agent"]
# after  — works: sh is on PATH, $HERDR_PLUGIN_ROOT is absolute
command = ["sh", "-c", "exec \"$HERDR_PLUGIN_ROOT/bin/lilbox-herdr\" agent"]

Actions keep the direct form (the action runner resolves it fine).

Verification (live, herdr 0.7.5)

  • Before: herdr plugin pane open --entrypoint boxes → plugin_pane_open_failed.
  • After: same call → plugin_pane_opened, and reading the pane terminal shows real shim output (lilbox ls via the watch entrypoint) — proving $HERDR_PLUGIN_ROOT expands and the shim executes, not just that sh spawned.

Tests

  • New pane_programs_are_path_resolvable pins the invariant: no pane runs a relative-with-slash program — checking the effective program the launcher execs, not just argv[0].
  • Taught the two contract tests (shim_commands_exist_and_are_executable, every_shim_subcommand_in_the_manifest_is_dispatched) both command forms via helpers shim_subcommand / plugin_relative_targets / effective_pane_program; extraction tolerates the ${VAR} brace form.
  • cargo test --locked → 94 passed.

Docs (second commit)

  • Removed a nonexistent "action menu" claim from contrib/herdr/README.md — herdr has no plugin-action palette; actions run via a keybinding or herdr plugin action invoke.
  • Added a "Driving it over Herdr Mirror" section: a plugin_action keybinding resolves on the local herdr (where lilbox isn't), and Mirror forwards raw pane input but not prefix-mode commands — so a keybinding can't reach the remote box from either config. Documents the two paths that work (invoke from a mirrored remote pane; or herdr --remote <host> --remote-keybindings server) and notes the worktree.removed teardown hook is unaffected.

Architecture

No architectural change. No new dependency, abstraction, or Rust code touched — only the plugin manifest (contrib/herdr/), its README, and the manifest test harness. The manifest⇄shim contract's two halves move together.

🤖 Generated with Claude Code

pgebheim and others added 3 commits August 5, 2026 06:14
The box/agent/boxes panes ran `["bin/lilbox-herdr", <sub>]`. Herdr's
pane spawner resolves argv[0] against PATH — unlike its action runner,
it does not honour the plugin dir as the program's lookup root — so the
relative path was "not found in PATH" and every pane failed with
plugin_pane_open_failed. The plugin's headline box/agent panes never
opened as shipped; only the one-shot actions (which take the action
code path) worked.

Launch the panes via `sh -c` and reach the shim by absolute path through
the herdr-injected $HERDR_PLUGIN_ROOT. Actions keep the direct form,
which resolves fine.

Tests: pin the invariant that no pane program is a relative-with-slash
path, and teach the shim-existence / dispatch contract tests both the
direct and launcher command forms.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GGspVVM6AEiQQxAd11e8zh
herdr has no action-menu / command palette that lists plugin actions —
actions run via a keybinding or `herdr plugin action invoke`. Fix the
"Use" line accordingly.

Add a "Driving it over Herdr Mirror" section: a plugin_action keybinding
resolves on the local herdr (where lilbox isn't), and Mirror forwards
raw pane input but not prefix-mode commands, so a keybinding can't reach
the remote box from either config. Document the two paths that work
(invoke from a mirrored remote pane, or `herdr --remote
--remote-keybindings server`) and note the teardown hook is unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GGspVVM6AEiQQxAd11e8zh
Review follow-up. `pane_programs_are_path_resolvable` checked argv[0],
so a regressed `["sh","-c","exec bin/lilbox-herdr open"]` (relative inner
path — the very bug this fixes) would have passed. Check the *effective*
program the launcher execs instead. Also make the $HERDR_PLUGIN_ROOT
extraction tolerate the `${VAR}` brace form so shim-existence checks
can't silently go vacuous on a future edit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GGspVVM6AEiQQxAd11e8zh
@pgebheim
pgebheim merged commit e0b8764 into main Aug 5, 2026
1 check passed
@pgebheim
pgebheim deleted the pgebheim/herdr-pane-spawn-path branch August 5, 2026 06:22
pgebheim added a commit that referenced this pull request Aug 11, 2026
herdr-mirror v0.2.0 ships `remote-invoke`, which forwards any plugin
action to the mirrored host behind the focused pane. That removes the
gap the "Driving it over Herdr Mirror" section documented since #100:
a locally-bound key can now open a box on the remote host directly.

Lead with the remote-invoke flow (bound as a `shell` command, since
`plugin_action` can't carry the action argument, plus the
`remote-actions` / `bind` / `unbind` helpers), gated on
herdr-mirror >= v0.2.0, and keep the mirrored-remote-pane and
`herdr --remote --remote-keybindings server` routes as fallbacks for
older versions.


Claude-Session: https://claude.ai/code/session_01WVWQzi2PPmxfNpC5ef6KWx

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant