docspluginsextensions

Extensions

An extension gives an agent a real-world capability — reaching your inbox, watching your calendar, fetching a page — exposed as tools the agent can call.

What an extension does

On its own an agent can think and talk. An extension is how it acts: each one wraps an outside system and hands the agent tools for it — search this mailbox, create that event, fetch this page. The agent opts into the extensions it needs, and the tools appear in its kit. Some extensions also watch for change and push into a conversation the moment something happens, so the agent can react without being asked.

What Cast ships with

  • email — search and read mail, send and reply, and subscribe to matching mail.
  • calendar — list and inspect events, and create, update, or delete them through an approval ladder.
  • web-fetch — pull a URL, render it, and return clean text the agent can read.
  • whatsapp — read, send, and download WhatsApp messages and media.

Turning one on

An agent opts into an extension in its blueprint — blueprint/props/capabilities.json lists each one under extensions with enabled: true, plus an optional dedicated channel for push. Enablement is per-agent: the same extension can be on for one agent and off for another, which is what lets a blueprint ship to many installs.

From a service

The bundled extensions are registered with the Cast server and enabled per-agent. But an extension doesn't have to be registered fleet-wide to be used — an agent service can wire one up itself, with no change to the Cast runtime. The extension then lives inside that one agent's service.

The extension contract is portable: it depends only on @getcast/extension-schema, never on server internals. So the service imports the package and calls create() with a context built from its own directory, secrets, and message routing.

import { email } from '@getcast/ext-email';

const mail = email.create({
  config: { /* ... */ },
  secrets: svc.secrets,
  privateDir: svc.serviceDir,
  sharedDir: svc.sharedDir,
  deliver: (text) => svc.routeMessage('default', text),
  log: console,
});

const hits = await mail.search({ query: 'invoice' });

The methods a service calls this way run below the tool layer, where the approval gates live, so the service is the trusted caller and applies its own policy.

💡 TIP
This is the lighter path for a one-off or experimental capability you're not ready to register across the fleet. Authoring an extension to be driven this way is covered in Creating an extension.

Config & secrets

Two install-specific things live outside the blueprint, per agent: behavioral config (overrides in config/ext/<name>/config.json) and credentials (config/ext/<name>/secrets.json). The blueprint decides what an operator may change — a value is locked by default, or marked overridable. The files and the locking rule are covered in Configuring agents.

🔒 SECURITY
Files under config/ext/ are not mounted into the container. The extension runs on the host and reads them there, so a credential can power a tool the agent uses without the agent ever seeing the secret itself.

Extensions, services & MCP

An extension is the curated path — framework-backed, with typed config, a lifecycle, approval gates, and a contribution to the agent's prompt. When no extension fits, a service you write or an external MCP server can fill the gap, with different trade-offs. Capabilities lays out the three side by side.

Authoring your own

Extensions are standalone packages, built to ship to others. To write one, see Creating an extension.