Manifest and capabilities
What a plugin declares before it runs, side effects, credential, network and filesystem intents, digest, provenance and permission changes, and how the host treats each declaration.
The manifest schema (manifest.proto) and the annotations it is compared against are in the public tree. Install-time verification of signatures, SBOMs, provenance and the lockfile is performed by the proprietary runtime's governed install, which is designed and not generally available.
When to use this
You write or review a manifest when you build a capability provider, when you bump its version, or when you decide whether to approve an upgrade. The manifest is the unit a human reviews: it says what the provider is, which ports it implements, and for each capability exactly what it may touch.
Mechanism
A manifest travels two ways. It is a manifest.yaml in the installed package, and the running provider returns the same message from PluginService.GetManifest. The host requires the two to be equal (proto.Equal) or it refuses to start the plugin, so the running process cannot widen what was reviewed at install.
Three kinds of check apply to every declaration:
- Floors from the host's descriptor copy. A capability's
risk_floor,side_effect,idempotencyanddry_runare bounded by the annotations on the matching RPC in the host's own copy of the port file. A provider can claim more caution than the port requires, never less. - Enumerated intents. Credential, network, filesystem and environment requests are named in advance. A request outside the declared intents is refused at run time.
- Comparison against the lockfile. When a previous version is pinned, the host recomputes the permission change itself. Any widening needs approval.
Manifest fields
message Manifest {
string plugin_id = 1;
string version = 2;
numinance.types.v1.Digest digest = 3;
string signer_identity = 4;
ExtensionClass kind = 5;
repeated string ports = 6;
repeated CapabilityDescriptor capabilities = 7;
numinance.types.v1.Reference sbom_ref = 8;
numinance.types.v1.Reference provenance_ref = 9;
PermissionsDelta permissions_delta = 10;
google.protobuf.Timestamp deprecated_after = 11;
}Prop
Type
The extension class is a ceiling on authority: a skill carries no authority, a playbook shapes grants and never widens them, and a control pack can only restrict. A manifest of those classes with any ports or capabilities is rejected.
Capability descriptors
Each CapabilityDescriptor is one verb. Its name has the form <port>.<snake_case_method> (for example knowledge.search) and must match ^[a-z][a-z0-9]*\.[a-z][a-z0-9_]*$.
| Field | Meaning | Host check |
|---|---|---|
risk_floor | Worst-case risk class | At least action.risk of the host copy; never lowered against the lock |
side_effect | NONE, READ, WRITE, DELETE or DEPLOY | Floored by risk: a risk above READ means at least WRITE |
idempotency | NONE, KEYED or NATURAL | If the RPC is not idempotent in the host copy, only NONE is permitted |
dry_run | A dry run exists | True only when the RPC sets supports_dry_run |
compensation | Capability that compensates this one | Must have an entry in this manifest and match compensating_action |
credential_intents | Intent names, ^[a-z][a-z0-9._-]{0,127}$ | Resolved only against the broker catalog; a plugin cannot mint one |
network_intents | Egress destinations (host, port) | See below |
filesystem_intents | Sandbox paths and mode | See below |
environment_scope | Environment names or tags | Non-empty, never "all"; narrows the grant |
evidence_declared | Evidence record types produced | Must include every entry of action.evidence; required above READ |
timeout, resource_budget | Requested limits | Effective value is the minimum with the grant budget, under the policy ceiling |
conformance_suite | conformance/<port>/<major>/<suite> | Looked up in the host's kit index, never as a path; the host runs it and never trusts the claim |
llm_description | Human-readable description | Untrusted, at most 2048 bytes, rendered delimited and labelled, never as instructions |
Declared side effects
side_effect is the worst effect the capability can have. During a call the provider also reports ObservedSideEffect entries on the terminal message. One that exceeds the declared side_effect fails the call. When dry_run is set on the ActionContext, any reported effect above READ fails the call and is recorded.
Credential intents
A credential intent names a kind of access, for example the GitHub provider's scm.github.api. The provider asks HostService.RequestCredential for a handle for an intent in its capability's credential_intents that the grant allows. v1 is handle-only: the broker never returns credential material, and the manifest carries none (no field can).
Network intents
A NetworkIntent is a host and a port (1 to 65535). The host must be an exact lowercase DNS name or a canonical IP literal, with no scheme, port, path or wildcard, ASCII only. The lexical rules reject loopback, link-local, unspecified, multicast, the IANA special-purpose ranges and cloud metadata addresses in any textual form, including numeric spellings such as 2852039166. The check is necessary, not sufficient: the egress proxy resolves the name at request time, refuses those ranges regardless of policy, and connects to the address it checked without resolving again. Private ranges are reachable only when signed customer policy allows the destination.
For example, the GitHub source-control provider declares one destination, api.github.com on port 443, and the replaying build of the same provider declares none.
Filesystem intents
A FilesystemIntent is an absolute path inside the sandbox root with an optional mode, FILESYSTEM_MODE_READ_ONLY or FILESYSTEM_MODE_READ_WRITE. An absent mode means read-only. Paths are NFC, printable, free of .., . and empty segments, and the host rejects any path that resolves outside the sandbox root or into a protected mount. Rejected, never repaired. The two official verifiers declare no filesystem intent at all.
A manifest in code
The public tree has no standalone manifest.yaml example. The providers build their manifests in Go. This is the sample knowledge provider's, copied from plugins/examples/sample-knowledge/provider/server.go:
capability := func(verb string) *pluginv1.CapabilityDescriptor {
return &pluginv1.CapabilityDescriptor{
Name: "knowledge." + verb, RiskFloor: annotationsv1.RiskClass_RISK_CLASS_READ, SideEffect: pluginv1.SideEffect_SIDE_EFFECT_READ,
Idempotency: pluginv1.Idempotency_IDEMPOTENCY_NATURAL, EnvironmentScope: []string{"dev", "staging"},
ConformanceSuite: "conformance/knowledge/v1/basic", LlmDescription: "Reads documents of a small in-memory sample source.",
Timeout: durationpb.New(10_000_000_000),
}
}A read-only capability needs no declared evidence, so EvidenceDeclared is empty. A capability above READ without it is rejected. The surrounding Manifest sets PluginId to dev.numinance.sample-knowledge, Kind to EXTENSION_CLASS_CAPABILITY_PROVIDER, Ports to numinance.ports.knowledge.v1, and a real Digest computed from the running executable. Its SbomRef and ProvenanceRef are placeholders derived from a string, which the sample's README says governed install would refuse.
Digest, signer and provenance
digestcovers the package content withmanifest.yamlexcluded, because that file carries it. The signature and provenance verified at install cover the whole artifact, so the manifest itself is signed. The lockfile pins the digest the host recomputed.signer_identitymust match the verified signature exactly on both issuer and subject. It is a comparison, not a pin.sbom_refandprovenance_refare required for a capability provider; a mismatch fails install.
What verifies these is the runtime's governed install. See Registry and trust.
Permissions delta and widening
permissions_delta lists capability changes against previous_version. Each CapabilityChange has a name and a previous and current descriptor (absent previous means added, absent current means removed). When the lockfile has an entry for the plugin, previous_version must equal the locked version and the host recomputes the delta from the locked manifest. A mismatch fails install.
Against the locked descriptor, each of the following is a widening and needs approval:
- a capability added
risk_floor,side_effectordry_runloweredidempotencyraised towardNATURALcompensationremoved- any credential, network, filesystem or environment-scope entry added, or a filesystem mode changed to read-write
- any
evidence_declaredentry removed timeoutor anyresource_budgetfield raised, compared as effective values (a change from non-zero to zero is a raise)- a kind changed, a port major changed, or a different signer
- a version lower than the locked one (a rollback)
Everything else is a narrowing. With no lock entry, the whole manifest is a widening. A version equal to the locked version with a different recomputed digest is rejected. This is the rule that makes "an upgrade that quietly asks for more" a reviewed event, not a silent one.
Failure modes and safeguards
| Failure | Result |
|---|---|
| Manifest returned at run time differs from the installed one | The host refuses to start the plugin |
| A capability name not in the host descriptor copy, or a side-effecting RPC with no entry | Rejected at install |
risk_floor or side_effect below the port's floor | Rejected |
| Network host is a metadata address, loopback or numeric spelling of one | Rejected lexically; the proxy refuses again at connect time |
Empty environment_scope | Rejected at install, never read as "all" |
| Observed side effect above the declared one | The call fails |
| Declared evidence not emitted | The host derives PARTIAL |
Rejections name an index-based field path such as capabilities[3].network_intents[0].host and the violated bound, never the offending value.
Next steps
Plugin lifecycle
The full life of a provider process, from the host launching it to shutdown, with the exact RPCs, bounds and failure behavior of plugin/v1.
Write a plugin in Go
Build a capability provider with the Go plugin SDK, using the sample knowledge provider as a line-by-line reference, and prove it against the conformance kit.