Publish a plugin¶
Goal. Ship a binoc plugin so users can
pip install your-package and have the binoc CLI discover it
automatically.
Prerequisites. A working plugin (see Write a Python comparator or Write a Rust comparator).
Naming¶
Use the shared ecosystem namespace on PyPI:
- PyPI package name:
binoc-<your-name>(analogous topytest-*,llm-*). - Plugin names inside your package:
<your-name>.<plugin-name>(for examplebiobinoc.fasta). Never use the reservedbinoc.*prefix; that's for the standard library.
See Plugin discovery for the full convention table (plugin names, tags, item types, actions).
The entry point¶
Every binoc plugin registers under the binoc.plugins entry point
group in pyproject.toml.
Python plugin¶
[project]
name = "biobinoc"
version = "0.1.0"
dependencies = ["binoc>=0.1"]
[project.entry-points."binoc.plugins"]
biobinoc = "biobinoc:register"
# biobinoc/__init__.py
def register(registry):
from biobinoc.fasta import FastaComparator
from biobinoc.normalizer import SequenceNormalizer
registry.register_comparator("biobinoc.fasta", FastaComparator())
registry.register_transformer("biobinoc.sequence_normalizer", SequenceNormalizer())
Rust (native) plugin¶
[project]
name = "biobinoc"
version = "0.1.0"
dependencies = ["binoc>=0.1"]
[project.entry-points."binoc.plugins"]
biobinoc = "biobinoc"
[build-system]
requires = ["maturin>=1.7,<2.0"]
build-backend = "maturin"
[tool.maturin]
features = ["python"]
Note the entry point value is just the module name, no
module:function. The discovery code detects that it's a native
module and loads it via the C ABI. The registration happens inside
the export_plugin! macro you already wrote.
Versioning¶
Each published binoc package versions independently; your plugin should too.
Python plugins. binoc is a real Python API dependency.
- Lower bound
binoc>=X.Yfor the Python APIs you use. - No upper bound unless you know of a specific incompatibility.
Rust plugins. The Rust compatibility boundary is binoc-sdk,
not the binoc host.
- Tight dependency on
binoc-sdkinCargo.toml— depend on the minor line you built against. Native plugin compatibility is checked at runtime via the plugin'ssdk_version. - Loose dependency on
binocinpyproject.toml— depend with a lower bound for the loader features you need. Do not capbinocjust to mirror the SDK minor.
See Release surface and automated publishing ADR for why.
Build and publish¶
Python-only plugin¶
Rust (maturin) plugin¶
uv run --extra dev maturin develop # local install for testing
uv run --extra dev maturin build --release
uv publish dist/*.whl
For production, set up trusted publishing from a GitHub Actions workflow (OIDC, no PyPI token to manage). The binoc project's own release setup is documented in Cut a release; mirror it for your plugin.
Test before publishing¶
From the consumer's perspective:
If the plugin shows up in the output (or its comparator claims the right files), entry-point discovery is working.
For a reproducible test, see Test a plugin with vectors — the same harness the stdlib uses.
Publish alongside the binoc project¶
The in-tree reference plugins (model-plugins/binoc-sqlite,
model-plugins/binoc-row-reorder, model-plugins/binoc-html) are
published independently of the host binoc package; your plugin
should be too. Independent releases mean a bugfix to your plugin
doesn't require a new binoc host release, and vice versa.
Where to go next¶
- Plugin discovery reference — exhaustive entry-point spec.
- Install and use plugins — the consumer-facing side of what you just shipped.
- Cut a release — the binoc project's own release workflow, adaptable for plugin packages.