Skip to main content
A plugin is a directory with a plugin.yaml in it. That is the whole packaging format — no build step, no wheel, no registry account.

Layout

plugin.yaml

plugin.yaml

Required fields

string
required
Always forge/plugin/v1. Any other value is refused with the version this build speaks.
string
required
The leaf name. The platform stamps your account on it at publish time, so the published id is <owner>/<name> — you do not write the owner yourself.
string
required
Starts with a letter or digit; letters, digits, ., _, - after that. Immutable once published.
string
required
One of algorithm, environment, data-prep, recipe, benchmark, playbook, prompt. Decides everything else about how the package is treated.

Required for executable kinds

module.path:callable
Required for algorithm and environment. The module path is relative to the package root. Must exist at publish time.Forbidden for every other kind. A data-prep plugin is discovered by the prepare_*.py convention; a declarative pack executes nothing, so it has no entry point at all.
eager | deferred
default:"eager"
When the launcher calls your entrypoint. See algorithm plugins.

Optional fields

PEP 440 specifier
Which starforge-core versions your plugin works with, for example ">=0.3,<1". Checked at launch; a mismatch stops the job with plugin x@1.2.0 requires SDK >=0.3,<1, this one is 0.2.9 rather than failing somewhere stranger later.
string
One line, shown in listings.
emoji
A single emoji for the shelf card. At most 8 bytes. Defaults to the kind’s icon.
string
Who wrote it. Distinct from owner, which is the platform account that published it.
string, url, string[]
Display and search only. homepage must be http(s). At most 12 keywords, lowercased and deduplicated.

README.md

A README.md at the package root becomes the long description on the detail page. Capped at 64 KB; anything beyond is truncated, because the detail page wants an introduction, not a manual. It is deliberately not a manifest field — long text in YAML forces the author to escape things and loses the Markdown toolchain. It is covered by the package digest, so changing it needs a new version.

The seven kinds

playbook and prompt are deployment-wide singletons: one is active and it changes what everyone sees on a diagnosis page. They are admin-only because the consequence lands on other people. There are no per-user versions — “whose diagnosis verdict is this” is a question that should not exist.

Publish

The client validates the manifest and the layout locally, computes the directory digest, and uploads. The server recomputes the digest and refuses a mismatch.

Install and reference

--exp writes plugins.lock.json into the experiment: the reference and its digest. At submission the platform reads that lockfile, injects exactly that version into the job package under forge_plugins/<name>/, and records the triple in the JobSpec.
plugins.lock.json
Two plugins whose packages would unpack into the same leaf directory name cannot be combined in one job. Rename one.

Confirm it worked

Shows the version you just published and its digest. After submitting a job that references it, the job log carries one line per loaded plugin:
If the digest was tampered with after injection, the job refuses to start instead:

Next

Algorithm plugins

What your entrypoint receives, and when it is called.

Recipe packs

A training method as a declaration.