Skip to content

Capabilities

A capability is a script or small app your team can run safely — from the app, the API, or an AI agent. It has a name and an owner, the JSON Schema of its inputs (which becomes the form people fill in and the input agents send), and versions: every change is a new version, and runs use the one that is published.

{
"slug": "refund-customer",
"name": "Refund a customer",
"description": "Refunds an order and notifies the customer.",
"entry": "index.ts",
"inputSchema": {
"type": "object",
"required": ["orderId"],
"properties": { "orderId": { "type": "string" } }
}
}
// index.ts — the entry; it may import other files and npm packages
import { refund } from "./payments.ts";
export default async function run(inputs: { orderId: string }, ctx) {
ctx.log(`refunding ${inputs.orderId}`);
return { refunded: inputs.orderId };
}

The entry default-exports run(inputs, ctx) and returns JSON. JavaScript and TypeScript both work. When you publish, the entry and everything it imports — your other files and npm packages from the folder’s node_modules (run npm install first) — are bundled into one module, at most 5 MB. Node built-ins (node:crypto, node:buffer …) are available as imports.

By default a capability has no network. To call an API, list its hosts, and the secrets to attach to requests to them:

{
"hosts": ["api.stripe.com"],
"secrets": {
"STRIPE_KEY": {
"host": "api.stripe.com",
"header": "Authorization",
"value": "Bearer {secret}"
}
}
}
export default async function run(inputs, ctx) {
// No key in the code: Reminix adds the Authorization header on the way out.
const res = await fetch("https://api.stripe.com/v1/refunds", {
method: "POST",
body: new URLSearchParams({ payment_intent: inputs.paymentId }),
});
return await res.json();
}
  • Requests go out only to hosts, over HTTPS; anything else fails with “Host not allowed”, and every request is in the run’s log.
  • Each secret is attached only to its host — and only if the secret itself allows that host (Secrets). The code never holds the value. (An API that echoes your credentials back in its response would reveal them to the code — don’t send secrets to one.)
  • value defaults to {secret}; use it for the scheme, e.g. "Bearer {secret}".
  • To read a secret as a plain value (ctx.env.NAME), list it in "env": ["NAME"] — allowed only for a secret whose owner turned on “Let capabilities read the value itself”.

The capability page shows each version’s hosts and secrets, so whoever publishes sees what it can reach.

Terminal window
reminix capabilities publish ./refund-customer # uploads a draft version
reminix capabilities publish ./refund-customer --publish # …and publishes it

The first publish creates the capability. Drafts change nothing until a version is published — by the capability’s owner, or a workspace owner or admin. An agent’s publish becomes a request a person approves. Publishing an older version again rolls back. See Governance for who can use a capability, runs that need approval, and a second person for publishing.

Through the API, with a key or token holding capabilities:write: POST /v1/capabilities (create), POST /v1/capabilities/{slug}/versions (upload { entry, inputSchema, code }), and POST /v1/capabilities/{slug}/versions/{number}/publish.

Once published, anyone in the workspace can run it:

  • In the app: Capabilities → the capability. Its input schema becomes a form; Run shows the output and the log.
  • From the command line: reminix capabilities run refund-customer --input '{"orderId":"o_123"}' prints the output (--log also prints the log).
  • From an agent: through the MCP server, every published capability is a tool named run_<slug> (run_refund_customer) taking its inputs.
  • From the API: POST /v1/capabilities/{slug}/runs — see Runs.