Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

herdr-padio

A herdr plugin that tells PadIO which app is running in the focused pane, so your game controller switches mode automatically as you move around.

Focus a Claude Code pane and the controller is in agent mode. Move to a shell pane and it is in shell mode. Launch nvim in that pane and it becomes vim mode. No manual mode picking.

How it works

The bridge polls herdr for the focused pane and writes a single token to ~/.config/padio/context. PadIO watches that file and maps the token to a mode via context_modes.

herdr                                bridge                     PadIO
─────                                ──────                     ─────
poll pane.current @5Hz  ──>  agent field, else argv0   ──> write ──> file watch
                             where pid == pgid          context      → mode

The token is resolved in two steps:

  1. If herdr has detected an agent in the pane, its agent field is used directly (claude, and so on). herdr does this detection itself, so no process inspection is needed.
  2. Otherwise the bridge asks for pane.process_info and takes the argv0 of the process whose pid equals foreground_process_group_id — the process actually driving the pane. That yields zsh for a shell, ssh for a remote session, nvim for an editor.

Why it polls instead of subscribing

herdr has an event stream, and pane.focused is an accurate focus signal: measured on 0.7.5, four real focus changes produced exactly four events, in order, each arriving ahead of a 2 Hz poll, with no spurious events. An event-driven bridge is therefore possible. This one still polls, for two reasons.

events.subscribe replays retained history (#1270). Every new subscription first re-delivers a buffer of past events — 116 of them on the session this was developed against — paced at about 100 ms, before any live event arrives. It is per subscription rather than per connection, and nothing marks where the replay ends, so a subscriber cannot cleanly tell stale from live. Acting on the replay would walk the mode through every historical focus change in turn. Working around it means a heuristic, such as treating a quiet gap as the end of history, and reapplying it after every reconnect.

Polling is cheaper than that heuristic. Connect plus one pane.current costs about 0.14 ms, so 5 Hz is roughly 1 ms of work per second. It also collapses two cases into one call: pane switches and launching a program inside a pane you are already in. The latter has no reliable event at all, since pane.updated is touch-driven and a process change on its own emits nothing (#2115).

So the tradeoff is a millisecond a second against replay-detection logic and a second code path. If #1270 is fixed with an explicit "live only" or cursor option, switching to events would be worthwhile.

Install

herdr plugin install vgreg/herdr-padio

Requires python3 on PATH (no packages, stdlib only) and PadIO 2026.3.0 or later.

To run it outside herdr, or to develop against a checkout:

git clone https://github.com/vgreg/herdr-padio
herdr plugin link ./herdr-padio

Configure PadIO

Map tokens to modes in the profile for your terminal, in ~/.config/padio/config.json. Put herdr's own workspace/tab/pane navigation in global so it stays available in every mode:

{
  "profiles": {
    "ghostty": {
      "apps": ["com.mitchellh.ghostty"],
      "default_mode": "herdr-nav",
      "global": { "…": "workspace / tab / pane navigation" },
      "context_modes": {
        "claude": "agent",
        "nvim": "vim",
        "zsh": "shell",
        "ssh": "shell"
      },
      "hidden_modes": ["agent", "vim"],
      "modes": { "herdr-nav": {}, "agent": {}, "vim": {}, "shell": {} }
    }
  }
}

Matching is exact. Three PadIO behaviours are worth knowing:

  • A token with no context_modes entry leaves the current mode alone. It does not fall back to default_mode, so you only need entries for apps you care about.
  • A mode picked by hand sticks until the context token changes.
  • hidden_modes keeps context-driven modes out of the mode picker while leaving them reachable. Useful once you have one mode per app and only want to pick a couple by hand.

Naming wrapped programs

Some tools run under a wrapper, so argv0 is unhelpful: node for a JavaScript CLI, uv for uv run python …. Add substring rules in ~/.config/padio/bridge.json:

{
  "rules": [
    { "match": "bin/some-cli", "token": "some-cli" },
    { "match": "uv run python train", "token": "training" }
  ]
}

Each rule's match is tested as a plain substring against the process command line, most specific first; the first hit wins. Rules are tried against the pane's main process, then any other foreground process. If none match, the bridge falls back to argv0.

Identifying the app is the bridge's job; mapping that name to a mode is PadIO's. Keep rules here and modes in context_modes.

Troubleshooting

See what the bridge resolves right now, without writing anything:

python3 padio_bridge.py --once

Inspect a specific pane instead of the focused one:

python3 padio_bridge.py --once --pane w5:p2

Read the plugin's output:

herdr plugin log

Other flags: --interval (poll seconds, default 0.2), --context (output path), --rules (rules file), --quiet.

Behaviour notes

  • The bridge writes only when the resolved token changes, via a temp file plus rename, which is the atomic-replace contract PadIO's file watcher expects.
  • A pane it cannot identify leaves the context file untouched, matching PadIO's "no match leaves the mode alone" rule.
  • If herdr is unreachable it retries with backoff and says so once. PadIO keeps working with manual mode switching, since a missing or stale context file is a no-op.
  • The context file is not cleared on exit, so the last mode persists. This is deliberate and consistent with the rule above.
  • The bridge owns the context file. If something else overwrites it, the bridge will not restore it until the resolved token next changes.

License

MIT

About

Switch PadIO controller modes automatically based on the app running in herdr's focused pane

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages