dev-cloudflare-pages-ci-setup

Set up Cloudflare Pages deployment with GitHub Actions workflows. Use when: (1) Deploying a static site to Cloudflare Pages, (2) User says 'cloudflare pages', 'deploy to cloudflare', 'cf pages setup', (3) User wants CI/CD workflows for Cloudflare Pages with PR previews, (4) Setting up wrangler deployment pipelines.

6 stars

Best use case

dev-cloudflare-pages-ci-setup is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Set up Cloudflare Pages deployment with GitHub Actions workflows. Use when: (1) Deploying a static site to Cloudflare Pages, (2) User says 'cloudflare pages', 'deploy to cloudflare', 'cf pages setup', (3) User wants CI/CD workflows for Cloudflare Pages with PR previews, (4) Setting up wrangler deployment pipelines.

Teams using dev-cloudflare-pages-ci-setup should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/dev-cloudflare-pages-ci-setup/SKILL.md --create-dirs "https://raw.githubusercontent.com/Takazudo/claude-resources/main/skills/dev-cloudflare-pages-ci-setup/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/dev-cloudflare-pages-ci-setup/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How dev-cloudflare-pages-ci-setup Compares

Feature / Agentdev-cloudflare-pages-ci-setupStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Set up Cloudflare Pages deployment with GitHub Actions workflows. Use when: (1) Deploying a static site to Cloudflare Pages, (2) User says 'cloudflare pages', 'deploy to cloudflare', 'cf pages setup', (3) User wants CI/CD workflows for Cloudflare Pages with PR previews, (4) Setting up wrangler deployment pipelines.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

Related Guides

SKILL.md Source

# Cloudflare Pages CI Setup

Set up Cloudflare Pages deployment with GitHub Actions workflows for static sites. Supports production deploys, PR preview deploys, and named preview branches.

## Step 1: Gather Project Info

Identify the project's build setup:

```bash
cat package.json
ls .github/workflows/ 2>/dev/null
cat wrangler.toml 2>/dev/null
```

Determine: **package manager** (pnpm/npm/yarn), **build command**, **output directory** (dist/, build/, out/), **base path** (root `/` or subpath like `/pj/project-name/`).

## Step 2: Ask User Preferences

1. **Cloudflare Pages project name** (used in `--project-name`)
2. **Which workflows**: Main only, Main + PR previews, Main + PR + named previews
3. **Base path**: root `/` or specific subpath
4. **IFTTT notifications**: yes/no

## Step 3: Create Cloudflare Configuration

### wrangler.toml

```toml
# Cloudflare Pages project configuration

compatibility_date = "2024-12-01"
```

### Add wrangler devDependency

```bash
pnpm add -D wrangler  # or npm
```

For pnpm: add `esbuild` and `workerd` to `pnpm.onlyBuiltDependencies` in package.json.

### public/\_redirects (if using a base path)

If the site has a base path (e.g., `/pj/project-name/`), create `public/_redirects`:

```
/ /pj/project-name/ 302
```

Most static site generators (Astro, Next.js, etc.) copy `public/` to output, eliminating CI-time redirect generation.

## Step 4: Create Workflows

### Security Best Practices (apply to all workflows)

- **Explicit `permissions` blocks** (least privilege)
- **Pass `${{ }}` values via `env:` blocks**, never inline in `github-script` JavaScript (prevents script injection)
- **Quote all shell variable expansions**: `"${GITHUB_SHA}"`
- **Pin wrangler version**: `npm install -g wrangler@4` (or `pnpm exec wrangler` when node_modules available)
- **Add `timeout-minutes`** to all jobs (build: 15, deploy: 20, notify: 5)
- **Use `curl -sSf --max-time 10`** for external HTTP calls

### Deploy Retry (apply to all deploy steps)

Cloudflare Pages API occasionally returns transient errors (504 Gateway Timeout on `/upload-token`). Wrap all `wrangler pages deploy` commands in a bash retry loop:

