# Managing Herdr Plugins

> Installs, audits, forks, develops, links, updates, and removes Herdr plugins. Use whenever working with Herdr plugins, herdr-plugin.toml, the Herdr marketplace, local plugin forks, plugin PRs, or switching Herdr from an upstream plugin to a local checkout.

- Skill: `aspiers/managing-herdr-plugins` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add aspiers/managing-herdr-plugins`
- Raw SKILL.md: https://api.skillmd.com/api/skills/aspiers/managing-herdr-plugins/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: aspiers (https://skillmd.com/u/aspiers)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/aspiers/managing-herdr-plugins

---


# Managing Herdr Plugins

Manage Herdr plugins without running unreviewed code and keep Adam's local
forks, `mr` inventory, Stow-managed registry, and Org notes consistent.

## Non-negotiable rules

1. **Audit before execution.** Read
   [the security audit procedure](references/security-audit.md) completely and
   audit the exact source snapshot before running a build, package install,
   test, plugin action, `herdr plugin install`, or `herdr plugin link`.
2. Treat a plugin as arbitrary code running as the user. Herdr does not sandbox
   plugins, and the marketplace is an automatic, unreviewed GitHub index.
3. An audit reduces risk; it cannot prove that code is non-malicious. Do not
   install when the audit is incomplete, a binary is unverifiable, dependencies
   are unpinned, or a critical finding remains.
4. Present the audit report, exact commit SHA, and residual risks, then obtain
   the user's explicit approval before first execution or installation.
5. Never edit `~/.config/herdr/plugins.json` manually. Herdr rewrites it, often
   replacing its Stow symlink. After every install, reinstall, link, unlink,
   enable, disable, or uninstall, run:

   ```bash
   stow --adopt -d ~/.STOW -t ~ --no-folding herdr-config
   ```

6. Use GNU Stow, never `ln`, for Herdr configuration links.
7. A fork used for local development belongs under `~/.GIT/3rd-party`, must be
   registered in `~/.config/mr/groups.d/26-AI`, and must be documented in
   `~/org/notes/herdr.org`.
8. Before editing another repository (`~/.config/mr`, `~/org`, or a plugin),
   read that repository's agent instructions and inspect its Git status. Do not
   overwrite unrelated changes.
9. **Never stage, commit, or rewrite history in `~/org`.** Edit the required Org
   files in the working tree only, then leave them unstaged for the repository's
   auto-commit and auto-sync. Do not run `git add`, `git commit`, `git commit
   --amend`, rebase, reset, or force-push in `~/org`. If an existing unmerged
   path cannot be cleared without an index update, stop and obtain explicit user
   permission before a single file-scoped `git add` that marks only the resolved
   conflict; leave the merge commit to auto-commit.

## Decide which workflow applies

- **Evaluate or install upstream:** audit a detached inspection checkout, then
  install the reviewed SHA with Herdr.
- **Develop, patch, or contribute:** fork upstream, manage the checkout with
  `mr`, audit it, build it, and use `herdr plugin link` so Herdr executes the
  local working tree.
- **Refresh an existing plugin:** audit all commits and dependency changes since
  the previously approved SHA before reinstalling or rebuilding.

## Installing a reviewed upstream plugin

`plugin install` accepts GitHub shorthand only: `owner/repo[/subdir...]`.

1. Clone without running repository code and record the immutable commit:

   ```bash
   audit_dir=$(mktemp -d)
   git -c core.hooksPath=/dev/null clone --no-recurse-submodules \
     https://github.com/OWNER/REPO.git "$audit_dir/REPO"
   git -C "$audit_dir/REPO" checkout --detach REF
   reviewed_sha=$(git -C "$audit_dir/REPO" rev-parse HEAD)
   ```

2. Apply the complete security audit to the whole checkout and the plugin
   subdirectory. A subdirectory plugin can still be affected by repository-root
   build files, workspaces, dependencies, CI, and shared code, so do not audit
   only the subdirectory.
3. Ask for approval using the audit report and `reviewed_sha`.
4. Install the exact reviewed revision. Prefer the interactive trust preview;
   use `--yes` only for an already reviewed noninteractive installation:

   ```bash
   source=OWNER/REPO
   # For a monorepo plugin instead use: source=OWNER/REPO/SUBDIR
   herdr plugin install "$source" --ref "$reviewed_sha"
   ```

5. Adopt the generated registry, then verify the registration:

   ```bash
   stow --adopt -d ~/.STOW -t ~ --no-folding herdr-config
   herdr plugin list --plugin PLUGIN_ID --json | jq .
   herdr plugin action list --plugin PLUGIN_ID
   ```

There is no `plugin update` in plugin v1. To update a GitHub-managed plugin,
audit the new revision and reinstall it with a new exact `--ref`.

## Creating and tracking a local fork

Use repository name `REPO` as the `mr` entry name unless local conventions
require otherwise.

1. Create Adam's GitHub fork without cloning into an unmanaged location:

   ```bash
   gh repo fork OWNER/REPO --clone=false
   ```

2. Add this stanza to `~/.config/mr/groups.d/26-AI`, following the surrounding
   ordering and formatting:

   ```ini
   [$HOME/.GIT/3rd-party/REPO]
   checkout = github_clone
   remotes = auto_remotes
   lib =
       set_git_origin_user OWNER
   ```

   Add `set_git_origin_name REPO` only when the checkout directory name and
   upstream repository name differ. Do not add automatic build or link fixups:
   future updates must be audited before they execute.

3. Check out and verify the managed repository:

   ```bash
   mrco REPO
   git -C ~/.GIT/3rd-party/REPO remote -v
   git -C ~/.GIT/3rd-party/REPO config remote.pushDefault
   ```

   Local `mr` conventions normally retain upstream as `origin`, add Adam's fork
   as `github`, and add machine remotes. Verify rather than assuming names.
4. Audit the exact checkout before installing dependencies or building it.
5. Work on a topic branch, not the upstream default branch:

   ```bash
   git -C ~/.GIT/3rd-party/REPO switch -c TYPE/TOPIC
   ```

## Making Herdr use the local fork

Set `plugin_root` to the checkout directory containing `herdr-plugin.toml`; for
a monorepo it may be `~/.GIT/3rd-party/REPO/SUBDIR`.

1. Determine the plugin id from `herdr-plugin.toml` and inspect any current
   registration:

   ```bash
   herdr plugin list --plugin PLUGIN_ID --json | jq .
   ```

2. If the same id is GitHub-managed, uninstall it. If it is already local,
   unlink it. These commands unregister the plugin; `uninstall` additionally
   removes Herdr's managed GitHub checkout, while `unlink` leaves local files:

   ```bash
   herdr plugin uninstall PLUGIN_ID   # GitHub-managed source
   # or
   herdr plugin unlink PLUGIN_ID      # local source
   stow --adopt -d ~/.STOW -t ~ --no-folding herdr-config
   ```

3. Build the audited checkout using the repository's documented locked and
   reproducible process. `plugin link` does **not** run manifest build commands.
4. Link the working tree and adopt the registry:

   ```bash
   plugin_root=$(realpath ~/.GIT/3rd-party/REPO)
   # For a monorepo plugin, append /SUBDIR in the realpath command.
   herdr plugin link "$plugin_root"
   stow --adopt -d ~/.STOW -t ~ --no-folding herdr-config
   ```

5. Prove that Herdr points to the fork rather than a managed upstream clone:

   ```bash
   herdr plugin list --plugin PLUGIN_ID --json |
     jq -e --arg root "$plugin_root" \
       '.result.plugins | length == 1 and
        .[0].source.kind == "local" and .[0].plugin_root == $root'
   ```

Do not copy fork source into this configuration repository and do not create a
second manifest here. The registry's absolute local path is the source of truth;
`mr` ensures the checkout occupies the same path on managed machines.

## Local development loop

- Source/script changes are read from the linked working tree on the next
  invocation. Event hooks may execute them without a manual action.
- Disable the plugin before pulling, rebasing, switching to, or introducing
  unreviewed executable code. Adopt the registry. Audit and rebuild the new
  snapshot before relinking/enabling it, then adopt the registry again.
- Rebuild compiled plugins after source changes.
- Rerun `herdr plugin link "$plugin_root"` after changing
  `herdr-plugin.toml`, because actions, events, panes, and link handlers are
  registered from the manifest. Adopt `plugins.json` afterward.
- Startup hooks do not run merely because a plugin is linked or enabled. Test
  them with a deliberate Herdr server restart/handoff after approval.
- Exercise narrow entrypoints and inspect logs:

  ```bash
  herdr plugin action list --plugin PLUGIN_ID
  herdr plugin action invoke PLUGIN_ID.ACTION
  herdr plugin pane open --plugin PLUGIN_ID --entrypoint PANE_ID
  herdr plugin log list --plugin PLUGIN_ID --limit 50
  ```

- Run repository tests and linters only after their commands and dependencies
  have been audited.
- Before each rebuild after pulling/rebasing, review the incoming diff,
  dependency/lockfile changes, generated files, and resulting tree. Repeat the
  full audit when trust boundaries or executable paths changed.

## Contributing changes upstream

1. Keep one focused topic branch and include tests/documentation expected by
   upstream.
2. Review `git diff origin/DEFAULT...HEAD` for secrets, unrelated changes, new
   executable behavior, and dependency changes.
3. Commit and push to the verified writable fork remote (normally `github`).
4. Create a PR targeting `OWNER/REPO`; include what was tested and any security
   implications. Obtain user approval before publishing the PR.
5. Keep Herdr linked to `~/.GIT/3rd-party/REPO[/SUBDIR]` while the PR is open.
   Do not reinstall upstream merely because a PR exists.
6. After merge, fetch/rebase the fork, audit the merged revision, rebuild, and
   relink. To return to Herdr-managed upstream later, unlink the local plugin
   and install an audited exact upstream SHA.

## Required Org documentation

Keep `~/org/notes/herdr.org`'s final two top-level sections named
`* Useful keybindings` and `* Installed plugins`; do not append a new top-level
section after them.

- Under `* Useful keybindings`, update the appropriate table whenever the
  plugin adds or changes a binding. Ensure the documented key, config entry,
  qualified action id, and actual behavior agree.
- Put only installed or linked plugins under `* Installed plugins`.
- Put evaluated but rejected plugins under a separate `* Rejected plugins`
  section before the final `* Useful keybindings` and `* Installed plugins`
  sections. Record why installation was rejected.
- Each plugin subsection should contain upstream and fork links, plugin id,
  purpose, local checkout/subdirectory, currently reviewed SHA, audit
  date/verdict and residual risks, build command, `herdr plugin link` command,
  useful actions, and PR/issue links as applicable.
- If no keybinding exists, say so in the appropriate plugin subsection rather
  than inventing one.
- Leave Org documentation changes unstaged and uncommitted. The `~/org`
  auto-commit and auto-sync must create and synchronize the commit; never run
  staging, commit, or history-rewriting commands there.

## Registry and final verification

After any plugin registry mutation:

```bash
stow --adopt -d ~/.STOW -t ~ --no-folding herdr-config
readlink ~/.config/herdr/plugins.json
herdr plugin list --plugin PLUGIN_ID --json | jq .
git -C ~/.GIT/adamspiers.org/herdr-config diff -- .config/herdr/plugins.json
git -C ~/.config/mr diff -- groups.d/26-AI
git -C ~/org diff -- notes/herdr.org
```

Confirm no unrelated registry entries changed, the linked root is under
`~/.GIT/3rd-party`, the plugin remains enabled only when intended, and all
three repositories contain only expected changes.

## Herdr facts and references

- Remote installs run manifest `[[build]]` commands; local links do not.
- Commands run as argv arrays unless the manifest explicitly invokes a shell.
- Runtime commands receive the plugin root, config/state directories, context,
  socket, and Herdr binary paths. They can call the full Herdr CLI.
- User-editable configuration belongs in `HERDR_PLUGIN_CONFIG_DIR`; durable
  state belongs in `HERDR_PLUGIN_STATE_DIR`, not the managed source checkout.
- Official documentation:
  [Plugins](https://herdr.dev/docs/plugins/),
  [CLI reference](https://herdr.dev/docs/cli-reference/), and
  [Marketplace](https://herdr.dev/docs/marketplace/).

