Claude Code Skill

Say /deploy,
get a live website.

A skill for Claude Code that deploys static sites to Cloudflare Pages with custom domains. Git repo, DNS, SSL — all automated.

claude
$ claude
> /deploy
Loading website-deploy skill...
Claude What's the project name?
> myapp
✓ Created GitHub repo
✓ Deployed to Cloudflare Pages
✓ DNS configured + SSL provisioned
Claude Live at https://myapp.your-domain.com

Skill Files

Download these files and place them in ~/.claude/skills/website-deploy/

SKILL.md Required
Download
---
name: website-deploy
description: Deploy a static website to Cloudflare Pages with GitHub repo creation, subdomain configuration, and production deployment
disable-model-invocation: false
allowed-tools: Bash, Read, Write, Edit, Task, AskUserQuestion
---

# Website Deployment Skill

Deploy a static website to Cloudflare Pages with a custom subdomain.

## Configuration

All sensitive values are read from environment variables or a local config file.

### Required Environment Variables

| Variable | Description |
|---|---|
| `GITHUB_TOKEN` | GitHub personal access token (or `gh auth` session) |
| `CLOUDFLARE_API_TOKEN` | Cloudflare API token with Zone:DNS:Edit, Zone:Zone:Read, Account:Pages:Edit |
| `CLOUDFLARE_ACCOUNT_ID` | Cloudflare account ID |

### Required Config: `~/.claude/skills/website-deploy/config.env`

```bash
DEPLOY_GITHUB_ORG=your-github-org
DEPLOY_DOMAIN=your-domain.com
DEPLOY_CF_ZONE_ID=your-cloudflare-zone-id
```

Load config at the start of execution:
```bash
source ~/.claude/skills/website-deploy/config.env
```

## Pre-flight Checks

```bash
gh auth status
source ~/.zshrc && printenv CLOUDFLARE_API_TOKEN | wc -c  # should be 41
source ~/.claude/skills/website-deploy/config.env && echo "Org: $DEPLOY_GITHUB_ORG | Domain: $DEPLOY_DOMAIN"
```

All must succeed before proceeding.

## Execution Steps

### Step 1: Confirm Deployment Details

Use `AskUserQuestion` to gather:
1. **Project name**: Used for GitHub repo name, Cloudflare Pages project name, and subdomain
2. **Cloudflare account**: Only ask if `wrangler whoami` shows multiple accounts

Derive from project name:
- `$REPO_NAME` = project name
- `$PAGES_PROJECT_NAME` = project name (no dots allowed, use hyphens)
- `$SUBDOMAIN` = `$PROJECT_NAME.$DEPLOY_DOMAIN`

### Step 2: Initialize Git + Create GitHub Repo

```bash
cd $PROJECT_DIRECTORY
git init
gh repo create $DEPLOY_GITHUB_ORG/$REPO_NAME --private \
  --description "$DESCRIPTION" \
  --source=. --remote=origin
```

### Step 3: Verify Static Site Structure

Ensure these files exist in the project:
- `index.html` - Main entry point
- `styles.css` or `style.css` - Stylesheet (optional)
- `robots.txt` - SEO configuration (optional)
- `_headers` (optional) - Cloudflare Pages security headers
- `_redirects` (optional) - Cloudflare Pages URL redirects

### Step 4: Initial Commit and Push

```bash
git add .
git commit -m "feat: initial website deployment"
git push -u origin main
```

### Step 5: Deploy to Cloudflare Pages

```bash
npx wrangler pages project create $PAGES_PROJECT_NAME --production-branch=main
npx wrangler pages deploy . --project-name=$PAGES_PROJECT_NAME --branch=main
```

### Step 6: Configure Subdomain

Add a CNAME record via Cloudflare API:

