The plugin manifest

Every field, the two integrity forms, and the mistakes that fail validation.

Written By Dustin

Last updated About 3 hours ago

Every package carries a manifest.toml. It is what tovio plugin validate reads, what the binding intersects against, and what a signature covers.

A complete manifest

id = "com.example.license-check"
name = "Example License Check"
version = "1.2.0"
publisher = "Example Corp"
publisher_identity = "did:key:<64 hex digits>"
api_version = "v1"
type = "check"
runtime = "wasm-wasi"
events = ["pre-land", "proposal-created"]
timeout_ms = 5000
[schemas]
input = "v1"
output = "v1"
[capabilities]
read_metadata = true
read_clear_paths = ["**"]
block_operation = true
emit_audit = true
[integrity.signed]
sha256 = "<64 hex digits>"
signature = "ed25519:<128 hex digits>"

The fields

FieldNotes
idStable and globally namespaced, in reverse-domain form. It is the key everything else refers to.
name, publisherHuman-facing labels.
versionSemantic-version ordering. Enforcing bindings should pin it.
publisher_identityAn Ed25519 key as did:key:. Required when a publisher signature is claimed; may be omitted only when none is.
api_versionThe plugin API generation.
typeOne of check, transform, resolver, policy-adapter, notifier. An unknown type fails validation.
runtimewasm-wasi. Native executable plugins are not part of the trust model.
eventsA flat top-level array of event names. A plugin never runs for an event it did not declare here.
timeout_msA flat top-level key, not a nested limits table.
[schemas]input and output schema versions.
[capabilities]Optional. Absent means the deny-by-default set. Present, it may list only what it changes.
integrityRequired, in one of two forms below.

The two integrity forms

A manifest must carry exactly one of them.

Signed — a table with the artifact's sha256 and an optional detached signature. The signature covers the canonical manifest without the signature, plus the artifact hash, under a domain separator; changing the manifest, the identity, or the artifact invalidates it.

Local development — the bare marker integrity = "local_dev". Because it is a bare top-level key, TOML requires it to appear before the first table header. Putting it after [schemas] is the most common authoring mistake in the whole file.

A local_dev package installs and runs locally under a visibly reported development policy. It is refused by remote HTTPS install and by hosted Forge registration, and it is never reported as publisher-verified.

What fails validation

  • A non-namespaced id, a non-semver version, or an unknown type.
  • An event name outside the closed vocabulary.
  • A self-contradictory capability request.
  • Neither integrity form present.
  • A manifest declaring transcript-parse that requests any capability at all. That event's whole security argument is an empty grant, so an over-reaching package is refused at validation, naming the offending capability, rather than silently narrowed later.
  • A file that is missing, unreadable, or not valid TOML — a parse fault, reported with a parse-specific cause.

All of these surface as TVO-PLUGIN-001.

Validate before you ship

tovio plugin validate <path>

It works in every build, writes nothing, and names the offending field. Run it in your own CI so a bad manifest is caught by you rather than by whoever tries to install it.

The binding file

Bindings live separately, in .tovio/plugins/bindings.toml, as an array of [[bindings]] entries. A binding refers to a plugin by plugin_id, must carry a non-empty scope, and expresses its version requirement as a tagged table — exact for a pin, or at_least for a floor — rather than a bare version string. A binding carries no source or hash of its own: artifact provenance belongs to the installed manifest.

You do not normally hand-write it. tovio plugin bind and tovio policy hook add author it for you.