skillZs
★ LIVE SKILL TAGS ★
>>> LIVE SKILLS INDEX <<<
* OPEN SOURCE *
NO LOGIN, NO TRACKING
※ REAL INSTALL DATA ※
← back to all skills
fellowship-dev/dogfooded-skills163 installs

vercel-deploy

Use when deploying an existing Vercel project to production non-interactively.

How do I install this agent skill?

npx skills add https://github.com/fellowship-dev/dogfooded-skills --skill vercel-deploy
view source ↗

Is this agent skill safe to install?

  • Gen Agent Trust Hubpass

    The skill facilitates the automated deployment of an existing Vercel project using the official Vercel CLI and API. It includes stages for environment preflight, project linking via file creation, deployment execution, and API polling for status. All operations target trusted or well-known services.

  • Socketpass

    No alerts

  • Snykpass

    Risk: LOW · No issues

What does this agent skill do?

Purpose

Deploy an existing Vercel project to production from a local directory. Designed to never hang, never create new projects, and never assume implicit state.

Required Secrets

Must be available as environment variables (from crew secret store):

  • VERCEL_TOKEN — Access token with deploy permissions (this is the only real secret)

Required Inputs

All inputs are passed as KEY=value pairs in the skill invocation or task description. Parse them from the args — never read these from environment variables.

  • DEPLOY_DIR — Path to the deployable directory (e.g., ./ui, repo root)
  • PROD_DOMAIN — Expected production domain (e.g., pylot.fellowship.dev)
  • VERCEL_ORG_ID — Organization/team ID (starts with team_)
  • VERCEL_PROJECT_ID — Project ID (starts with prj_)

These values come from the repo playbook (GET /admin/playbooks/<repo>), not from secrets. The operator reads the playbook and passes them when invoking this skill. Deploy only through this skill's CLI flow — never rely on Vercel's Git auto-deploy integration; it bypasses the playbook-sourced inputs above and the checks in Forbidden Actions.

Optional Inputs

  • DEPLOY_BRANCH — Git branch to deploy from. Defaults to main if not specified. Always checks out and pulls before deploying.
  • DEPLOY_AUTHOR — Git name of a verified Vercel team member (e.g., maxfindel). If provided along with DEPLOY_EMAIL, Stage 00 will fix the commit author before deploying. Only needed when Vercel enforces team membership on the commit author.
  • DEPLOY_EMAIL — Git email matching the author. Required if DEPLOY_AUTHOR is set.

Forbidden Actions

  1. NEVER create a new Vercel project. If it doesn't exist, STOP and report failure.
  2. NEVER assume project auto-links. Always verify or write .vercel/project.json explicitly.
  3. NEVER connect a git repo to the Vercel project. All deploys are CLI pushes, not git-triggered.
  4. NEVER run vercel without --token and --yes. The CLI hangs forever without them.
  5. NEVER run vercel link. It prompts interactively. Write .vercel/project.json directly.
  6. NEVER run vercel project create or equivalent. Separate procedure exists for that.

Stage Overview

StageNamePurpose
00author-fixFix commit author if DEPLOY_AUTHOR is set (optional, skipped otherwise)
01preflightVerify secrets, tools, compute deploy context
02linkEnsure .vercel/project.json exists; verify project via API
03deployRun vercel deploy --prod non-interactively
04pollPoll Vercel API until deployment reaches READY or ERROR
05verifyConfirm production domain is reachable, emit outcome

Stage 00 — Author Fix (conditional)

Skip this stage if DEPLOY_AUTHOR is not provided. Not all Vercel projects enforce team membership on commit authors.

When Vercel does enforce it (TEAM_ACCESS_REQUIRED / seatBlock), bot accounts (e.g. fry-lobster) will block CLI deploys. The fix is an empty commit with a team member as author.

# Only run if DEPLOY_AUTHOR is set in the skill params
if [ -n "$DEPLOY_AUTHOR" ] && [ -n "$DEPLOY_EMAIL" ]; then
  HEAD_AUTHOR=$(git log -1 --format='%an')
  if [ "$HEAD_AUTHOR" != "$DEPLOY_AUTHOR" ]; then
    echo "[vercel-deploy] HEAD author '$HEAD_AUTHOR' is not a Vercel team member."
    echo "[vercel-deploy] Creating empty commit with author '$DEPLOY_AUTHOR' to unblock deploy."
    git commit --allow-empty \
      --author="$DEPLOY_AUTHOR <$DEPLOY_EMAIL>" \
      -m "chore: vercel deploy author fix (empty commit)"
    git push origin HEAD
  fi
else
  echo "[vercel-deploy] Stage 00 skipped — no DEPLOY_AUTHOR configured"
fi

Stage 01 — Preflight

