Skip to main content

Capabilities

A Capability is a named, schema-described function that an agent can call. Capabilities are registered on an AppChain and form the menu of operations available to agents.

Defining a Capability

const sendSmsCapability = {
name: 'send_sms',
description: 'Send an SMS message',
inputSchema: {
type: 'object',
required: ['to', 'message'],
properties: {
to: { type: 'string', description: 'Phone number in E.164 format' },
message: { type: 'string', description: 'SMS content' },
},
},
outputSchema: {
type: 'object',
properties: {
messageId: { type: 'string' },
status: { type: 'string' },
},
},
execute: async (args, ctx) => {
// ctx.agentId — who called this
// ctx.hostId — which host this agent belongs to
// ctx.permissions — all active capabilities for this agent
return smsApi.send(args.to, args.message);
},
};

Key Properties

PropertyRequiredDescription
nameYesUnique identifier. Must match the method name on the target object (if not using execute).
descriptionYesHuman-readable description.
inputSchemaYesJSON Schema for the arguments. The required array is enforced.
outputSchemaYesJSON Schema for the return value.
executeNoCustom execution function. If omitted, the call delegates to the target object's method.

Execute vs. Delegation

There are two modes for running a capability:

With execute

The capability defines its own function. The Proxy calls it directly after auth passes:

{
name: 'createInvoice',
execute: async (args, ctx) => {
// This runs after the 11-step auth pipeline passes
return db.createInvoice(args);
},
}

Without execute (delegation)

The Proxy forwards the call to the target object's method of the same name:

const service = {
async createInvoice(args) {
return db.createInvoice(args);
},
};

// The capability has the same name — no execute needed
const capabilities = [{
name: 'createInvoice',
description: '...',
inputSchema: { ... },
outputSchema: { ... },
// No execute — delegates to service.createInvoice
}];

const secured = chain.wrap(service, grants);
await secured.createInvoice({ amount: 100 });
// → service.createInvoice is called after auth

Agent Context

When using execute, the second argument is an AgentContext:

type AgentContext = {
agentId: string; // Who called this
hostId: string; // Which host this agent belongs to
permissions: string[]; // All active capability names for this agent
};

Capability Registry

Capabilities are stored in a CapabilityRegistry. You typically don't interact with it directly, but it's available:

import { CapabilityRegistry } from 'agents-chain';

const registry = new CapabilityRegistry();

registry.register(capability); // Throws if already registered
registry.upsert(capability); // Replaces without throwing
registry.get('capabilityName'); // Returns Capability or undefined
registry.unregister('capabilityName'); // Removes, returns true if existed
registry.list(); // Returns all registered capabilities