SuperAPI AI Directory

cloudflare-pages-ops

Deployment & operations

View repository

Updated 10-15 20:07

About this skill

cloudflare-pages-ops

Overview

This skill lets an agent perform Cloudflare Pages operations CLI-first (the Wrangler CLI) with a REST fallback on Cloudflare's official API — no SDK. Wrangler is the ergonomic common path (create a project, deploy a build directory); the REST API is the comprehensive long tail (custom domains, deployment status, project/deployment/domain management), grounded on a bundled Pages OpenAPI slice via an endpoint index + a $ref-resolver so coverage never loads the spec into context. The agent consumes the caller-injected account_id + token, picks the Wrangler command or REST operation, runs it, and parses the result. It drives Cloudflare Pages' static/JAMstack + serverless surface — not full-stack container hosting.

When to activate

  • ✅ Creating a Pages project, or deploying a build directory to one (Direct Upload).
  • ✅ Adding/listing a custom domain, or reading deployment status (the stage machine).
  • ✅ Listing/inspecting/deleting projects, deployments (retry/rollback), or domains.

Do NOT activate when:

  • You need full-stack container/app hosting (Render, Fly.io, Railway, Vercel SSR-as-PaaS) — Cloudflare Pages here is a static/JAMstack + serverless host only.
  • You only need credential setup — credentials are provided by the caller; this skill does not provision or resolve them, and never runs wrangler login (see references/credentials.md).

Workflow

Step 1 — Receive the injected credentials

The caller has already resolved the account and injected what this operation needs — consume it; do not look for a record or log in. You receive from context:

  • account_id (a non-secret plain context value — exported as CLOUDFLARE_ACCOUNT_ID and interpolated into the REST path) and the capability (web-hosting).
  • The token, by an ordered load rule the context carries the variable NAME for: the project-level .env value if that file exists and defines the var, else the environment variable of that name (project .env first). The token value is never in context prose — only its variable name. Perform no scope resolution or directory walk; it is project .env, not .envrc.

Bridge into CLOUDFLARE_API_TOKEN (Bearer) + CLOUDFLARE_ACCOUNT_ID. Never wrangler login. Full contract: references/credentials.md.

Step 2 — Pick the common path (Wrangler) or the long tail (REST)

Step 3 — Run it

The four bundled scripts cover the priority ops:

  • create-project.sh <name> [branch] — wrangler pages project create … --production-branch … (Direct-Upload project).
  • deploy.sh <project> <dir> [branch] — wrangler pages deploy … --commit-dirty true (uploads the built dir).
  • add-custom-domain.sh <project> <domain> — REST POST …/domains (Wrangler has no domain command).
  • deployment-status.sh <project> <deployment-id> — REST get-deployment-info (the stage machine).

For anything else: Wrangler command from cli-index.md, or a curl against the resolved REST op.

Step 4 — Handle the response

  • Get the deployment id first. deploy.sh (Wrangler) prints only text, not the id deployment-status.sh needs — capture it with wrangler pages deployment list --project-name <name> --json | jq -r '.[0].Id' (deployment list --json returns capitalized table keys, so .Id, not .id).
  • Deploys are async + staged. A deployment moves through latest_stage.name ∈ queued/initialize/clone_repo/build/deploy with status ∈ success/idle/active/failure/canceled. Poll deployment-status.sh until the deploy stage reaches status: success (done) or any stage hits failure.
  • Check the envelope, not just HTTP. Every REST response is {success, errors, messages, result} — a 200 can carry success: false; read errors[].code/message.
  • Custom domain ≠ DNS. Adding a domain needs it on a Cloudflare zone with DNS pointed at the project.
  • Limits: 1,200 requests / 5 min per user → HTTP 429.

Rules

Hard rules (never violate):

  • Never wrangler login. Auth is the injected CLOUDFLARE_API_TOKEN + CLOUDFLARE_ACCOUNT_ID; Wrangler runs headlessly. A missing token/account_id is a hard caller error, not a cue to log in.
  • Never read or print the token value. Reference it only as $CLOUDFLARE_API_TOKEN (env / Bearer); the subprocess reads it from the environment. The token lives only in .env (gitignored) or the environment. account_id is non-secret context, not a secret.
  • Deploy a directory with Wrangler, not curl. The REST create-deployment body is multipart/form-data; never hand-roll a directory deploy over curl.
  • Resolve before constructing a REST call. Build a body/params from the $ref-resolved schema (endpoint.py) — never from a guessed field set.
  • Check success, not just HTTP. A 200 with success:false is a failure — read errors[].
  • This skill never writes credentials. Credentials are provided by the caller.

Preferences (override-able):

  • Pass --json to wrangler pages project list / deployment list for machine output.
  • --commit-dirty true on a deploy from an uncommitted tree.
  • Use REST for custom domains + per-deployment status (Wrangler has no command for those).

