Skip to main content
manifest.visibility sets the default for every tool the plugin ships. Individual tools can override it. Three values: 'always', 'on-demand' (default), 'silent'.
1

Set plugin-wide visibility on the manifest

The manifest’s visibility flag is the default applied to every tool the plugin returns.
import type { PluginManifest } from '@ixo/oracle-runtime';

const manifest: PluginManifest = {
  title: 'Weather',
  summary: 'Current weather + forecast lookups for cities.',
  whenToUse: ['Current weather', 'Forecasts', 'Outfit recommendations'],
  visibility: 'on-demand',
};
Three tiers: 'always' (bound to the agent at boot, listed in the Tier-1 prompt), 'on-demand' (default — discoverable via list_capabilities, loaded via load_capability), 'silent' (not advertised — see the warning below). Canonical source: weather.plugin.ts.
'silent' controls advertising, not access — it is not a security boundary. A silent plugin is left out of the Tier-1 capability block, excluded from list_capabilities (by default), and rejected by load_capability. But if a silent plugin returns tools, the capability gate passes them straight through to the model, exactly like 'always'-tier tools. Use 'silent' for transport/middleware/Nest-module plugins (e.g. Slack transport, credits/billing) that have nothing to advertise to the agent — never to “hide” a sensitive capability.
2

Override visibility per tool

Set visibility directly on the PluginTool when one tool needs a different tier from the rest of the plugin.
import { tool, z, type PluginTool } from '@ixo/oracle-runtime';

const currentTool: PluginTool = tool(handler, {
  name: 'get_current_weather',
  description: 'Get the current weather for a city.',
  schema: z.object({ city: z.string() }),
});
currentTool.visibility = 'always';

const forecastTool: PluginTool = tool(handler, {
  name: 'get_weather_forecast',
  description: 'Get a daily forecast for a city.',
  schema: z.object({ city: z.string(), days: z.number().optional() }),
});
forecastTool.visibility = 'on-demand';

return [currentTool, forecastTool];
PluginTool shape: see types.ts.
3

Pick the right tier

Use this decision tree.Promoting to 'always' costs ~80 tokens per plugin in the Tier-1 prompt plus the tool schemas on every turn. 'silent' simply stops advertising the plugin to the agent — it does not hide or disable any tools the plugin returns.

What to know before shipping

  • Default is 'on-demand'. A plugin without an explicit manifest.visibility is treated as on-demand.
  • 'on-demand' plugins live in a per-thread loadedPlugins set. The set is monotonic — loading is forever for that thread; a new thread resets it.
  • Per-tool overrides let you ship a mixed plugin (one 'always' tool + several 'on-demand' tools) without splitting it.
  • 'silent' plugins still run their middleware and Nest modules, and any tools they return stay callable by the agent — they’re just never advertised. Use it for instrumentation, rate limiting, billing, and transports. It is not a way to hide a capability for security.
  • A fork with 50 'on-demand' plugins can usually keep 3–5 loaded per thread — the budget stays bounded as the catalog grows.

Visibility tiers concept

Costs and trade-offs for each tier.

Meta-tools

How list_capabilities and load_capability work.