All tools are bound; visibility controls exposure
A common misconception: thatvisibility decides whether a plugin’s tools are bound to the agent. It doesn’t. Every plugin tool — always, on-demand, and silent — is bound to the agent at compile time. What visibility controls is three separate things: whether the plugin is advertised in the Tier-1 prompt block, whether it is discoverable via the meta-tools, and whether the LLM can call its tools right now (the CapabilityGate enforces this last one per model call).
The three tiers
| Visibility | Callable by the LLM | Listed in Tier-1 prompt | Discoverable via list_capabilities / load_capability |
|---|---|---|---|
always | Always | Yes | Yes |
on-demand | After load_capability({ names: [...] }) for this thread | No | Yes |
silent | Always (if it ships tools) | No | No |
on-demand. A plugin without an explicit visibility is treated as on-demand.
What each tier is for
| Tier | Use for | Token cost per turn |
|---|---|---|
always | Plugins the agent needs on nearly every turn (e.g. memory, skills, user-preferences) | ~80–150 tokens for the Tier-1 entry + tool schemas (~100–300 per tool) on every turn |
on-demand | Plugins useful in narrow situations (e.g. portal, firecrawl, composio) | No Tier-1 entry; tool schemas only count once the plugin is loaded |
silent | Plugins that act through middleware or HTTP only (e.g. credits, calls) | No Tier-1 entry and not discoverable; any tools it ships are still bound |
How on-demand gating actually works
Because all tools are bound at compile time, “loading” a plugin is not about binding — it’s about lifting a filter. TheCapabilityGateMiddleware runs on every model call. It reads the thread’s loadedPlugins set and trims the tool list the model sees:
alwaysandsilenttools → always pass the gate (the model can call them).on-demandtools → pass only when their plugin is inloadedPlugins.
createAgent({ tools }) freezes the bound list, so a load_capability call updating state mid-run would otherwise have no effect until the next request rebuilt the agent. Filtering inside the middleware lets a load decision take effect on the very next LLM call. The gate is one of the always-on middlewares.
Picking a tier
Promoting toalways is a deliberate budget choice — it pays Tier-1 tokens on every turn. silent is for plugins that don’t need to be advertised or discovered (they work through middleware or HTTP). Most plugins should stay on the default — on-demand.
Loading and unloading
on-demand plugins live in a per-thread loadedPlugins state field. The set is monotonic — it only grows. Loading a plugin makes its tools available for the rest of that thread; a new thread starts with an empty loadedPlugins.
There is no “unload” operation. If a thread accumulates too many loaded plugins, starting a new thread is the reset.
Per-tool override
A plugin can override visibility per tool by settingvisibility on the PluginTool itself. This lets one plugin ship a mix — e.g. one always tool and several on-demand tools — without splitting into two plugins.
Read next
Set visibility (recipe)
How to declare each tier in plugin code.
Meta-tools
How
list_capabilities and load_capability work.PluginManifest.