Gotchas

  • Don't log in. Reaching for wrangler login when the token "isn't working" violates the contract — a bad token/account_id is an error to surface, not a login to perform.
  • CLOUDFLARE_ACCOUNT_ID is required headlessly. Wrangler needs it alongside the token; a missing account id is the most common CI failure.
  • Deploy is multipart. The REST deploy endpoint is multipart/form-data (binary parts) — use wrangler pages deploy <dir>; don't JSON-POST a deploy.
  • Direct Upload vs Git-connected. wrangler pages deploy works on Direct-Upload projects; a Git-connected project deploys on git push and Wrangler won't deploy it. (A Direct-Upload project can't later switch to Git.)
  • The envelope hides failures. {success:false} can ride a 200; always check it.
  • Custom domain needs DNS — the API won't create it. add-custom-domain.sh only registers the domain (status: initializing); the REST POST /domains does NOT create the DNS record, even on a same-account zone (only the dashboard auto-creates it). Validation stays pending ("CNAME record not set") until a CNAME <domain> -> <project>.pages.dev exists on the zone — and a Pages-scoped token can't create that record (needs Zone DNS:Edit), so the caller adds it out-of-band.
  • pages deploy <dir> uploads, doesn't build. Pass the already-built output dir (dist/build/…); Wrangler doesn't run your framework build.
  • Rate limit. 1,200 req/5 min per user, cumulative — back off on 429.

Anti-patterns

  • Running wrangler login. Forbidden — the contract injects the token; never resolve your own auth or prompt the user to log in.
  • Echoing the token. Never echo $CLOUDFLARE_API_TOKEN, never paste it into a printed command, never write its value to a file. Reference the env var only. (account_id is non-secret and may appear in paths.)
  • Hand-rolling a directory deploy over REST. The deploy is multipart — use Wrangler.
  • Guessing a REST body. Resolve create-project / add-domain with endpoint.py — don't hand-write a body from memory.
  • Trusting the HTTP status alone. A 200 with success:false is a failure — read errors[].
  • Loading the whole spec. Don't cat the bundled slice — scan the index, resolve one op. (And never fetch the 10 MB full Cloudflare OpenAPI.)

Output

This skill produces CLI/API side effects (the requested Cloudflare Pages operation) and returns the parsed result to the calling agent. It writes no files of its own (it only consumes the caller-injected credentials). For a deploy it reports the deployment id + URL + terminal stage status; for a project it reports the project name/id + URL; for reads it returns the requested result. The abstract consumer is the calling agent (or a sub-agent) that needs the web-hosting operation performed; secrets never enter that output.

Related

  • references/credentials.md — the credential contract (account_id from context + token-by-name → CLOUDFLARE_API_TOKEN, the ordered load rule, no-login).
  • references/wrangler.md — the Wrangler Pages surface + what it doesn't cover.
  • references/rest-api.md — the REST long tail, the envelope, the deploy stage machine, limits.
  • This is the CLI-first sibling of github-cli-ops and the OpenAPI-grounded sibling of atlassian-rest-ops / netlify-ops, under the per-provider service-skill pattern.

Progressive disclosure

Heavy content lives in subfolders, loaded only on demand:

  • references/credentials.md — caller-injected account_id + token, the ordered load rule, the Bearer bridge, no-login. Load in Step 1.
  • references/wrangler.md — the Wrangler commands + the Direct-Upload-vs-Git rule + CLI gotchas. Load in Steps 2–3.
  • references/rest-api.md — the REST pattern, the priority-op table, the envelope, the deploy stage machine, limits. Load for the REST tail.
  • references/sources.md — provenance (the bundled Pages slice + official docs) + the "confirm live" items.
  • assets/cli-index.md — the Wrangler quick command list (Step 2).
  • assets/endpoint-index.md — one line per REST operation (Step 2).
  • assets/cloudflare-pages-openapi.json — the bundled Pages OpenAPI slice (queried via the resolver, never loaded wholesale).
  • scripts/endpoint.py + .validation.md — the python3 $ref-resolver (Step 2).
  • scripts/{create-project,deploy,add-custom-domain,deployment-status}.sh + .validation.md — four validated priority-op scripts.

Standalone usage (optional, not required)

This is a convenience for a human running the skill by hand outside an agent-flow — it is not a dependency of the skill. The skill's normative contract is caller-injection (Step 1); this appendix is only the manual-operator bridge.

To run by hand, create a scoped token (My Profile → API Tokens → Create Token, Cloudflare Pages: Edit), store its value in a gitignored .env, install Wrangler (npm i -g wrangler), then populate the vars yourself:

set -a; source .env; set +a                 # loads $CLOUDFLARE_PAGES_TOKEN, never prints it
export CLOUDFLARE_ACCOUNT_ID="<account-id>"
export CLOUDFLARE_API_TOKEN="$CLOUDFLARE_PAGES_TOKEN"
bash scripts/create-project.sh my-site main
bash scripts/deploy.sh my-site ./dist

The token value is referenced by name only, never printed. Prefer a revocable, short-lived scoped token.

Body budget

  • description ≤ 1,024 chars (agentskills.io cap).
  • Body ≤ ~500 lines / 5,000 tokens — kept in context every turn; Wrangler/REST detail lives in references/.
  • assets/cloudflare-pages-openapi.json is the Pages slice (queried on disk, never loaded into context).