Skip to main content
A plugin is a PluginManifest. This page is a distilled reference to the manifest surface — enough to author from. For the full field-by-field catalog with every validation rule, read the SDK’s docs/manifest-reference.md in the codebase. For a guided build, see Build a plugin.

PluginManifest

The top-level object returned by build_manifest(ctx): Construction-time invariants (a violation fails the build): tool, capability, and resource names are unique; every ToolSpec.capability resolves to a capability on the same manifest; write-class tools live under an approval_required capability and declare idempotent explicitly.

Identity

PluginIdentityname (slug matching ^[a-z][a-z0-9_-]*$, equal to the entry-point name), version, display_name, description, owner, optional homepage.

Auth

PluginAuth.type is one of the AuthType shapes — describing the shape of credentials, never values: Credentials are resolved at runtime through the SecretsProvider on PluginContext; the manifest only declares what’s required. Prefer the canonical auth_shape over the legacy auth.type for new plugins — onboarding, health sweepers, and connection setup all read it.

Capabilities

CapabilityMetadata is the routing surface. A capability groups tools and tells the router when to pick them:
Write routing_hints as plain sentences, not keyword bags — the ranker is BM25 over that prose, and it doubles as model-facing fallback guidance. Give every user-facing capability routing_examples.

Role floor

minimum_role (None by default) is a hard floor. None lets any actor on the tenant-reach ladder invoke; TENANT_ADMIN restricts to tenant/super admins (use for tenant-shared credentials, financial finalization, bulk/admin operations, irreversible deletes); SUPER_ADMIN restricts to the platform operator. Tenants can tighten further but cannot loosen below the floor.

Tools

ToolSpec binds a callable to the manifest: READ tools are idempotent by definition. WRITE-class tools must declare idempotent explicitly — False for create-* tools that mint a new resource each call, True for update/delete/set-state tools whose post-condition depends only on the input.

Connections and profiles

  • connection_shapes declares who owns a connection record: user-owned, tenant-owned, either, a layered user-plus-tenant prerequisite, or none.
  • profiles declares deployment variants (commercial/gov cloud, production/sandbox). Hosts project one setup target per profile; config_keys are safe to surface as hints and never carry secret values.

Query-profile and pushdown contract

Every read-capable plugin (one or more READ tools) must declare a query profile — enforced fleet-wide by the check_query_profile gate. Satisfy it one of three ways, in order of preference:
1

Pushdown

For providers with a native query language, declare a DatasetPushdown so the host pushes a plan prefix (filter / project / sort / limit and declared aggregates) down to the source instead of fetching everything and computing host-side.
2

Bounded fetch

Expose a dataset the host can resolve to completeness — an explicit datasets entry, or a READ tool returning a single list of flat scalar-field rows, which the SDK auto-adapts into a queryable dataset.
3

Recorded opt-out

When the read surface is genuinely non-tabular (relevance search, ops snapshots), record a rationale in [tool.aperium.query_surface]. An empty rationale or a stale key fails the gate.
DatasetSpec validates the pairing at build time: a dynamic dataset (no fixed schema) declaring pushdown must supply a schema_probe; a fixed-schema dataset must not. An ordinary refusal degrades to fetch-then-compute; a PlanPrefixRetryError preserves terminal model remediation without that fallback.

MCP exposure

Most first-party plugins are direct-call and leave mcp unset. Two opt-in surfaces exist:
  • mcp (McpConfig) — expose this plugin’s tools as an MCP server (STDIO, SSE, or HTTP; port required for HTTP/SSE). Opt in only for MCP-adapter examples or plugins deliberately exposed to non-Aperium MCP clients.
  • remote_mcp (RemoteMcpToolsetSpec) — the inverse: the plugin’s tools come from a remote MCP server, introspected at runtime. The host provisions a per-tenant managed server row from a credential-rendered URL template.

JSON wire shape

PluginManifest.model_dump_json() emits a metadata view for external tooling: identity, auth type, and capabilities dump in full; input/output/config schemas emit as JSON Schema; handler, resource, and health-check callables are excluded — rehydrating executable code from JSON is intentionally unsupported.