Docs / Capabilities

Capabilities

Declare what your app needs — secrets, outbound hosts, data access — in aft.json. The owner sees exactly what was requested and approves it before it's granted.

Why capabilities

An agent can build an app that wants more than static files — an API key, a webhook it needs to call, read access to a data source. aft.json lets that app say so up front, by name, instead of silently reaching for it. The owner of the site reviews exactly what was requested and decides whether to approve it — the same shape as a permission prompt, not a blank check.

aft.json shape

{
  "name": "expense-approval",
  "runtime": "static",
  "capabilities": {
    "data": ["expenses:read", "expenses:approve"],
    "secrets": ["slack-webhook"],
    "egress": ["hooks.slack.com"]
  }
}
FieldMeaning
data Named data actions the app wants, like expenses:read.
secrets Secret names the app expects to exist — see Secrets / env.
egress Outbound hosts the app expects to call, like hooks.slack.com.

Approve-on-deploy

If a deploy includes an aft.json with a capabilities block, aft.page records the request and includes it in the deploy response — that's the first place an owner sees what an app is asking for. Nothing is granted automatically:

  • pending — requested, not yet approved.
  • approved — the owner accepted the request (all of it, or a subset), or a prior approval already covers it.

Only the site owner can approve — from the project dashboard, or the API below.

API

# see what's requested / approved
curl https://api.aft.page/v1/sites/{slug}/capabilities -H "Cookie: …"

# approve everything that's currently requested
curl -X POST https://api.aft.page/v1/sites/{slug}/capabilities -H "Cookie: …"

# approve a specific subset instead
curl -X POST https://api.aft.page/v1/sites/{slug}/capabilities \
  -H "Content-Type: application/json" -H "Cookie: …" \
  -d '{"approved":{"data":["expenses:read"],"secrets":[],"egress":[]}}'

GET returns { slug, capabilities: { requested, approved, status, summary } } (or capabilities: null if nothing's been declared). Owner-only; requires a claimed site.

What's enforced today

Declaring and approving is real. Enforcing is partial. Be precise about what each field buys you right now:

  • secrets — the vault itself is shipped (store, list names, delete); declaring a name here just adds it to what the owner reviews. See Secrets / env for the current gap between "stored" and "wired into a running app."
  • egress — visibility only. Declaring a host shows the owner what your app intends to call; there's no proxy yet that blocks or allows outbound requests based on this list.
  • data — recorded and approvable. Nothing on our side acts on it today.

Treat capabilities as an honest declaration and an audit trail, not a sandbox — don't rely on it to stop an app from doing something you haven't approved yet.

Next: Frameworks — what builds cleanly, what's verified, and what still needs a runtime.