> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ixo.world/llms.txt
> Use this file to discover all available pages before exploring further.

# Manifest schema

> Field-by-field reference for PluginManifest — every field, type, constraint, and validation rule the runtime enforces at boot.

## 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.

```ts theme={"system"}
import type { PluginManifest, ManifestExample } from '@ixo/oracle-runtime';
```

## Type

```ts theme={"system"}
export interface PluginManifest {
  title: string;
  summary: string;
  whenToUse: string[];
  whenNotToUse?: string[];
  examples?: ManifestExample[];
  tags?: string[];
  category?:
    | 'data' | 'communication' | 'automation' | 'memory'
    | 'integration' | 'ui' | 'auth' | 'observability' | 'core';
  visibility?: 'always' | 'on-demand' | 'silent';
  stability?: 'stable' | 'beta' | 'experimental';
}

export interface ManifestExample {
  user: string;
  thought?: string;
  tool: string;
  args?: Record<string, unknown>;
}
```

## Fields

<AccordionGroup>
  <Accordion title="title" icon="tag">
    * **Type:** `string`
    * **Required:** yes

    Human-readable name. Used to prefix every tool description (`[Climate Data] Fetch emissions…`) and appears in the `app.plugins.status()` report. Distinct from `name` — `name` is kebab-case unique identifier, `title` is prose.
  </Accordion>

  <Accordion title="summary" icon="quote-right">
    * **Type:** `string`
    * **Required:** yes

    One-line description. Rendered in the Tier-1 prompt block for `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.
  </Accordion>

  <Accordion title="whenToUse" icon="bullseye">
    * **Type:** `string[]`
    * **Required:** when `visibility !== 'silent'`

    Trigger phrases — each entry teaches the agent a situation in which this plugin is the right call.

    **Validation:**

    * Hard: at least 1 entry when `visibility !== 'silent'`.
    * Soft warn: > 8 entries, or any entry > 100 chars.
  </Accordion>

  <Accordion title="whenNotToUse" icon="circle-xmark">
    * **Type:** `string[]`
    * **Required:** no

    Anti-patterns. Use to disambiguate from other plugins.

    **Validation:**

    * Soft warn: > 4 entries, or any entry > 80 chars.
  </Accordion>

  <Accordion title="examples" icon="lightbulb">
    * **Type:** `ManifestExample[]`
    * **Required:** no

    Few-shot examples. Each example binds a user message to a tool call.

    **Validation:**

    * Hard: every `example.tool` must 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.

    ```ts theme={"system"}
    examples: [
      {
        user: "What's the weather in Berlin?",
        thought: 'Direct lookup — call get_current_weather.',
        tool: 'get_current_weather',
        args: { city: 'Berlin' },
      },
    ]
    ```
  </Accordion>

  <Accordion title="tags" icon="hashtag">
    * **Type:** `string[]`
    * **Required:** no

    Labels for search and filter. Surfaced in `list_capabilities` output.

    **Validation:**

    * Hard: every tag must be lowercase. An uppercase tag is a boot error — `createOracleApp` throws `Plugin manifest validation failed` and the oracle never starts (so `tags: ['Weather']` aborts boot; use `['weather']`).
  </Accordion>

  <Accordion title="category" icon="folder-tree">
    * **Type:** `'data' | 'communication' | 'automation' | 'memory' | 'integration' | 'ui' | 'auth' | 'observability' | 'core'`
    * **Required:** no

    Grouping label. Surfaced in `list_capabilities` output.
  </Accordion>

  <Accordion title="visibility" icon="eye">
    * **Type:** `'always' | 'on-demand' | 'silent'`
    * **Required:** no
    * **Default:** `'on-demand'`

    Discovery and loading mode.

    * `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 via `list_capabilities`; the agent calls `load_capability` to make the tools available.
    * `silent` — the plugin is not advertised in the capability block or `list_capabilities`, but its tools still pass through the capability gate exactly like `always` and are visible to the model. `silent` means "unadvertised", **not** "hidden" or "secure" — it is not a security boundary.

    See [Visibility tiers](/build-an-oracle/develop/plugin-recipes/set-visibility).
  </Accordion>

  <Accordion title="stability" icon="flask">
    * **Type:** `'stable' | 'beta' | 'experimental'`
    * **Required:** no

    Stability hint surfaced to the agent. `experimental` plugins get a warning footnote in `list_capabilities` output.
  </Accordion>
</AccordionGroup>

## ManifestExample

```ts theme={"system"}
interface ManifestExample {
  user: string;                       // representative user message
  thought?: string;                   // optional reasoning
  tool: string;                       // tool the agent should call (must exist)
  args?: Record<string, unknown>;     // tool args
}
```

`thought` is optional but useful — agents pick up the reasoning pattern alongside the example.

## Validation behaviour

At boot the runtime calls `validateManifest(manifest, pluginName)` from `@ixo/oracle-runtime/manifest`. The result:

```ts theme={"system"}
interface ManifestValidationResult {
  valid: boolean;
  errors: string[];        // hard violations — boot fails
  warnings: string[];      // soft violations — logged, boot continues
}
```

Hard violations abort boot with the full error list printed.

Soft violations log warnings. The plugin still loads.

Manifest validation runs before env validation, so manifest errors surface even when env vars are missing.

## Cross-checking examples against tools

Each `example.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:

```text theme={"system"}
[boot-error] [weather] examples[0].tool: references unknown tool "foo".
```

This catches typos and stale manifests during refactors.

The check is **lenient for MCP-sourced plugins**: when a plugin registers no boot-time tools (its tools come from `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

```ts theme={"system"}
const manifest: PluginManifest = {
  title: 'Weather',
  summary: 'Weather lookups via Open-Meteo (no API key required).',
  whenToUse: [
    'Whenever asked about current weather, temperature, precipitation, or wind in any city.',
    'Any question related to forecasts (today, tomorrow, next week) for any location.',
    'When the user asks "what should I wear", "do I need an umbrella", or similar outfit guidance.',
  ],
  whenNotToUse: [
    'Questions about historical or long-term climate data.',
    'Locations smaller than city-level precision.',
  ],
  examples: [
    {
      user: "What's the weather in Berlin?",
      tool: 'get_current_weather',
      args: { city: 'Berlin' },
    },
    {
      user: 'Forecast for Tokyo this week.',
      tool: 'get_weather_forecast',
      args: { city: 'Tokyo', days: 7 },
    },
  ],
  tags: ['weather', 'forecast', 'outfit'],
  category: 'data',
  visibility: 'on-demand',
  stability: 'experimental',
};
```

## Retuning a bundled plugin's manifest

You don't have to fork a bundled plugin to change its manifest. `createOracleApp` accepts a [`manifestOverrides`](/build-an-oracle/reference/createoracleapp#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.

## Related references

* [Manifest concept](/build-an-oracle/understand/manifest)
* [Visibility tiers](/build-an-oracle/develop/plugin-recipes/set-visibility)
* [Plugin API](/build-an-oracle/reference/plugin-api)
* [`manifestOverrides` on `createOracleApp`](/build-an-oracle/reference/createoracleapp#manifestoverrides)