```yaml
- name: Deploy to Cloudflare Pages
  run: |
    for attempt in 1 2 3; do
      echo "Deploy attempt $attempt/3..."
      if wrangler pages deploy deploy \
        --project-name=PROJECT_NAME \
        --branch=main \
        --commit-hash="${GITHUB_SHA}" \
        --commit-message="Production deploy: ${GITHUB_SHA}"; then
        echo "Deploy succeeded on attempt $attempt"
        exit 0
      fi
      if [ "$attempt" -lt 3 ]; then
        echo "Deploy failed, retrying in 150 seconds..."
        sleep 150
      fi
    done
    echo "Deploy failed after 3 attempts"
    exit 1
  env:
    CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
    CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
```

- **3 attempts, 150s (2.5 min) delay** between retries
- Increase `timeout-minutes` on deploy jobs to **20** (from 10) to accommodate retries
- For steps that set `GITHUB_OUTPUT` (preview URLs), move the output logic inside the success branch of the `if` block
- Works with both `npx wrangler@4` and `pnpm exec wrangler` variants

### Production Deploy (main-deploy.yml)

Trigger: push to `main`. Concurrency: `production-deploy`, cancel-in-progress: false.

```yaml
permissions:
  contents: read

jobs:
  build:
    # Heavy job — candidate for self-hosted runner via /dev-actions-self-runner
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      # fetch-depth: 0 if project needs git history (e.g., doc history, changelogs)
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20, cache: pnpm }
      - run: pnpm install --frozen-lockfile
      - run: pnpm build
      - uses: actions/upload-artifact@v4
        with: { name: dist-out, path: dist/, retention-days: 1 }

  deploy:
    needs: build
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - uses: actions/download-artifact@v4
        with: { name: dist-out, path: deploy/ }
      - run: npm install -g wrangler@4
      - name: Deploy to Cloudflare Pages (production)
        run: |
          for attempt in 1 2 3; do
            echo "Deploy attempt $attempt/3..."
            if wrangler pages deploy deploy \
              --project-name=PROJECT_NAME \
              --branch=main \
              --commit-hash="${GITHUB_SHA}" \
              --commit-message="Production deploy: ${GITHUB_SHA}"; then
              echo "Deploy succeeded on attempt $attempt"
              exit 0
            fi
            if [ "$attempt" -lt 3 ]; then
              echo "Deploy failed, retrying in 150 seconds..."
              sleep 150
            fi
          done
          echo "Deploy failed after 3 attempts"
          exit 1
        env:
          CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}

  notify: # Optional IFTTT notification
    needs: [build, deploy]
    if: always()
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - name: Notify via IFTTT
        if: env.IFTTT_PROD_NOTIFY != ''
        env:
          IFTTT_PROD_NOTIFY: ${{ secrets.IFTTT_PROD_NOTIFY }}
          RAW_COMMIT_MSG: ${{ github.event.head_commit.message }}
          BUILD_RESULT: ${{ needs.build.result }}
          DEPLOY_RESULT: ${{ needs.deploy.result }}
          GITHUB_SHA_VAL: ${{ github.sha }}
          SERVER_URL: ${{ github.server_url }}
          REPO: ${{ github.repository }}
          RUN_ID: ${{ github.run_id }}
        run: |
          if [ "$DEPLOY_RESULT" = "success" ]; then STATUS="succeeded"
          elif [ "$BUILD_RESULT" = "failure" ]; then STATUS="failed (build)"
          elif [ "$DEPLOY_RESULT" = "failure" ]; then STATUS="failed (deploy)"
          else STATUS="cancelled"; fi

          COMMIT_MSG=$(echo "$RAW_COMMIT_MSG" | head -1 | sed 's/"/\\"/g')
          SHORT_SHA=$(echo "$GITHUB_SHA_VAL" | cut -c1-7)
          RUN_URL="${SERVER_URL}/${REPO}/actions/runs/${RUN_ID}"

          curl -sSf --max-time 10 -X POST "$IFTTT_PROD_NOTIFY" \
            -H 'Content-Type: application/json' \
            -d "{
              \"value1\": \"Cloudflare Pages deploy ${STATUS}\",
              \"value2\": \"${SHORT_SHA} ${COMMIT_MSG}\",
              \"value3\": \"${RUN_URL}\"
            }" || echo "::warning::IFTTT notification failed"
```

