mcpField
N
netlify-ops

netlify-ops

github.com/bm629Cloud & DevOps586 installsUpdated 2w ago
Repository

About netlify-ops

netlify-ops is a skill for agents to perform Netlify hosting operations, using the CLI for site creation, deployment, and status checks, with REST for domains and DNS. It consumes caller-provided credentials and does not handle login or credential setup.

Key features

  1. 01Create sites and deploy with CLI
  2. 02Check deployment status
  3. 03Configure custom domains and DNS
  4. 04Read site data through REST API
  5. 05Resolve operations from OpenAPI spec

Use cases

  1. 01Create a Netlify site and deploy a build directory
  2. 02Publish a preview or production deployment
  3. 03Set up a custom domain and DNS
  4. 04Inspect site or deployment status

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/bm629/agent-skills --skill netlify-ops

After installing, type/netlify-opsin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

assets/
cli-index.md
endpoint-index.md
references/
cli-reference.md
credentials.md
forge-amendments.log
rest-api.md
sources.md
scripts/
create-site.sh
create-site.sh.validation.md
deploy-status.sh
deploy-status.sh.validation.md
deploy.sh
deploy.sh.validation.md
endpoint.py
endpoint.py.validation.md
set-custom-domain.sh
set-custom-domain.sh.validation.md

Details

From the project README

netlify-ops

Overview

This skill lets an agent perform Netlify web-hosting operations CLI-first (the netlify CLI) with a REST fallback on Netlify's official API — no SDK. The CLI is the ergonomic common path (create a site, deploy a directory, read status); the REST API is the comprehensive long tail (custom domains, fine-grained reads, DNS), grounded on a bundled OpenAPI via an endpoint index + a $ref-resolver so coverage never loads the spec into context. The agent consumes the caller-injected token, picks the CLI command or REST operation, runs it, and parses the JSON. It drives Netlify's static/JAMstack + serverless surface — not full-stack container hosting.

When to activate

  • ✅ Creating a Netlify site, or deploying a build to one (draft/preview or --prod).
  • ✅ Setting + verifying a custom domain, or configuring a site's DNS.
  • ✅ Reading deploy status (the state field) or listing/inspecting sites/deploys.

Do NOT activate when:

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

Workflow

Step 1 — Receive the injected credentials

The caller has already resolved the account and injected the token — consume it; do not look for a record or log in. Netlify has no non-secret record field (the host is fixed; no account id/email). You receive from context the capability (web-hosting) and the token's variable NAME. Resolve that name as 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 the token into NETLIFY_AUTH_TOKEN (the CLI reads it; the REST fallback sends Authorization: Bearer). Never netlify login/logout. Full contract: references/credentials.md.

Step 2 — Pick the common path (CLI) or the long tail (REST)
Step 3 — Run it

The four bundled scripts cover the priority ops:

  • create-site.sh <name> [account-slug] — netlify sites:create … --json (returns the site; its id is the id field — --json keys it as id, not site_id — pass that id as --site to deploy).
  • deploy.sh <site-id> <dir> [--prod] — netlify deploy --dir … --site … --json (draft by default; --prod publishes).
  • set-custom-domain.sh <site-id> <domain> — REST PATCH updateSite (custom_domain).
  • deploy-status.sh <site-id> <deploy-id> — getSiteDeploy (the state field).

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

Step 4 — Handle the response
  • Deploys are async + multi-stage. Pull the deploy id from deploy.sh's --json output (the deploy_id / id field) to feed deploy-status.sh. A deploy moves building → uploading → processing → ready (or error). Poll deploy-status.sh (or getSiteDeploy) until state is terminal; a draft deploy has a unique preview URL, --prod publishes to the live site.
  • Custom domain ≠ DNS. Setting custom_domain does not make it resolve — follow with DNS config (configureDNSForSite / dns_zones records).
  • Errors / limits: non-2xx JSON; rate limits are 500 req/min general and deploys 3/min · 100/day — honor the X-RateLimit-* headers. A 401 means a missing/expired token.

Rules

Hard rules (never violate):

  • Never netlify login / netlify logout. Auth is the injected token via NETLIFY_AUTH_TOKEN (or --auth); the CLI runs headlessly. A missing token is a hard caller error, not a cue to log in.
  • Never read or print the token value. Reference it only as $NETLIFY_AUTH_TOKEN (CLI env) or Bearer $NETLIFY_AUTH_TOKEN (REST); the subprocess reads it from the environment. The token lives only in .env (gitignored) or the environment.
  • Resolve before constructing a REST call. Build a body/params from the $ref-resolved schema (endpoint.py) — never from a guessed field set.
  • Deploy to a known site_id with --site. A fresh checkout has no .netlify/state.json; never rely on link state, never use --allow-anonymous.
  • CLI-first, REST for the tail. Use the CLI for create/deploy/status; drop to REST for custom domain, DNS, and fine-grained reads.
  • This skill never writes credentials. Credentials are provided by the caller.

