Set visibility

Control whether a plugin's tools are bound at boot, discoverable on demand, or invisible to the agent.

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

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.

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.

Hold back rare tools in an always plugin (Workers runtime)

On @ixo/oracle-runtime-workers 0.39.0 and later, an always plugin can list tools in manifest.onDemandTools instead of setting visibility on each one. The plugin keeps its Tier-1 entry and its other tools; the listed tools wait until load_capability names the plugin. Names are matched at request time, so this works for tools that come from an MCP server too. Give the plugin a brief that says what the held-back tools do: that is its line in the prompt's on-demand catalogue.

import type { PluginManifest } from '@ixo/oracle-runtime-workers';

const manifest: PluginManifest = {
  title: 'Weather',
  summary: 'Current weather + forecast lookups for cities.',
  whenToUse: ['Current weather', 'Forecasts', 'Outfit recommendations'],
  visibility: 'always',
  brief: 'week-long forecasts',
  onDemandTools: ['get_weather_forecast'],
};

A tool's own visibility still wins over the list. Bound tool definitions are paid on every model call, so this keeps the first call small without hiding the plugin.

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. On the Node.js runtime the set is monotonic — loading is forever for that thread; a new thread resets it. On the Workers runtime (0.39.0 and later) a cold turn unloads plugins the thread stopped using, and never a warm one, so the prompt cache is kept. See Loading and unloading on the Workers runtime.
  • Per-tool overrides let you ship a mixed plugin (one 'always' tool + several 'on-demand' tools) without splitting it. On the Workers runtime, manifest.onDemandTools does the same from the manifest.
  • On the Workers runtime (0.39.0 and later) the model reaches an 'on-demand' plugin from its line in the on-demand catalogue, the capability router can load it before the first model call, and a call to one of its hidden tools loads it. Set routable: false to keep the router from preloading it.
  • The bundled sandbox and vfs plugins are wholly 'on-demand' on the Workers runtime from 0.39.0, and memory, skills and user-preferences hold back their rare tools with onDemandTools. Undo any of it with manifestOverrides, for example sandbox: { visibility: 'always' } or memory: { onDemandTools: [] }.
  • '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.