### PR Preview Deploy (pr-checks.yml)

Trigger: pull_request to `main`. Concurrency: per-PR, cancel-in-progress: true.

```yaml
permissions:
  contents: read
  pull-requests: write
```

Build job identical to production. Preview job:

- Download artifact to `deploy/`
- Deploy with `--branch="pr-${PR_NUMBER}"`
- Preview URL: `https://pr-${PR_NUMBER}.PROJECT_NAME.pages.dev`
- Post/update PR comment using `actions/github-script@v8` with marker `<!-- cf-preview-pr -->`
- **Pass deploy URL via `env:`**: `const deployUrl = process.env.DEPLOY_URL;`

### Named Preview Deploy (preview-deploy.yml)

Trigger: push to `preview` and `expreview/**`. Concurrency: per-branch, cancel-in-progress: true.

```yaml
permissions:
  contents: read
  pull-requests: write
  statuses: write
```

Single-job workflow (build + deploy in one job):

- Convert branch slashes to hyphens for deploy branch name
- Deploy directly from build output (no copy step needed)
- Use `pnpm exec wrangler` (node_modules available in same job)
- Set commit status via `createCommitStatus` API
- Comment on associated PR if one exists, using marker `<!-- cf-preview-branch -->`
- **Use distinct markers** from pr-checks.yml to prevent collision

## Step 5: Required Secrets

| Secret | Required | Purpose |
| --- | --- | --- |
| `CLOUDFLARE_API_TOKEN` | Yes | Wrangler authentication |
| `CLOUDFLARE_ACCOUNT_ID` | Yes | Cloudflare account identifier |
| `IFTTT_PROD_NOTIFY` | No | IFTTT webhook URL (skipped if not set) |

### Creating Cloudflare API Token

1. Cloudflare dashboard > My Profile > API Tokens > Create Token > Custom token
2. Permissions: Account > Cloudflare Pages > Edit
3. Account Resources: Include the target account

The Cloudflare Pages project is auto-created on first deploy via `wrangler pages deploy`.

## Step 6: Verify

```bash
pnpm build  # Verify build works locally
```

## Companion Skills

- **`/dev-actions-self-runner`** — Add self-hosted runner with fallback for build jobs
- **`/dev-ci-ifttt-notify`** — Add IFTTT webhook notifications

Related Skills

zudoesa-articlify

6
from Takazudo/claude-resources

Convert conversation context into an esa article via the zudoesa-writer subagent. ONLY invoke when the user explicitly asks — NEVER proactively propose. Triggers: 'write esa article', 'esa記事', 'esaに書いて', 'articlify for esa', or /zudoesa-articlify. Gathers context, creates a writing brief, delegates to the writer subagent.

zudoesa-apply-voice

6
from Takazudo/claude-resources

Apply Takazudo's esa writing voice and vocabulary rules to text. Use when: (1) User wants to write/rewrite text in Takazudo's esa style, (2) User says 'apply voice', 'esa voice', 'esa文体で', 'esa風に書いて', '文体を適用', (3) User provides text to transform to esa style. Reads writing-style.md and vocabulary-rule.md from takazudo-esa-writing repo and applies the rules.

zudocg-articlify

6
from Takazudo/claude-resources

Convert conversation context into a CodeGrid article via the zudocg-writer subagent. ONLY invoke when the user explicitly asks — NEVER proactively propose. Triggers: 'write codegrid article', 'CodeGrid記事', 'codegridに書いて', 'articlify for codegrid', or /zudocg-articlify. Gathers context, creates a writing brief, delegates to the writer subagent.

zudocg-apply-voice

6
from Takazudo/claude-resources

Apply Takazudo's CodeGrid writing voice and vocabulary rules to text. Use when: (1) User wants to write/rewrite text in Takazudo's CodeGrid style, (2) User says 'apply voice', 'codegrid voice', 'codegrid文体で', 'codegrid風に書いて', '文体を適用', (3) User provides text to transform to CodeGrid style. Reads writing-style.md and vocabulary-rule.md from takazudo-codegrid-writing repo and applies the rules.

zpaper-articlify

6
from Takazudo/claude-resources

