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

  1. Public repo containing at least one herdr-plugin.toml.
  2. GitHub topic herdr-plugin on the repo (Settings > Topics, or gh repo edit --add-topic herdr-plugin).
  3. 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> with exec, never a relative path (relative resolution breaks on some platforms).
  • Document required tools in the README: cargo (and bun/node if any script entries use them).
  • Keep [[build]] minimal: one compile step. If you want prebuilt-binary fast installs, look at file-viewer’s fetch-or-build.sh pattern (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 version in herdr-plugin.toml per release. Semver; the field is display plus (for plugins that fetch their own binaries) release-URL material.
  • Keep a CHANGELOG.md per 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 an update action 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"