Skip to Content
Numinance
Integrations

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.

View as .mdUpdated
Available in public spec

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.

The plugin describes. The host authorises and enforces. A manifest is a statement of intent that is compared against grants and descriptors; it is never permission.

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:

  1. Floors from the host's descriptor copy. A capability's risk_floor, side_effect, idempotency and dry_run are 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.
  2. Enumerated intents. Credential, network, filesystem and environment requests are named in advance. A request outside the declared intents is refused at run time.
  3. Comparison against the lockfile. When a previous version is pinned, the host recomputes the permission change itself. Any widening needs approval.

Manifest fields

proto/numinance/plugin/v1/manifest.proto
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_]*$.

FieldMeaningHost check
risk_floorWorst-case risk classAt least action.risk of the host copy; never lowered against the lock
side_effectNONE, READ, WRITE, DELETE or DEPLOYFloored by risk: a risk above READ means at least WRITE
idempotencyNONE, KEYED or NATURALIf the RPC is not idempotent in the host copy, only NONE is permitted
dry_runA dry run existsTrue only when the RPC sets supports_dry_run
compensationCapability that compensates this oneMust have an entry in this manifest and match compensating_action
credential_intentsIntent names, ^[a-z][a-z0-9._-]{0,127}$Resolved only against the broker catalog; a plugin cannot mint one
network_intentsEgress destinations (host, port)See below
filesystem_intentsSandbox paths and modeSee below
environment_scopeEnvironment names or tagsNon-empty, never "all"; narrows the grant
evidence_declaredEvidence record types producedMust include every entry of action.evidence; required above READ
timeout, resource_budgetRequested limitsEffective value is the minimum with the grant budget, under the policy ceiling
conformance_suiteconformance/<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_descriptionHuman-readable descriptionUntrusted, 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:

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

  • digest covers the package content with manifest.yaml excluded, 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_identity must match the verified signature exactly on both issuer and subject. It is a comparison, not a pin.
  • sbom_ref and provenance_ref are 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_effect or dry_run lowered
  • idempotency raised toward NATURAL
  • compensation removed
  • any credential, network, filesystem or environment-scope entry added, or a filesystem mode changed to read-write
  • any evidence_declared entry removed
  • timeout or any resource_budget field 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

FailureResult
Manifest returned at run time differs from the installed oneThe host refuses to start the plugin
A capability name not in the host descriptor copy, or a side-effecting RPC with no entryRejected at install
risk_floor or side_effect below the port's floorRejected
Network host is a metadata address, loopback or numeric spelling of oneRejected lexically; the proxy refuses again at connect time
Empty environment_scopeRejected at install, never read as "all"
Observed side effect above the declared oneThe call fails
Declared evidence not emittedThe 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

On this page