```bash
python3 -c "
import urllib.request, json, os
token = os.environ['CLOUDFLARE_API_TOKEN']
zone_id = os.environ.get('DEPLOY_CF_ZONE_ID', '')
data = json.dumps({
    'type': 'CNAME',
    'name': '$PROJECT_NAME',
    'content': '$PAGES_PROJECT_NAME.pages.dev',
    'proxied': True, 'ttl': 1
}).encode()
req = urllib.request.Request(
    f'https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records',
    data=data, method='POST')
req.add_header('Authorization', f'Bearer {token}')
req.add_header('Content-Type', 'application/json')
resp = urllib.request.urlopen(req)
print(json.dumps(json.loads(resp.read()), indent=2))
"
```

Bind custom domain via Pages Domains API:

```bash
python3 -c "
import urllib.request, json, os
token = os.environ['CLOUDFLARE_API_TOKEN']
account_id = os.environ['CLOUDFLARE_ACCOUNT_ID']
data = json.dumps({'name': '$PROJECT_NAME.$DEPLOY_DOMAIN'}).encode()
req = urllib.request.Request(
    f'https://api.cloudflare.com/client/v4/accounts/{account_id}/pages/projects/$PAGES_PROJECT_NAME/domains',
    data=data, method='POST')
req.add_header('Authorization', f'Bearer {token}')
req.add_header('Content-Type', 'application/json')
try:
    resp = urllib.request.urlopen(req)
    print(json.dumps(json.loads(resp.read()), indent=2))
except urllib.error.HTTPError as e:
    print(f'Error {e.code}: {e.read().decode()}')
"
```

SSL is provisioned automatically by Cloudflare (Let's Encrypt).

### Step 7: Verification

```bash
dig $PROJECT_NAME.$DEPLOY_DOMAIN
curl -I https://$PAGES_PROJECT_NAME.pages.dev
curl -I https://$PROJECT_NAME.$DEPLOY_DOMAIN
```

### Step 8: Document Deployment

Create README.md with deployment info and update commands.
config.env Required
Download
DEPLOY_GITHUB_ORG=your-github-org
DEPLOY_DOMAIN=your-domain.com
DEPLOY_CF_ZONE_ID=your-cloudflare-zone-id

Setup Guide

1. Set environment variables

Add to ~/.zshrc or ~/.bashrc:

# GitHub (or just run: gh auth login)
export GITHUB_TOKEN="ghp_your_token"

# Cloudflare
export CLOUDFLARE_API_TOKEN="your_cf_api_token"
export CLOUDFLARE_ACCOUNT_ID="your_cf_account_id"

Cloudflare token permissions: Zone:DNS:Edit / Zone:Zone:Read / Account:Pages:Edit

2. Download and install skill files

Place the files you downloaded above into:

~/.claude/skills/website-deploy/
├── SKILL.md       # Skill logic (download above)
└── config.env     # Fill in your values (download above)

3. Edit config.env

Fill in your actual values:

DEPLOY_GITHUB_ORG=my-org          # your GitHub org or username
DEPLOY_DOMAIN=example.com        # your domain (managed by Cloudflare)
DEPLOY_CF_ZONE_ID=abc123...     # Cloudflare zone ID for the domain

Find your Zone ID in Cloudflare Dashboard → your domain → Overview → right sidebar.

4. Use it

# In Claude Code, type:
/deploy

Claude will ask for the project name, then handle everything: GitHub repo, Cloudflare Pages deploy, DNS, SSL.

What happens when you /deploy

1

GitHub repo

Creates a private repo, pushes all files.

2

Cloudflare Pages

Deploys to global CDN via Wrangler.

3

Custom domain

CNAME DNS + auto SSL via Let's Encrypt.

4

Verification

Checks DNS, HTTPS, writes README.

Requirements

Claude Code Anthropic's CLI for Claude
GitHub CLI (gh) Authenticated via gh auth login
Cloudflare account Free tier works. Need an API token.
Domain on Cloudflare DNS Your domain's DNS must be managed by Cloudflare.
Copied