Concepts¶
The plugin system has three layers, four modes, and a closed set of lifecycle events. Once you know those, the rest of the model — capabilities, bindings, audit — is just detail.
The three layers¶
Plugin definition = manifest, package, runtime, permissions, schemas, integrity metadata
Plugin binding = local/repo/org/Forge rule attaching a plugin to a lifecycle event + mode
Plugin execution = sandboxed invocation with structured input/output and bounded capabilities
- Definition is what the plugin is: a packaged artifact plus a manifest that declares its identity, runtime, supported events, requested capabilities, input/output schema versions, and integrity metadata.
- Binding is what makes the plugin run. A plugin never runs automatically until something (a developer, a repo config, a policy) attaches it to an event with a mode and a scope.
- Execution is a single sandboxed invocation. TOVIO marshals structured input across the sandbox boundary, waits with a timeout, validates the structured output, and either allows, warns, blocks, or applies a proposal.
The three layers are separated so that tovio-core stays pure — it defines contracts, schemas,
and result-handling logic, but it never installs, loads, or executes plugins. Execution belongs to
runtime hosts: the CLI dispatches to the tovio-plugin-host edge crate (a Wasmer/Cranelift WASI
sandbox), and tovio-forge reuses that same sandbox and the same contracts server-side when it is
built with the native runner. A default Forge build ships the attestation gate but no executor.
flowchart LR
D["Definition<br/>(manifest + artifact<br/>+ integrity)"] --> B["Binding<br/>(event + mode + scope<br/>+ filters)"] --> E["Execution<br/>(sandboxed I/O<br/>+ capabilities)"]
E --> R["PluginResult<br/>(pass / warn / fail /<br/>error / skipped / unsupported)"]
R --> A["Audit entry<br/>(enforcing runs)"]
More diagrams: Workflows.
The four modes¶
| Mode | What it can do | Can block? |
|---|---|---|
| advisory | Emit warnings and findings. | No (default) |
| enforcing | Block the operation on fail; on error/skipped/unsupported if required. |
Yes |
| transform | Propose changes to the working copy or objects. | No, unless the binding grants transform-apply. |
| resolver | Propose a structured Resolution for a conflict. |
No; TOVIO applies accepted resolutions via the normal conflict path. |
Advisory and enforcing are the two binding modes; transform and resolver are plugin types
whose results are handled specifically. A check plugin is the default type.
The lifecycle events¶
A plugin binds to one of a closed set of named events. The most common ones:
| Event | When it runs |
|---|---|
pre-snapshot |
Before TOVIO snapshots the working copy into the active change. Replaces pre-commit. |
pre-land |
Before a change is landed onto a target lane/ref. |
resolve-requested |
When a user, agent, or configured operation asks for plugin-assisted conflict resolution. |
proposal-created |
When a Forge proposal is created. Metadata-safe input by default. |
Other events cover the rest of the day-to-day loop — post-snapshot, pre-sync/post-sync,
post-land, conflict-created, review-submitted, policy-changed, access-granted/revoked,
lock-acquired/released, agent-session-started, agent-scope-exceeded, release-created,
archive-created, bundle-created/applied, and git-imported/exported. No reserved names are
left — every one of those is a full event you can declare and bind today — but bindable is not the
same as fired: an event is only dispatched where its owning subsystem has a wired firing site, and
a binding for an unfired event simply never runs. Each event, and whether it fires today, is
documented in Lifecycle events; the enum is closed, so an unknown event name
is rejected with a typed error rather than silently accepted.
One event stands apart: transcript-parse is TOVIO's only request/response event. Every other event
is observe-or-block, but this one hands your plugin an AI agent transcript's raw bytes and uses the turns
it returns. It is also the only event whose grant is empty by rule — a manifest declaring it may request no
capability at all — because reading the transcript is TOVIO's job and only the parsing is sandboxed.
Why pre-snapshot, not pre-commit
TOVIO has no staging area. Your working copy auto-snapshots into the active change, so the
architectural event is pre-snapshot. A pre-commit alias may exist later for Git-muscle-memory
compatibility, but the canonical name is pre-snapshot.
The five plugin types¶
| Type | Purpose |
|---|---|
check |
Produce findings; pass/warn/fail/error/skipped/unsupported. |
transform |
Propose working-copy or object changes. |
resolver |
Propose a conflict Resolution. |
policy-adapter |
Bridge to an external policy engine. Enforcing use requires policy approval. |
notifier |
Emit structured notifications. Not a Forge webhook replacement. |
Deny-by-default, always¶
Every plugin runs with the deny-by-default capability set unless its manifest requests more and the binding grants it and the actor is authorized and (for agents) the agent's token allows it. The effective capability set is the intersection of all four.
Concretely, the default set is:
read_metadata = true
read_clear_paths = [] # no cleartext file contents
read_protected_metadata = false
read_protected_plaintext = false # never provided by default
write_working_copy = false
write_plugin_cache = false
network_access = false
emit_audit = false
invoke_tovio_command = false
propose_resolution = false
propose_transform = false
block_operation = false
See Capabilities & security for the full model.
What plugins never get¶
- Protected plaintext — denied by default. Even when a manifest requests it, the request must be
approved by the binding, the actor's read authorization, sandbox trust, and audit policy. There is
no shortcut through the binding surface either:
tovio plugin bind --grant read_protected_plaintextis refused outright rather than silently granted or silently dropped. In practice today, plugin input for protected paths is redacted metadata only. - Key material — never. There is no manifest field, no binding grant, no policy override.
- Ambient environment secrets — the sandbox runs with a minimal environment.
- Arbitrary filesystem access — the sandbox denies it. Plugins do not see
.tovio/internals. - Network — denied unless explicitly granted.
Fail-closed enforcement¶
For an enforcing binding on a protected operation:
pass→ allow.warning→ allow (warnings are surfaced but do not block).fail→ block.error,skipped,unsupported→ block if the binding isrequired = true.- Malformed output → treated as
error, therefore blocks required protected operations.
This is the fail-closed rule: an enforcing plugin that cannot produce a valid pass/warning must
not silently let a protected operation through.
Local, CI, and Forge parity¶
The same plugin, run with the same manifest and the same input, produces the same result whether it runs on a developer's laptop, in a CI job, or on a Forge runner. That is the point of the sandbox, the structured schemas, and the version pinning. Forge will only trust a local result as an enforced gate when a policy-approved attestation or server-side execution backs it.
Last reviewed September 9, 2026
Suggest an improvement to this page Not for security reports — see disclosure