Capabilities

Capabilities are Storsko's fine-grained permission system for AI agents. Every action an agent wants to take — searching the web, sending an email, executing code, transferring money — must be declared as a capability, granted explicitly to the agent, and validated at runtime before execution.

Capabilities

Capabilities are Storsko's fine-grained permission system for AI agents. Every action an agent wants to take — searching the web, sending an email, executing code, transferring money — must be declared as a capability, granted explicitly to the agent, and validated at runtime before execution.

Think of capabilities as a combination of OAuth scopes and Linux capabilities: they define exactly what an agent is allowed to do, and the governance layer enforces those boundaries on every request.


Why Capabilities Matter

Without a capability system, an AI agent with access to your infrastructure can do anything its underlying tools allow. Storsko's capability model enforces least privilege at the agent level:

  • An agent that should only read files cannot write them
  • An agent that can make phone calls will always require human approval before doing so
  • Capability grants are audited and can be revoked at any time

This is particularly important for multi-agent systems where agents spawn sub-agents (agent.spawn) or delegate tasks (agent.delegate) — the child agent inherits a subset of the parent's capabilities, never more.


Built-in Capabilities

Storsko ships a curated set of built-in capabilities covering common agent actions. Custom capabilities can be defined via the capability registry.

Communication

CapabilityDescriptionDefault HITL Mode
phone.callPlace outbound phone callsescalate
email.sendSend emails on behalf of the agent's ownerpropose
email.readRead emails from a connected inboxnotify

Finance

CapabilityDescriptionDefault HITL Mode
finance.transferInitiate financial transfers or paymentsescalate
finance.readRead account balances and transaction historynotify

File System

CapabilityDescriptionDefault HITL Mode
file.readRead files from connected storage (local, S3, GCS, etc.)auto
file.writeWrite or modify files in connected storagenotify
file.deletePermanently delete filespropose

Web

CapabilityDescriptionDefault HITL Mode
web.searchPerform web searches via configured search providerauto
web.browseNavigate web pages and extract contentauto
web.postSubmit forms or POST data to external web endpointsnotify

Calendar & Scheduling

CapabilityDescriptionDefault HITL Mode
calendar.readRead calendar events and availabilityauto
calendar.writeCreate, modify, or delete calendar eventspropose

Code & Data

CapabilityDescriptionDefault HITL Mode
code.executeExecute code in a sandboxed environmentnotify
data.queryQuery connected databases (read-only)auto
data.writeWrite to connected databasespropose

Agent Operations

CapabilityDescriptionDefault HITL Mode
agent.spawnSpawn a new sub-agent with a subset of current capabilitiesnotify
agent.delegateDelegate a task to another registered agentnotify
agent.terminateTerminate a running agent sessionpropose

High-Risk Capabilities

Two capabilities are hardcoded as high-risk and have special treatment that cannot be overridden by configuration:

CapabilityReason
phone.callReal-world irreversible action; potential for fraud/harassment
finance.transferFinancial transactions are irreversible and directly harmful

For these capabilities:

  1. The HITL mode is always escalate, regardless of what is configured
  2. Escalation targets the organization admin — not just the task owner
  3. Even if HITL is globally disabled (not recommended), these capabilities are still blocked and escalated
  4. They appear with a warning badge in the Storsko dashboard
// packages/capability-registry — excerpt
export const HIGH_RISK_CAPABILITIES = ["phone.call", "finance.transfer"] as const;

export function isHighRisk(capability: string): boolean {
  return (HIGH_RISK_CAPABILITIES as readonly string[]).includes(capability);
}

Granting Capabilities to Agents

Capabilities are granted when an agent is created or updated. Grants are stored in the database and reflected in the agent's JWT.

At Creation Time

curl -X POST http://localhost:3000/api/v1/agents \
  -H "Authorization: Bearer $STORSKO_ROOT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "research-agent",
    "description": "Searches the web and reads files for research tasks",
    "capabilities": ["web.search", "web.browse", "file.read"],
    "risk_level": "minimal"
  }'
import { StorskoClient } from "@storsko/sdk";

const client = new StorskoClient({ apiKey: process.env.STORSKO_ROOT_KEY });

const agent = await client.agents.create({
  name: "research-agent",
  description: "Searches the web and reads files for research tasks",
  capabilities: ["web.search", "web.browse", "file.read"],
  riskLevel: "minimal",
});

Adding Capabilities to an Existing Agent

curl -X POST http://localhost:3000/api/v1/agents/agt_01h9.../capabilities \
  -H "Authorization: Bearer $STORSKO_ROOT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"capability": "email.send"}'
await client.agents.grantCapability(agentId, "email.send");

Revoking Capabilities

curl -X DELETE \
  http://localhost:3000/api/v1/agents/agt_01h9.../capabilities/email.send \
  -H "Authorization: Bearer $STORSKO_ROOT_KEY"