Preferences (override-able):

  • Pass --json (machine output) and --force (skip prompts) to the CLI for non-interactive use.
  • For body-carrying REST writes (updateSite, createSiteDeploy) prefer the pure curl over the netlify api escape hatch (the escape-hatch body-key convention is unverified); use the escape hatch for path-params-only ops.
  • Prefer the CLI netlify deploy --dir over the hand-rolled digest protocol — it does the SHA1 diff + upload for you.

Gotchas

  • Don't log in. The single biggest contract violation: reaching for netlify login when the token "isn't working." A bad token is an error to surface, not a login to perform.
  • --no-build, not --build. The CLI builds by default; there is no --build flag — opt out with --no-build.
  • Draft vs prod. Omitting --prod gives a draft/preview deploy (unique URL, production untouched). Only --prod publishes to the live site.
  • site_id is the key. --name/--account-slug are human-facing; every API op keys on the opaque site_id (in .netlify/state.json after a link). Note: sites:create --json returns this id under id, not site_id (.site_id is null on create) — read .id from create output and pass it as --site.
  • The digest-deploy required-files step. A hand-rolled REST createSiteDeploy returns a required array of SHA1s you must then upload — skip it and the deploy never reaches ready. The CLI handles this.
  • Custom domain needs DNS. updateSite sets custom_domain; the domain only resolves once DNS is configured.
  • Rate limits bite deploys. 3 deploys/min, 100/day — back off on X-RateLimit-Remaining: 0.
  • state is a free string. The spec doesn't enumerate deploy states; treat the value list as from docs and confirm against a live deploy.

Anti-patterns

  • Running netlify login. Forbidden — the contract injects the token; never resolve your own auth or prompt the user to log in.
  • Echoing the token. Never echo $NETLIFY_AUTH_TOKEN, never paste it into a printed command, never write its value to a file. Reference the env var only.
  • Guessing a REST body. Resolve updateSite / createSiteDeploy with endpoint.py — don't hand-write a body from memory.
  • Deploying without --site. Relying on link state in a fresh checkout silently deploys to the wrong (or no) site. Always pass site_id.
  • Using --allow-anonymous. That creates a claimable site without auth — not this skill's path; always deploy to a known site with the injected token.
  • Loading the whole spec. Don't cat the ~690 KB OpenAPI — scan the index, resolve one op.

Output

This skill produces CLI/API side effects (the requested Netlify operation) and returns the parsed JSON to the calling agent. It writes no files of its own (it only consumes the caller-injected token). For a deploy it reports the deploy id + URL + terminal state; for a site it reports the site_id + URL; for reads it returns the requested JSON. 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 (token-by-name → NETLIFY_AUTH_TOKEN, the ordered load rule, no-login).
  • references/cli-reference.md — the netlify CLI surface + the netlify api escape hatch.
  • references/rest-api.md — the REST long tail, the digest-deploy protocol, state + limits.
  • This is the CLI-first sibling of github-cli-ops and the OpenAPI-grounded sibling of atlassian-rest-ops, under the per-provider service-skill pattern.

Progressive disclosure

Heavy content lives in subfolders, loaded only on demand:

  • references/credentials.md — caller-injected token, the ordered load rule, the Bearer bridge, no-login. Load in Step 1.
  • references/cli-reference.md — the CLI commands + escape hatch + CLI gotchas. Load in Steps 2–3.
  • references/rest-api.md — the REST pattern, priority-op table, digest-deploy protocol, state + limits. Load for the REST tail.
  • references/sources.md — provenance (official OpenAPI + CLI/API docs + the two source skills) + the "confirm live" items.
  • assets/cli-index.md — the CLI quick command list (Step 2).
  • assets/endpoint-index.md — one line per REST operation (Step 2).
  • assets/netlify-openapi.json — the bundled spec (Swagger 2.0; queried via the resolver, never loaded wholesale).
  • scripts/endpoint.py + .validation.md — the python3 $ref-resolver (Step 2).
  • scripts/{create-site,deploy,set-custom-domain,deploy-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 Netlify PAT (User → Applications → Personal access tokens), store its value in a gitignored .env, install the CLI (npm i -g netlify-cli), then populate the var yourself:

set -a; source .env; set +a                 # loads $NETLIFY_PROD_TOKEN, never prints it
export NETLIFY_AUTH_TOKEN="$NETLIFY_PROD_TOKEN"
bash scripts/create-site.sh my-site
bash scripts/deploy.sh <site-id> ./dist --prod

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

Body budget

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

Comments

Markdown supported