Overview
PluginManifest is the structured metadata every plugin must declare. The runtime composes it into the Tier-1 prompt block, feeds it to the meta-tools, and validates it at boot.
Type
Fields
title
title
- Type:
string - Required: yes
[Climate Data] Fetch emissions…) and appears in the app.plugins.status() report. Distinct from name — name is kebab-case unique identifier, title is prose.summary
summary
- Type:
string - Required: yes
always plugins as - {name}: {summary}. Keep it short — every Tier-1 plugin costs ~80 tokens on every turn.Validation:- Hard: must be non-empty.
- Soft warn: > 120 chars.
whenToUse
whenToUse
- Type:
string[] - Required: when
visibility !== 'silent'
- Hard: at least 1 entry when
visibility !== 'silent'. - Soft warn: > 8 entries, or any entry > 100 chars.
whenNotToUse
whenNotToUse
- Type:
string[] - Required: no
- Soft warn: > 4 entries, or any entry > 80 chars.
examples
examples
- Type:
ManifestExample[] - Required: no
- Hard: every
example.toolmust reference a tool the plugin actually registers — but only when the plugin registers boot-time tools. Plugins whose tools arrive at request time (MCP-sourced:sandbox,memory,firecrawl) register zero boot-time tools, so the cross-check is skipped for them. A sub-agent’s wrapped name (call_<name>) is a valid example tool too. - Soft warn: > 3 examples.
category
category
- Type:
'data' | 'communication' | 'automation' | 'memory' | 'integration' | 'ui' | 'auth' | 'observability' | 'core' - Required: no
list_capabilities output.visibility
visibility
- Type:
'always' | 'on-demand' | 'silent' - Required: no
- Default:
'on-demand'
always— tools bound at boot; the plugin is listed in the Tier-1 prompt block.on-demand— tools NOT bound at boot; the manifest is discoverable vialist_capabilities; the agent callsload_capabilityto make the tools available.silent— the plugin is not advertised in the capability block orlist_capabilities, but its tools still pass through the capability gate exactly likealwaysand are visible to the model.silentmeans “unadvertised”, not “hidden” or “secure” — it is not a security boundary.
stability
stability
- Type:
'stable' | 'beta' | 'experimental' - Required: no
experimental plugins get a warning footnote in list_capabilities output.ManifestExample
thought is optional but useful — agents pick up the reasoning pattern alongside the example.
Validation behaviour
At boot the runtime callsvalidateManifest(manifest, pluginName) from @ixo/oracle-runtime/manifest. The result:
Cross-checking examples against tools
Eachexample.tool is checked against the names the plugin registers — the union of its boot-time tool names and its sub-agent wrapped names (call_<name>). If a manifest references tool: 'foo' but the plugin registers no such tool, boot fails:
getRequestTools fetched per-request from an upstream MCP server — sandbox, memory, firecrawl), the runtime can’t see those names at boot, so it skips the cross-check rather than false-flag every example.
Worked example
Retuning a bundled plugin’s manifest
You don’t have to fork a bundled plugin to change its manifest.createOracleApp accepts a manifestOverrides option that shallow-merges fork-supplied fields onto each loaded plugin’s manifest before validation and registration — so the override is what the Tier-1 prompt, the meta-tools, and the visibility index all see. This is the supported way to flip a bundled plugin’s visibility (e.g. drop a noisy always plugin to on-demand) or relabel its summary / tags / whenToUse without touching the plugin source.