Skip to content

Plugins

Herdr-compatible: same herdr-plugin.toml manifest format, same trust-preview install gate, same environment contract for the parts tmux can support.

Plugin support is in beta

Ten real herdr plugins were installed and run before this release. The compatibility matrix says which work, which cannot work in tmux, and which need a tool of their own. Other plugins have not been run under taw yet, so expect gaps.

taw plugin install owner/repo[/subdir][@ref] --yes   # or omit --yes for an interactive prompt
taw plugin update [id|source...] [--yes]             # fetch the installed ones again

Before running anything, install prints every [[build]] and [[startup]] command the manifest declares and requires --yes or an interactive y: the same trust preview herdr shows. A control character in the plugin's id, version or commands is written out there (\x1b, \r), so a command cannot redraw its line to look like another. Plugin processes get HERDR_BIN_PATH (call back into taw portably), HERDR_PLUGIN_CONFIG_DIR/HERDR_PLUGIN_STATE_DIR, HERDR_PLUGIN_CONTEXT_JSON, and matching HERDR_WORKSPACE_ID/HERDR_TAB_ID/ HERDR_PANE_ID, plus a TAW_ twin of every one of those. An action invoked with --pane gets that pane's tab and workspace too (with --tab, its workspace). Invoked without --pane, it gets a pane as herdr fills a missing context from the pane in front: the active pane of --tab or --workspace when you give one, else the pane the command runs in, else (outside tmux) the active pane of the session tmux takes as current. And HERDR_PLUGIN_CONTEXT_JSON carries herdr's own fields (workspace_id, tab_id, focused_pane_id, focused_pane_cwd, workspace_cwd, selected_text and the rest of herdr's PluginInvocationContext, null where taw has nothing) with taw's nested workspace, tab, pane and caller_pane_id beside them. taw plugin pane open takes herdr's flags (--plugin, --entrypoint, --placement, --direction, --target-pane, --cwd, --width, --height, --env KEY=VALUE, --focus) as well as PLUGIN.PANE, and answers in herdr's shape (plugin_pane holds plugin_id, entrypoint and the pane's record), with --cwd the folder the pane starts in and --target-pane the pane it opens beside. A pane's program named by a path inside the plugin (command = ["bin/tool"]) is found in the plugin's folder, as herdr finds it, wherever the pane starts; a bare name (sh, node) is looked up on PATH. Actions, hooks and build steps run in the plugin's folder. An event hook also gets HERDR_PLUGIN_EVENT_JSON, herdr's event envelope (event, and data with the fields herdr's event has, null where taw has nothing). A popup or overlay pane needs a client to show it on: with none attached, the call fails with "no attached client to open the popup on" (use --placement split there), and no error holds an --env value. taw plugin action invoke takes herdr's ACTION --plugin ID as well as ID.ACTION, and taw plugin action list and taw plugin log list take --plugin. disable and uninstall end the processes that plugin's [[startup]] commands started in this boot: the command's process group while the command runs, and once it has exited (a command that puts a daemon in the background), its group while a process in it started within 10 seconds of the command. A group that cannot be told for the plugin's that way is left alone, with a line in taw's log.

taw plugin update fetches a plugin installed from GitHub again at the ref it was installed with (a branch moves, a tag stays, a full commit pins), with no argument for every installed plugin. Name a plugin by its id or by the source you installed it from (owner/repo[/subdir]). A plugin whose ref still points at the commit you have is left as it is, found by asking GitHub for the commit, with nothing downloaded; a plugin pinned to a full commit is left as it is without asking at all. Each commit of a plugin lives in a folder of its own, named for it, so a build that writes the path it was built in (a Python virtual environment, for one) still finds it after an update. A new commit is fetched into its folder beside the old one, shown in the same trust preview with the same --yes rule, and built there; only then does the plugin switch to it, and the old folder is removed (if that fails, the result says so, and the update still stands). A build only ever runs in a folder that run made: taw plugin install over a plugin you have at the commit you already have, and an update to a commit whose folder another plugin lives in, build in a new folder of their own (<repo>@<12-char sha>-2, then -3 and so on) and switch to it the same way. Declining or a failed fetch or build removes the new folder and leaves the copy you have exactly as it was, build output included; a folder left by Ctrl-C at the prompt is removed at the next install or update of that repository, and your records and the copy you have are untouched. Plugins that an older taw installed from folders of one repository share its copy, so they update together, and a decline by any of them changes none. A plugin you linked from a local folder is left alone. An update keeps a plugin enabled or disabled and starts nothing: the new copy's startup commands run the next time tmux starts, as after disable and enable. A process the plugin started from its old folder keeps running from it after an update: restart it, or run taw plugin startup once the old one has stopped. @<sha> (and --ref <sha>) take a full 40-character commit and pin the plugin to it; a ref that looks like a short commit (7 to 39 hex characters) and that GitHub does not name as a branch or tag is refused before anything is fetched, with "give the full 40-character commit, or a branch or tag". GitHub serves a commit of any fork of a repository under that repository's address, so a pin should be a commit you have looked at: the trust preview names the commit it fetched, so check that it is the one you meant. The result lists each plugin as updated, unchanged, linked or failed, with the reason; one failing does not stop the others, and the command then exits 1.

HERDR_SOCKET_PATH is never set. There's no daemon and no socket here, so a plugin that talks raw JSON-RPC over it directly (rather than through HERDR_BIN_PATH), such as parts of herdr-plus, is unsupported. herdr-browser is unsupported for another reason: it draws in a pane with graphics, which tmux does not show. See docs/COMPAT.md for the full environment contract and a compatibility read on specific known plugins.