Verify all secrets and inputs exist, tools are installed, and checkout the deploy branch.

# Verify required secret (from crew secret store — the only real secret)
[ -z "$VERCEL_TOKEN" ] && { echo "[vercel-deploy] MISSING secret: VERCEL_TOKEN"; exit 1; }

# Verify required inputs (parsed from skill args / task description — from the repo playbook)
[ -z "$DEPLOY_DIR" ]        && { echo "[vercel-deploy] MISSING input: DEPLOY_DIR — check the repo playbook"; exit 1; }
[ -z "$PROD_DOMAIN" ]       && { echo "[vercel-deploy] MISSING input: PROD_DOMAIN — check the repo playbook"; exit 1; }
[ -z "$VERCEL_ORG_ID" ]     && { echo "[vercel-deploy] MISSING input: VERCEL_ORG_ID — check the repo playbook"; exit 1; }
[ -z "$VERCEL_PROJECT_ID" ] && { echo "[vercel-deploy] MISSING input: VERCEL_PROJECT_ID — check the repo playbook"; exit 1; }

# Optional: warn if author-fix params are incomplete (both or neither)
if [ -n "$DEPLOY_AUTHOR" ] && [ -z "$DEPLOY_EMAIL" ]; then
  echo "[vercel-deploy] WARNING: DEPLOY_AUTHOR set but DEPLOY_EMAIL missing — Stage 00 will be skipped"
fi

# Verify vercel CLI is available
command -v vercel >/dev/null 2>&1 || command -v npx >/dev/null 2>&1 || {
  echo "[vercel-deploy] vercel CLI not available — install with: npm i -g vercel"
  exit 1
}

# Verify deploy directory exists
[ -d "$DEPLOY_DIR" ] || { echo "[vercel-deploy] DEPLOY_DIR not found: $DEPLOY_DIR"; exit 1; }

# Checkout and pull deploy branch
DEPLOY_BRANCH="${DEPLOY_BRANCH:-main}"
git checkout "$DEPLOY_BRANCH" && git pull origin "$DEPLOY_BRANCH" || {
  echo "[vercel-deploy] Failed to checkout/pull $DEPLOY_BRANCH"
  exit 1
}

# Save state for downstream stages
cat > /tmp/vercel-deploy-ctx.env <<EOF
DEPLOY_BRANCH=$DEPLOY_BRANCH
DEPLOY_DIR=$DEPLOY_DIR
PROD_DOMAIN=$PROD_DOMAIN
EOF

echo "[vercel-deploy] Stage 01 complete — preflight passed, branch: $DEPLOY_BRANCH"

Stage 02 — Link

Write .vercel/project.json directly (never use vercel link), then verify the project exists via API.

source /tmp/vercel-deploy-ctx.env

# Write project link file directly
mkdir -p "$DEPLOY_DIR/.vercel"
cat > "$DEPLOY_DIR/.vercel/project.json" <<EOF
{
  "orgId": "$VERCEL_ORG_ID",
  "projectId": "$VERCEL_PROJECT_ID"
}
EOF

# Verify project exists via Vercel API
PROJECT_JSON=$(curl -sf \
  -H "Authorization: Bearer $VERCEL_TOKEN" \
  "https://api.vercel.com/v9/projects/$VERCEL_PROJECT_ID?teamId=$VERCEL_ORG_ID")

[ -z "$PROJECT_JSON" ] && {
  echo "[vercel-deploy] Stage 02 failed: project $VERCEL_PROJECT_ID not found — STOP, do not create"
  exit 1
}

PROJECT_NAME=$(echo "$PROJECT_JSON" | python3 -c \
  "import sys,json; d=json.load(sys.stdin); print(d.get('name','unknown'))" 2>/dev/null || echo "unknown")

echo "PROJECT_NAME=$PROJECT_NAME" >> /tmp/vercel-deploy-ctx.env
echo "[vercel-deploy] Stage 02 complete — linked to project '$PROJECT_NAME' ($VERCEL_PROJECT_ID)"

Stage 03 — Deploy

Run vercel deploy --prod non-interactively. Must use --token and --yes — without them the CLI hangs.

source /tmp/vercel-deploy-ctx.env

cd "$DEPLOY_DIR"
DEPLOY_OUTPUT=$(npx vercel deploy --prod --token="$VERCEL_TOKEN" --yes 2>&1)
DEPLOY_EXIT=$?

echo "$DEPLOY_OUTPUT"

if [ $DEPLOY_EXIT -ne 0 ]; then
  echo "[vercel-deploy] Stage 03 failed: vercel deploy exited $DEPLOY_EXIT"
  exit 1
fi