Convert conversation context into a zpaper blog article via the zpaper-writer subagent. ONLY invoke when the user explicitly asks — NEVER proactively propose. Triggers: 'write zpaper article', 'zpaper記事', 'zpaperに書いて', 'articlify for zpaper', or /zpaper-articlify. Gathers context, creates a writing brief, delegates to the writer subagent.

zpaper-apply-voice

6
from Takazudo/claude-resources

Apply Takazudo's zpaper blog writing voice and vocabulary rules to text. Use when: (1) User wants to write/rewrite text in Takazudo's zpaper style, (2) User says 'apply voice', 'zpaper voice', 'zpaper文体で', 'zpaper風に書いて', 'ブログ文体を適用', (3) User provides text to transform to zpaper style. Reads writing-style.md and vocabulary-rule.md from the zpaper repo and applies the rules.

xlsx

6
from Takazudo/claude-resources

Spreadsheet creation, editing, and analysis. Use when working with .xlsx, .xlsm, .csv, .tsv files for: (1) Creating spreadsheets with formulas and formatting, (2) Reading or analyzing data, (3) Modifying existing spreadsheets while preserving formulas, (4) Data analysis and visualization, (5) Recalculating formulas.

x

6
from Takazudo/claude-resources

Facade for development workflows. Routes on two axes: plan-first vs implement-now (escalates to /big-plan -a when the request needs research / decomposition / has unclear scope — the appended -a makes the plan chain into implementation in-session), then single vs multi on the ready-to-build fast paths (/x-as-pr single-topic, /x-wt-teams multi-topic parallel). Use when: (1) User says '/x' followed by dev instructions, (2) User wants to start development without choosing the workflow skill, (3) User says 'dev', 'implement', or 'build' with a task. Default option: -v (verify-ui). Review-loop (-l) is opt-in — without -l the downstream skill runs a single /deep-review pass. Forwards -a (autonomy/auto-chain) and -m (merge at the end + cleanup + CI watch) through every route; auto-fix of raised findings (-f) and issue-raising (-ri) are downstream defaults, with -nf/--no-fix and -nori/--no-raise-issues as the forwarded opt-outs. -a and -m are orthogonal — full hands-off end-to-end is -a -m.

x-wt-teams

6
from Takazudo/claude-resources

Parallel multi-topic development using git worktrees, base branches, and Claude Code agent teams. Use when: (1) User wants to work on multiple related features in parallel, (2) User mentions 'worktree', 'base branch', 'parallel development', 'split into topics', or 'multi-topic'. FULLY AUTONOMOUS — creates worktrees, spawns teams, coordinates everything. Also supports Super-Epic child mode for [Epic] issues from /big-plan with '**Super-epic:** #N' markers (targets the super-epic base branch instead of main).

x-as-pr

6
from Takazudo/claude-resources

Start a development workflow as a draft PR. Creates a NEW branch from the current branch, empty start commit, draft PR targeting the current branch, then implements. ALWAYS creates a new branch by default — produces a nested PR-on-PR when the current branch already has one. Use when: (1) User says 'dev as pr', (2) User wants a PR-first workflow before coding, (3) User passes -s/--stay to reuse the current branch instead of nesting, (4) User passes a GitHub issue URL to implement, (5) User passes --make-issue/--issue to create an issue first. Logs progress via issue comments when an issue is linked.

watch-ci

6
from Takazudo/claude-resources

Watch GitHub PR CI checks in the background and notify on completion. Use when: (1) User wants to monitor CI/CD status, (2) User says 'watch CI', 'check CI', 'monitor checks', or 'wait for CI', (3) User wants to know when checks pass or fail. Runs a background gh polling shell loop (NOT a subagent — near-zero token cost), sends macOS notification on completion. Also handles merged PRs by watching the target branch CI.

w-update-wording-rule

6
from Takazudo/claude-resources

Add or update wording rules (表記ルール) in the w repo's vocabulary-rule.md files. Use when: (1) User says 'add wording rule', 'update wording rule', '表記ルール追加', (2) User wants to add a kanji/hiragana usage rule, (3) User provides a rule like 'X should be Y' with examples.