await client.agents.revokeCapability(agentId, "email.send");

Listing an Agent's Capabilities

curl http://localhost:3000/api/v1/agents/agt_01h9.../capabilities \
  -H "Authorization: Bearer $STORSKO_ROOT_KEY"

Response:

{
  "agent_id": "agt_01h9k2m3n4p5q6r7s8t9u0v1w2",
  "capabilities": [
    {
      "name": "web.search",
      "granted_at": "2024-03-01T10:00:00Z",
      "granted_by": "usr_01h9...",
      "hitl_mode": "auto"
    },
    {
      "name": "email.send",
      "granted_at": "2024-03-15T14:30:00Z",
      "granted_by": "usr_01h9...",
      "hitl_mode": "propose"
    }
  ]
}

Capability Validation in the Execution Adapter

The packages/execution-adapter is the governance chokepoint where every execution request is validated. The flow is:

Agent sends: POST /api/v1/executions
  │
  ├─ 1. Validate agent JWT (signature + expiry)
  │
  ├─ 2. Extract capabilities[] from JWT claims
  │
  ├─ 3. Check requested capability is in JWT capabilities[]
  │        → if not: 403 Forbidden
  │
  ├─ 4. Check capability grant is active in DB (not revoked mid-session)
  │        → if revoked: 403 Forbidden
  │
  ├─ 5. Check agent status is "active"
  │        → if deactivated: 403 Forbidden
  │
  ├─ 6. Determine HITL mode for this capability
  │        → high-risk? force "escalate"
  │        → else: use configured hitl_mode for this agent+capability
  │
  ├─ 7. Apply HITL mode
  │        → auto: proceed immediately
  │        → propose/notify/escalate: create HITL request, wait/notify
  │        → block: reject with 403
  │
  ├─ 8. Execute capability
  │
  └─ 9. Write audit log entry (success or failure)

Execution Request Format

curl -X POST http://localhost:3000/api/v1/executions \
  -H "Authorization: Bearer $AGENT_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "capability": "web.search",
    "input": {
      "query": "EU AI Act compliance checklist 2024"
    },
    "context": {
      "task_id": "task_01h9...",
      "session_id": "sess_01h9..."
    }
  }'

Success response (auto mode):

{
  "execution_id": "exec_01h9k2m3n4p5q6r7s8t9u0v1w2",
  "status": "completed",
  "capability": "web.search",
  "output": { "results": [...] },
  "audit_entry_id": "aud_01h9...",
  "hitl_mode": "auto"
}

Pending response (propose mode):

{
  "execution_id": "exec_01h9...",
  "status": "pending_approval",
  "capability": "email.send",
  "hitl_request_id": "hitl_01h9...",
  "hitl_mode": "propose",
  "message": "Awaiting human approval before executing email.send"
}

Configuring HITL Mode Per Capability

You can override the default HITL mode for a specific capability on a specific agent:

curl -X PATCH \
  http://localhost:3000/api/v1/agents/agt_01h9.../capabilities/email.send \
  -H "Authorization: Bearer $STORSKO_ROOT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"hitl_mode": "notify"}'
await client.agents.updateCapabilityConfig(agentId, "email.send", {
  hitlMode: "notify",
});

Custom Capabilities

Beyond the built-in capabilities, you can define custom capabilities in the capability registry for domain-specific actions:

// Define a custom capability
await client.capabilities.define({
  name: "crm.update",
  description: "Update a CRM contact or opportunity",
  category: "crm",
  defaultHitlMode: "notify",
  isHighRisk: false,
  schema: {
    input: {
      type: "object",
      properties: {
        contact_id: { type: "string" },
        fields: { type: "object" },
      },
      required: ["contact_id", "fields"],
    },
  },
});

Capability Inheritance in Agent Delegation

When an agent delegates a task to another agent (agent.delegate), the target agent can only receive capabilities that the delegating agent already has. This prevents privilege escalation through delegation chains:

Agent A has: [web.search, file.read, email.send]
Agent A delegates to Agent B

Agent B can receive at most: [web.search, file.read, email.send]
Agent B CANNOT receive: [finance.transfer] (Agent A doesn't have it)

Similarly, when spawning a sub-agent (agent.spawn), the sub-agent's capability list must be a strict subset of the spawning agent's capabilities.


API Reference Summary

MethodEndpointDescription
GET/api/v1/agents/:id/capabilitiesList capabilities for an agent
POST/api/v1/agents/:id/capabilitiesGrant a capability to an agent
DELETE/api/v1/agents/:id/capabilities/:capabilityRevoke a capability from an agent
PATCH/api/v1/agents/:id/capabilities/:capabilityUpdate HITL mode for a capability
GET/api/v1/capabilitiesList all defined capabilities
POST/api/v1/capabilitiesDefine a custom capability
POST/api/v1/executionsExecute a capability (agent-auth only)