# Extract deployment URL (last https:// line in output)
DEPLOY_URL=$(echo "$DEPLOY_OUTPUT" | grep -E '^https://' | tail -1)
[ -z "$DEPLOY_URL" ] && {
  echo "[vercel-deploy] Stage 03 failed: no deployment URL found in vercel output"
  exit 1
}

echo "DEPLOY_URL=$DEPLOY_URL" >> /tmp/vercel-deploy-ctx.env
echo "[vercel-deploy] Stage 03 complete — deployment URL: $DEPLOY_URL"

Stage 04 — Poll

Poll the Vercel API until the deployment reaches READY or ERROR. Timeout after 120 seconds.

source /tmp/vercel-deploy-ctx.env

MAX_WAIT=120
ELAPSED=0
DEPLOY_HOST=$(echo "$DEPLOY_URL" | sed 's|https://||')

while [ $ELAPSED -lt $MAX_WAIT ]; do
  DEPLOY_STATE=$(curl -sf \
    -H "Authorization: Bearer $VERCEL_TOKEN" \
    "https://api.vercel.com/v13/deployments?url=${DEPLOY_HOST}&teamId=$VERCEL_ORG_ID&limit=1" \
    | python3 -c \
      "import sys,json; d=json.load(sys.stdin); deps=d.get('deployments',[]); print(deps[0].get('state','UNKNOWN') if deps else 'NOT_FOUND')" \
      2>/dev/null || echo "API_ERROR")

  echo "[vercel-deploy] Deploy state: $DEPLOY_STATE (${ELAPSED}s elapsed)"

  case "$DEPLOY_STATE" in
    READY)
      echo "[vercel-deploy] Stage 04 complete — deployment READY"
      break
      ;;
    ERROR|CANCELED)
      echo "[vercel-deploy] Stage 04 failed: deployment reached terminal state $DEPLOY_STATE"
      exit 1
      ;;
    *)
      sleep 10
      ELAPSED=$((ELAPSED + 10))
      ;;
  esac
done

[ $ELAPSED -ge $MAX_WAIT ] && {
  echo "[vercel-deploy] Stage 04 failed: timed out after ${MAX_WAIT}s — last state: $DEPLOY_STATE"
  exit 1
}

Stage 05 — Verify

Confirm the production domain is reachable (HTTP 200, 301, or 302), then emit outcome.

source /tmp/vercel-deploy-ctx.env

VERIFY_URL="https://$PROD_DOMAIN"
HTTP_STATUS=$(curl -sf -o /dev/null -w "%{http_code}" --max-time 15 "$VERIFY_URL" 2>/dev/null || echo "000")

echo "[vercel-deploy] $VERIFY_URL → HTTP $HTTP_STATUS"

case "$HTTP_STATUS" in
  200|301|302)
    echo "[vercel-deploy] Stage 05 complete — production domain verified"
    ;;
  *)
    echo "[vercel-deploy] Stage 05 failed: $VERIFY_URL returned HTTP $HTTP_STATUS"
    exit 1
    ;;
esac

After the verification command, emit the matching resolved marker as your final full assistant line (not from Bash and not inside a fence):

  • Verified: [pylot:$PYLOT_OUTCOME_NONCE] outcome="vercel-deploy succeeded" project=$PROJECT_NAME domain=$PROD_DOMAIN deploy_url=$DEPLOY_URL status=success
  • Failed: [pylot:$PYLOT_OUTCOME_NONCE] outcome="vercel-deploy failed at stage 05: $PROD_DOMAIN returned HTTP $HTTP_STATUS" status=failed

Execution Model

  • Follow stages in order. Each stage's checkpoint must pass before proceeding.
  • Do not skip stages. Every checkpoint is verified.
  • Fail fast. If any checkpoint fails, stop and report with status=failed.
  • State is passed between stages via /tmp/vercel-deploy-ctx.env.

Critical Rules

  1. Sequential execution only. Stage N's checkpoint must pass before starting stage N+1.
  2. No skipping. Every stage runs, every checkpoint is verified.
  3. Fail fast. If any checkpoint fails, stop and report.
  4. Every vercel or npx vercel invocation MUST include --token="$VERCEL_TOKEN" --yes.

Error Handling

If any stage fails:

  1. Print which stage failed and the exact error
  2. Include the Vercel API response body if available
  3. Emit: [pylot:$PYLOT_OUTCOME_NONCE] outcome="vercel-deploy failed at stage <NN>: <reason>" status=failed
  4. Do NOT retry automatically

Outcome

On success, emit:

[pylot:$PYLOT_OUTCOME_NONCE] outcome="vercel-deploy succeeded" project=$PROJECT_NAME domain=$PROD_DOMAIN deploy_url=$DEPLOY_URL status=success

Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.

<a href="https://skillzs.dev/skills/fellowship-dev/dogfooded-skills/vercel-deploy">View vercel-deploy on skillZs</a>