What a plugin can do

Lifecycle events, and advisory versus enforcing.

Written By Dustin

Last updated 29 minutes ago

A plugin is a WASM module bound to a lifecycle event and run in a capability-bounded sandbox. It replaces the outcome of a Git hook, not its implementation model — a Git hook is an arbitrary shell script running with your whole machine's authority, and a TOVIO plugin is a sandboxed guest that gets only what a manifest requested and a binding granted.

The events you will actually bind to

EventWhen it fires
pre-snapshotBefore the working copy is snapshotted into the active change. TOVIO has no staging area, so this is the architectural equivalent of pre-commit.
pre-landBefore a change lands onto a target lane or ref.
resolve-requestedOnly when plugin-assisted conflict resolution is explicitly asked for. tovio resolve --ai reaches this seam only when no ai.provider is configured; with a provider set, the built-in LLM resolver runs instead and a bound resolver plugin never fires.
proposal-createdWhen a Forge proposal is created. Metadata-safe input by default.

Those four are the MVP set, and most plugins never need another. The full vocabulary is twenty-four names, a closed set:

pre-snapshot, post-snapshot, pre-sync, post-sync, pre-land, post-land, conflict-created, resolve-requested, proposal-created, review-submitted, policy-changed, access-granted, access-revoked, lock-acquired, lock-released, agent-session-started, agent-scope-exceeded, release-created, archive-created, bundle-created, bundle-applied, git-imported, git-exported, transcript-parse.

Being bindable is not the same as being fired. An event is dispatched only where the subsystem that owns the operation has a firing site, and the four release and bundle events have no backing subsystem yet — no command, object kind, or transport format — so nothing dispatches them. Binding one early is legal and deliberate: the manifest can be authored, reviewed, and pinned ahead of the subsystem.

Two names people expect and will not find

  • There is no resolver event. resolver is a plugin type (alongside check, transform, policy-adapter, and notifier); the event a resolver binds to is resolve-requested.
  • There is no secret-scan event. com.tovio.secret-scan is a plugin id, and it is bound to pre-snapshot by default in every repo.

An event name that is not one of the twenty-four is refused at bind and at run with TVO-PLUGIN-004, rather than quietly accepted and never called.

Advisory, enforcing, required

--mode chooses whether a plugin can gate. --required is a separate flag that widens what gates.

BindingResultOutcome
advisoryanythingReported. Never blocks.
enforcingpass / warningProceeds. An enforcing warning surfaces but does not gate.
enforcingfailBlocks — whether or not the binding is required.
enforcingerrorBlocks if the binding is required, or if the operation touches protected content. Otherwise proceeds.
enforcingskipped / unsupportedBlocks if the binding is required. Otherwise proceeds.

The direction of that table is deliberate: ambiguity resolves to block. A plugin that could not produce a verdict has not passed, and a required gate that cannot run is not a gate that quietly lets the operation through.

Start advisory. Move to enforcing once you have watched it run against real content.

Deny by default

The sandbox provides no network, no filesystem, and no environment access unless the binding grants it. A plugin importing a host function it was not granted fails closed — TVO-PLUGIN-006 — rather than silently succeeding.

Protected plaintext is denied at execution preflight (TVO-PLUGIN-011) unless explicitly granted, and network likewise (TVO-PLUGIN-012). Key material is never provided to a plugin under any grant.

Running needs a feature build

Executing plugins requires the plugins-wasm build feature. Without it, plugin run and plugin test print a clean built without plugin execution message rather than pretending. The management surface — install, list, show, validate, verify, bind, bindings, doctor — works in every build.

As policy gates

tovio policy hook add <event> <plugin_id> --required

A policy hook is an enforcing binding authored through the policy surface, so it reads as a gate rather than as one person's local preference.