Skip to content

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_plaintext is 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 is required = 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