Ship to the Marketplace
Distribution is git-native: a public GitHub repo tagged with the herdr-plugin topic gets indexed automatically (refresh runs about every 30 minutes). No registry account, no submission form. This page covers naming, repo layout, builds, and versioning.
Before you name anything: the collision check
Two plugins may share an id across different repos (the index tolerates it), but on one machine a same-id install replaces the previous plugin. So a colliding id actively destroys someone else’s install. Check the index before committing to a name:
curl -s https://assets.herdr.dev/plugins/index.json | jq -r '
.plugins[]?.manifests[]? // empty
' 2>/dev/null | head -5
The exact jq depends on the index shape; the robust approach is to pull the id list and grep your candidate:
curl -s https://assets.herdr.dev/plugins/index.json -o /tmp/index.json
jq -r '.. | objects | select(has("id")) | .id' /tmp/index.json | sort -u | grep -i "^peteretelej\." || echo "clear"
As of October 2026 the index holds about 1,437 repos and 1,481 plugins. All 29 duplicate ids in it are flat generic names (herdr-automatic-rename-style). Username-prefixed ids like peteretelej.tab-topic are the only style with zero collisions.
Also check display names: ids may collide safely across machines, but two plugins with the same human-visible name confuse the marketplace browser. Search the index for your name too.
Repo requirements
- Public repo containing at least one
herdr-plugin.toml. - GitHub topic
herdr-pluginon the repo (Settings > Topics, orgh repo edit --add-topic herdr-plugin). - That’s it. The indexer picks up the manifest at the repo root or in subdirectories.
Monorepo layout
One repo can ship many plugins; each needs its own manifest. The lab suite uses a cargo workspace:
herdr-plugins/
├── Cargo.toml # workspace members = ["plugins/*"]
├── LICENSE # MIT, applies to all plugins
├── README.md
└── plugins/
├── tab-topic/
│ ├── herdr-plugin.toml
│ ├── Cargo.toml
│ └── src/main.rs
└── notify/
├── herdr-plugin.toml
├── Cargo.toml
└── src/main.rs
# Cargo.toml (workspace root)
[workspace]
members = ["plugins/*"]
resolver = "2"
Users install one plugin at a time with the subdir shorthand:
herdr plugin install peteretelej/herdr-plugins/plugins/tab-topic
Zoetrope is a working precedent for the subdir-manifest pattern (herdr-plugin/herdr-plugin.toml inside a larger repo); the official cookbook (ogulcancelik/herdr-plugin-examples) is a multi-plugin monorepo too.
The [[build]] section for Rust
[[build]] runs only on herdr plugin install from GitHub, never on herdr plugin link (local dev builds itself). For a Rust plugin:
[[build]]
command = ["cargo", "build", "--release"]
[[events]]
on = "pane.agent_status_changed"
command = ["sh", "-c", "exec \"$HERDR_PLUGIN_ROOT/target/release/tab-topic\" run pane.agent_status_changed"]
Rules that keep installs working:
- Reference the binary via
$HERDR_PLUGIN_ROOT/target/release/<name>withexec, never a relative path (relative resolution breaks on some platforms). - Document required tools in the README:
cargo(andbun/nodeif any script entries use them). - Keep
[[build]]minimal: one compile step. If you want prebuilt-binary fast installs, look at file-viewer’sfetch-or-build.shpattern (download a SHA-256-verified release binary, fall back to cargo on any miss). - The install aborts if the manifest changes between the preview and the build. Land manifest edits as the whole change, not as drive-by tweaks.
Versioning and CHANGELOG
- Bump
versioninherdr-plugin.tomlper release. Semver; the field is display plus (for plugins that fetch their own binaries) release-URL material. - Keep a
CHANGELOG.mdper repo. qu8n’s and collie’s changelogs are the ecosystem’s best: one entry per version, behavior changes called out. - There is no
herdr plugin update. Updating means reinstalling:herdr plugin uninstall <id> && herdr plugin install <source>(config and state directories survive). Say so in your README, and consider anupdateaction that does the git pull + rebuild for link-mode users (collie ships one).
Gotcha: if you ever change what your manifest commands point at (binary name, script path), old installs that cached the action set (herdr < 0.8.0) keep invoking the old string. Treat manifest commands as a public API; see version-compat-doctrine.md.
min_herdr_version for release
Keep it at the oldest herdr that actually works, not your dev version. A requirement above the running herdr is a hard load failure; see version-compat-doctrine.md.
Launch checklist
# 1. ids and names are collision-free
curl -s https://assets.herdr.dev/plugins/index.json | grep -c '"peteretelej.tab-topic"'
# 0 = clear
# 2. install from your own repo like a stranger would
herdr plugin install peteretelej/herdr-plugins/plugins/tab-topic
# 3. actions and events fire
herdr plugin action list --plugin peteretelej.tab-topic
herdr plugin log list --plugin peteretelej.tab-topic
# 4. topic applied
gh repo edit peteretelej/herdr-plugins --add-topic herdr-plugin
# 5. indexed within ~30 min
curl -s https://assets.herdr.dev/plugins/index.json | grep -c "peteretelej"