Manage Statamic content through a safe, authenticated tool execution gateway. Supports managing multiple Statamic sites from a single agent installation.
Before first use, follow the setup in INSTALL.md. For the endpoint contract, see references/api.md.
Credentials are stored in ~/.config/ai-gateway/sites.json (override with AI_GATEWAY_SITES_CONFIG).
json
{
"sites": {
"marketing": { "base_url": "https://marketing.example.com", "token": "token-aaa..." },
"docs": { "base_url": "https://docs.example.com", "token": "token-bbb..." }
}
}
Look up base_url and token by site name before every request.
MethodPathPurposePOST/ai-gateway/executeExecute a toolGET/ai-gateway/capabilitiesList all tools and their enabled stateGET/ai-gateway/capabilities/{tool}Get full usage docs for a specific tool
All requests require Authorization: Bearer {token}.
Do not guess tool arguments. Always discover before executing:
GET /capabilities — see which tools are enabled on this siteGET /capabilities/{tool.name} — get the argument schema, validation rules, example request/response, allowed targets, denied fields, and behavioral notes for that tool/execute requestThis is the primary way to learn how to use any tool. The capabilities endpoints are the source of truth.
json
{
"tool": "tool.name",
"arguments": { },
"request_id": "optional-tracking-id",
"idempotency_key": "optional-dedup-key",
"confirmation_token": "optional-if-confirming"
}
Success: { "ok": true, "tool": "...", "result": { ... }, "meta": { ... } }
Error: { "ok": false, "tool": "...", "error": { "code": "...", "message": "..." }, "meta": { ... } }
⛔ CRITICAL — Structured field values are READ-ONLY structures. Bard, Replicator, Grid, and similar fields store values as deeply nested ProseMirror/TipTap JSON. When reading these back from
entry.getorglobal.get, you will see arrays of node objects withtype,attrs,content, andmarkskeys.You MUST NOT alter the structure. Never add, remove, reorder, or rename nodes, attributes, or marks. You may only change the literal
textstrings inside leaf nodes — nothing else.To update a rich-text field: (1) fetch with
entry.get/global.get, (2) change onlytextvalues, (3) send back structurally identical. Violating this corrupts content.
base_url and token from sites.json before every request./capabilities then /capabilities/{tool} before using any tool for the first time on a site.enabled: true. Only target allowlisted resources. forbidden means off-limits.data must be a JSON object, never an array or string. Don't send unknown argument keys.entry.upsert over entry.create — safer and idempotent.navigation.update is a full tree replacement. Always fetch with navigation.get first.requires_confirmation: true in capabilities: (1) send the request, (2) receive confirmation_required with a token, (3) show the user the operation_summary and ask permission, (4) only if approved, resend with confirmation_token. Never auto-confirm.rate_limited, back off and retry.request_id (e.g. marketing:upsert-about).stache.warm rebuilds content indexes, static.warm regenerates static pages.CodeHTTPActionunauthorized401Check token in sites.json``forbidden403Target not in allowlisttool_not_found404Check name against /capabilities``tool_disabled403Tool is off on this sitevalidation_failed422Read error.message and error.details``resource_not_found404Collection/entry/global/nav/taxonomy missingconflict409Entry exists — use entry.upsert``rate_limited429Wait and retryconfirmation_required200Resend with confirmation_token (after user OK)execution_failed500Retry or reportinternal_error500Retry or report