| name | vercel-remote |
| description | Read-first wrapper around the Vercel REST API. Single-call project overviews (deployments, domains, env NAMES-only, warnings) for incident triage. Use whenever the user wants the state of a Vercel project — what deployed, what's failing, which env vars exist, which domains are verified — without you chaining `vercel list`, `vercel inspect`, `vercel env ls`, `vercel domains ls` per project. Also covers deployment logs via `logs` and async deploys via Deploy Hooks with `--wait`. |
| when_to_use | Trigger on phrases like "what's happening on vercel", "is prod up", "vercel status", "why is <project> broken", "latest deployment on <project>", "env vars on <project>", "vercel overview", "check domains on <project>", "tail the logs on <deployment>", "trigger a vercel deploy". |
| allowed-tools | Bash(vercel-remote:*) Bash(python3 *vercel-remote*:*) |
vercel-remote
Project-scoped CLI that wraps the Vercel REST API into a read-first, JSON-output overview tool. Stdlib-only Python 3 (no pip installs, no venvs). Designed for agent-driven incident triage — one call returns the full project/deployments/domains/env-names picture so you don't burn tool calls chaining per-resource requests.
Lives at ${CLAUDE_SKILL_DIR}/../../bin/vercel-remote; the plugin auto-adds bin/ to PATH, so just run vercel-remote ....
Prerequisites
VERCEL_TOKEN set (project .env / .env.local or shell env). Get one at https://vercel.com/account/tokens.
- Optional:
VERCEL_TEAM_ID for team-scoped projects. Every API call appends ?teamId=… when set.
- Optional:
VERCEL_PROJECT to omit --project on every call.
The CLI bails with a clear missing-config message if VERCEL_TOKEN is absent.
When to reach for this
- User asks "what's happening on " → run
overview --project <name> --pretty. One call → project info + recent deployments (with commit metadata) + domain health + env var NAMES + top-level warnings.
- User asks "why is prod broken" → run
deployments list --project <name> --state error --limit 5 then logs <deployment-url> --errors-only.
- User asks "what env vars does have" → run
env list --project <name>. Names only — values never touch output.
- User asks "trigger a deploy" → run
deployments trigger --hook-url <hook> --wait. Waits up to 15 min for build completion.
- User asks "is my domain verified" → run
domains list --project <name> or domains verify <domain> --project <name> --wait.
Headline commands
vercel-remote projects list [--pretty]
vercel-remote projects resolve <name-or-id>
vercel-remote overview --project <name> [--limit 10] [--pretty]
vercel-remote deployments list [--project <name>] [--state ready|error|building|queued|canceled] [--limit 20]
vercel-remote deployments show <deployment-or-url>
vercel-remote deployments trigger --hook-url <url> [--wait] [--timeout 900]
vercel-remote logs <deployment-or-url> [--since 1h] [--errors-only] [--limit 100]
vercel-remote domains list --project <name>
vercel-remote domains verify <domain> --project <name> [--wait] [--timeout 300]
vercel-remote env list --project <name> [--env production|preview|development]
vercel-remote env set <KEY> <VALUE> --project <name> [--env ...] [--wait]
vercel-remote env remove <KEY> --project <name> [--env ...] [--wait]
vercel-remote whoami [--json]
All list/show commands emit JSON to stdout. Use --pretty for indentation.
Every payload carries a top-level tool: {name, version} field so agents can self-diagnose version drift from the output alone. Run vercel-remote --version to check the installed version directly.
Offloading large responses with --output
Vercel responses get large fast — logs on a chatty deployment, overview with high --limit, deployments list across many deployments. Pulling all of that through the model's context is wasteful when you only need a slice.
Pass --output <path> before the subcommand (it's a top-level flag, like --pretty):
vercel-remote --output /tmp/logs.json logs my-app-xyz.vercel.app --since 24h
vercel-remote --output /tmp/deps.json deployments list --project my-app --limit 50
Instead of printing the full payload, stdout returns a compact envelope:
{
"tool": {"name": "vercel-remote", "version": "..."},
"payloadPath": "/tmp/logs.json",
"bytes": 48320,
"fileLineCount": 1204,
"payloadKeys": ["deployment", "entries"],
"payloadShape": {
"deployment": {"type": "string", "length": 24},
"entries": {"type": "list", "length": 412,
"sample": {"type": "dict", "keys": 5,
"shape": {"level": {"type": "string", "length": 5},
"message": {"type": "string", "length": 187},
"timestamp": {"type": "number"}}}}
}
}
How to act on it:
- Check
payloadShape to see where the data lives and how much there is. In the example above, the agent immediately knows there are 412 log entries with {level, message, timestamp} fields — no second call needed to discover shape.
- Use
Read with offset/limit to pull the slice you need. fileLineCount is the upper bound.
- For list-shaped responses (
projects list, deployments list), the envelope has payloadType: "list" + payloadLength + sampleShape describing the first item.
--shape-depth <1|2|3> controls recursion depth. Default is 3 (two layers deep — surfaces patterns like deployments[0].meta). Drop to 1 for a minimal envelope.
When NOT to use --output: small responses (projects resolve, env list — NAMES are already tiny), or when you need the data in the same turn to act on. The envelope points at the file; it doesn't carry the data.
Piping to jq
Output is JSON-first, so pipe freely to jq for focused extraction:
vercel-remote overview --project my-app | jq '.deployments[] | select(.state == "ERROR")'
vercel-remote domains list --project my-app | jq '.[] | select(.verified == false) | .name'
vercel-remote env list --project my-app --env production | jq -r '.names[]'
Design rules (agent-plus patterns)
- Aggregate server-side.
overview returns project + deployments + domains + env names in one call — you don't chain four requests.
- Resolve by name. Pass
--project my-app, not prj_xxxxxxxxxxxxxxxx. The CLI resolves internally via /v9/projects/{idOrName}.
--wait on every async flow. deployments trigger, domains verify, env set/remove support --wait with per-command sensible timeouts (15m / 5m / 30s). On timeout: non-zero exit with partial JSON including the last-known state.
--json is the default. No human-prose output paths. Pipe to jq freely.
- Zero env-value leakage.
env list returns NAMES only. Every API response walks through _scrub() before emission, which masks password, token, githubToken, value, secret, encryptedValue, and related keys. A canary-value test (test/test_vercel_remote.py) asserts a known secret substring never appears in any output path.
Config precedence (highest first)
--token / --team CLI flags
--env-file <path> if passed
.env.local / .env walked up from cwd (closest wins)
- Shell env
Only VERCEL_* prefixed vars are picked up.
Safety
- Read-only by default. Write commands (
env set, env remove, deployments trigger) are explicit subcommands.
- No
deployments trigger via the file-upload path. The command uses Vercel Deploy Hooks (pre-configured webhook URLs, stored as a project secret) — see https://vercel.com/docs/deployments/deploy-hooks. Pass the hook URL via --hook-url.
- Team scoping is mandatory when
VERCEL_TEAM_ID is set. Every API call appends ?teamId=…. Without it, team-scoped resources return 404.
Error message contract
Every error path emits problem + cause + fix + link:
- Missing token → "Set in project
.env or .env.local (keys prefixed VERCEL_), or ~/.claude/settings.json. Get one: https://vercel.com/account/tokens"
- 401 → "Token invalid or expired. Regenerate: https://vercel.com/account/tokens"
- 403 → "Token lacks required scope. Regenerate with appropriate scope."
- 429 → "Rate-limited by Vercel API. Retry after a few seconds." (
Retry-After is honoured automatically; you only see this on exhausted retries.)
- 404 with team scope → notes the team-ID prefix so you can verify
VERCEL_TEAM_ID.
What it doesn't do
Deliberately out of scope for v1:
- Team / user CRUD (team scoping is fully supported via
VERCEL_TEAM_ID; only team management is deferred).
- Billing and invoices.
- Edge Config authoring.
- Framework-specific build logic.
Use the vercel CLI or the dashboard for those. This plugin is read-first operational triage plus the minimum write surface needed by agents (env set/remove, deploy hook trigger).
When NOT to use this — fall back to the vercel CLI or the Vercel API directly
This wrapper's scope is deliberately narrow: projects (list/resolve), overview, deployments (list/show/trigger via Deploy Hook), logs, domains (list/verify), and env (list NAMES / set / remove). Anything outside that surface is not here and won't be — use the vercel CLI (already authed on the user's machine) or curl https://api.vercel.com/... with Authorization: Bearer $VERCEL_TOKEN instead.
Specific cases where you should skip vercel-remote and go straight to vercel or the raw API:
- Creating, renaming, or deleting a project, or configuring its Git integration / framework preset / build-and-output settings. →
vercel project add, vercel project rm, or POST/PATCH/DELETE /v9/projects[/{id}]. vercel-remote only reads and resolves projects.
- DNS records CRUD, domain transfers, or buying a domain.
domains list/verify check project-attached domains; they don't touch the account-level domain registry. → vercel domains ... or /v4/domains, /v2/domains/{domain}/records.
- Edge Config, Blob, KV/Redis, or Postgres storage (reading/writing items, creating stores, rotating tokens). →
vercel env pull + the relevant storage SDK, or the /v1/edge-config/*, /v1/blob/*, storage integration endpoints directly.
- Cron jobs, firewall rules, deployment protection, preview comments, web analytics config, log drains, integrations/marketplace, team/user management, billing/invoices. None of these are wrapped. → dashboard,
vercel CLI, or the corresponding /v1/... endpoint.
- Deploying from local files (not via a pre-configured Deploy Hook).
deployments trigger only fires Deploy Hook URLs. → vercel deploy / vercel --prod, or POST /v13/deployments with a file-upload payload.
- Tailing logs live / runtime (non-build) logs.
logs is a one-shot snapshot of build/function logs for a specific deployment. → vercel logs <url> --follow for a live tail, or the runtime logs drain.
Don't get stuck in a loop. If a vercel-remote command errors with "unknown subcommand" / "not supported", or the user's request obviously needs a write or resource the wrapper doesn't expose, immediately switch to vercel or curl against api.vercel.com rather than re-trying vercel-remote with different flags. The wrapper exists to make reading faster and safer, not to replace the CLI or the REST API.