deploy
/deploy
Wdraża aplikację crouton na staging Cloudflare Workers z automatycznym tworzeniem D1 i KV, synchronizacją identyfikatorów, migracjami i podpięciem CI; produkcja ma osobny skill.
- Autor
- friendlyinternet ↗
- Repozytorium
- nuxt-crouton ↗
- Licencja
- MIT
- Ostatnia zmiana repozytorium
- 27.10.2026
Ocena i bezpieczeństwo
- Pliki w paczce
- 1
- Skrypty
- 0
- Komentarze HTML
- 0
- Adresy URL w SKILL.md
- 0
Brak sygnałów. Repozytorium zmienione 27.10.2026, bez odwołań do wycofanych modeli i API.
MIT, otwarta: można używać i zmieniać, z zachowaniem informacji o autorze.
Co robi i kiedy
Wdraża aplikację crouton na staging Cloudflare Workers z automatycznym tworzeniem D1 i KV, synchronizacją identyfikatorów, migracjami i podpięciem CI; produkcja ma osobny skill.
Oryginalny opis (EN)
Deploy a crouton app to Cloudflare Workers STAGING (auto-provisioning) — the DEFAULT deploy, staging only, never production. Handles the staging bootstrap (auto-creates D1+KV, syncs ids, migrates), wiring CI, routine staging deploys, and Pages→Workers migration. For production use the separate /deploy-production skill. Use when deploying any app in apps/.
Jak działa
- Environment & domain convention (133)
- Usage
- Rules
- How the pipeline works (one source of truth)
- Workflow
- Migrating a Pages app → Workers
- Credentials
- Troubleshooting
- Deploy Learnings Location
Podgląd SKILL.md
---
name: deploy
layer: stack
description: Deploy a crouton app to Cloudflare Workers STAGING (auto-provisioning) — the DEFAULT deploy, staging only, never production. Handles the staging bootstrap (auto-creates D1+KV, syncs ids, migrates), wiring CI, routine staging deploys, and Pages→Workers migration. For production use the separate /deploy-production skill. Use when deploying any app in apps/.
allowed-tools: Bash, Read, Grep, Glob, Edit, Agent, AskUserQuestion
---
# Deploy Skill — Cloudflare Workers
Deploys a crouton app to **Cloudflare Workers (static assets)** — the crouton
deploy standard (#108). Wrangler **auto-provisions** the app's D1 + KV on the
first deploy, so there's no manual resource/project creation, no id-juggling.
> **🟦 STAGING ONLY — this skill never deploys to production.** "Deploy" defaults to
> **staging** here. Shipping to production is a deliberate, human-initiated action handled
> by the separate **`/deploy-production`** skill. Never deploy production as part of routine work.
> **Not Cloudflare Pages.** We do NOT use `wrangler pages …`, `pages_build_output_dir`,
> or the Pages "strip env" step anymore. If you find those, the app is on the old
> Pages path — see **Migrating a Pages app → Workers** below.
## Environment & domain convention (#133)
Two environments, two domains — kept on **separate registrable domains** so a
staging session can never authenticate against production (cookie isolation):
| Env | wrangler env | Worker | Domain |
|-----|--------------|--------|--------|
| **production** | top-level | `<app>` | `<app>.friendlyinter.net` |
| **staging** | `env.staging` | `<app>-staging` | `<app>.pmcp.dev` (public) |
The deploy-env is named **`staging`** (not `preview`): scripts are `cf:staging` /
`db:migrate:staging`, deploys use `--env staging`. (The general `crouton` CLI stays
domain-agnostic via `--domain <zone>`; the friendlyinter.net/pmcp.dev split is this
monorepo's convention, applied per app at its production cutover — #136 for triage.)
## Usage
```
/deploy # Deploy current app to STAGING (auto-detected from cwd)
/deploy velo # Deploy a specific app to STAGING
# production → use the separate /deploy-production skill
```
## Rules
1. **STAGING ONLY.** This skill deploys to **staging**, never production (that's the separate `/deploy-production` skill). Always confirm the target app first.
2. **Workers, not Pages** — `NITRO_PRESET=cloudflare_module`, output in `.output/`, deploy with `wrangler deploy` (never `wrangler pages deploy`).
3. **NEVER manually create D1/KV** — they auto-provision from the **id-less** `wrangler.jsonc` on first deploy. After provisioning, run `sync:ids` and **commit** the written-back ids (remote `d1 migrations apply` needs them — workers-sdk#13632).
4. **NEVER skip `nuxt prepare` before build** in CI — rolldown tsconfig bug. (Locally, the `cf:*` scripts assume `node_modules`/`.nuxt` are prepared from `pnpm install`.)
5. **`hub: { db: 'sqlite' }`** — never `hub: { database: true }`.
6. **`postinstall` must be guarded** — `nuxt prepare 2>/dev/null || true`, never bare (a bare prepare aborts the whole-monorepo install and fails every app's deploy).
## How the pipeline works (one source of truth)
The deploy logic lives in the app's **`package.json` scripts** — the same commands
you run locally and that CI runs. Don't reinvent them step-by-step:
- **`cf:deploy`** (production — run **only** via the `/deploy-production` skill): `build → wrangler deploy (auto-provision) → sync:ids → d1 migrations apply --remote`
- **`cf:staging`** (isolated staging env): `build → inject-wrangler-env → wrangler deploy --env staging → sync:ids → inject-wrangler-env → d1 migrations apply --env staging --remote`
- **`sync:ids`** — queries wrangler, writes provisioned ids back into `wrangler.jsonc`
- **`db:migrate` / `db:migrate:prod` / `db:migrate:staging`** — D1 migrations (local / remote / staging-remote)
A freshly scaffolded app (`crouton init`) already ships all of this:
`wrangler.jsonc` (id-less), `scripts/sync-wrangler-ids.mjs`,
`scripts/inject-wrangler-env.mjs`, `drizzle.config.ts`, the chained scripts, the
CF stubs + nitro aliases, and the guarded postinstall.
## Workflow
### Step 1: Detect app
- arg → `apps/{arg}/`; else if cwd is inside an app → that app; else ask.
- Verify it has `wrangler.jsonc` + `package.json`.
### Step 2: Pre-flight (run in parallel)
Confirm the app is Workers-ready:
1. **`wrangler.jsonc`** present, **Workers-style** (has `compatibility_flags: ["nodejs_compat"]`, `d1_databases`/`kv_namespaces`; **no** `pages_build_output_dir`).
2. **Scripts** `scripts/sync-wrangler-ids.mjs` + `scripts/inject-wrangler-env.mjs` exist.
3. **`drizzle.config.ts`** exists (so `db:generate` works).
4. **Package scripts** — `cf:deploy` is the Workers chain; `postinstall` is guarded.
5. **CF stubs** — `server/utils/_cf-stubs/` exists; `nuxt.config.ts` has `nitro.alias` for passkey/webauthn/papaparse stubs and pins **no** preset.
6. **Auth** — `CLOUDFLARE_ACCOUNT_ID` + `CLOUDFLARE_API_TOKEN` available in the environment (see **Credentials**).
If anything is missing and the app is on the old Pages setup → **Migrating a Pages app → Workers**. If it's just missing files, copy them from `apps/velo` (the reference) or re-run the scaffolder.
### Step 3: First (bootstrap) staging deploy
The id-less bindings auto-provision here. Confirm with the user, then deploy the
isolated **staging** environment (its own auto-provisioned D1+KV):
```bash
cd apps/{app}
pnpm cf:staging # provisions + deploys the *-staging worker, migrates --env staging
```
Then **commit the written-back ids** (bootstrap → committed):
```bash
git add apps/{app}/wrangler.jsonc && git commit -m "chore({app}): commit provisioned staging D1/KV ids"
```
> The **production** bootstrap (`cf:deploy`, prod D1+KV, `<app>.friendlyinter.net`) is a
> deliberate, separate step — see the **`/deploy-production`** skill. This skill stops at staging.
> If you're an agent **without Cloudflare egress** (sandbox), you can't run these —
> verify what's verifiable (config, `pnpm sync:ids --dry-run` logic) and have the
> user run the CF-gated steps, pasting output (the #109/#113/#114 loop).
### Step 4: Wire CI (opt in via `deploy.config.json`)
There is **one generic workflow for all apps** — `.github/workflows/deploy-apps.yml`
(#481/#638; the old per-app `deploy-<app>.yml` callers are retired — don't create one).
An app opts in by adding a `deploy.config.json` next to its `package.json`. **Model on
`apps/velo/deploy.config.json`.** Set: `stagingUrl`, `productionUrl` and `layerPackages`.
Do **not** write a `watchPaths` list: the workflow's `detect` job derives it from the app's
`package.json` — the app dir, the lockfile and every `@fyit/*` dependency, transitively
(#2397) — so adding a package to the app is enough. `watchPaths` is only for paths that
can't be derived (rare). `detect` then fans out one reusable `deploy-app.yml` call per
affected app. Merge to `main`/open a PR → isolated staging
with the URL commented on the PR; manual dispatch (app + environment inputs) →
production (#347). The fan-out uses `secrets: inherit`.
Ensure **repo-level** secrets `CLOUDFLARE_ACCOUNT_ID` + `CLOUDFLARE_API_TOKEN` exist
(Settings → Secrets and variables → Actions).
### Step 4.5: App (Worker) secrets
The app's own secrets (`BETTER_AUTH_SECRET`/`BETTER_AUTH_URL`, `NUXT_*`, etc.) live
on the **Worker**, NOT in `wrangler.jsonc`. **Worker secrets persist across deploys**,
so this is a one-time bootstrap per worker (prod + staging), not a per-deploy step.
Two ways:
- **Manual (one-time):** `npx wrangler secret bulk secrets.json` (prod) /
`… --env staging` (staging). `BETTER_AUTH_URL`/`BASE_URL` must be the **production
domain** (not localhost). Pages secrets do NOT carry over — re-provide the values.
- **Automatic (CI):** store the whole bundle as a **repository-level** Actions secret
`WORKER_SECRETS_JSON` (a JSON object of `{ "NAME": "value", … }`). It MUST be
repo-level, NOT an Environment secret — the deploy job is reached via
`secrets: inherit` from caller jobs that declare no `environment:`, so an
Environment-scoped secret resolves EMPTY with no error and the Worker deploys
without secrets (#1094). The reusable `deploy-app.yml` runs `wrangler secret bulk`
from it on every deploy (`--env staging` for non-prod). Omit it to manage secrets
manually. If the app depends on the bundle, set `"secrets": { "required": true }`
in its `deploy.config.json` — an empty resolution then FAILS the deploy instead
of silently skipping. Automation can't invent values — they must live in that
secret once.
### Step 5: Routine deploys (staging)
- **CI (preferred):** merge to `main` (or open a PR) → the caller runs the staging pipeline (#347).
- **Local:** `pnpm cf:staging` from the app dir.
- **Production is never routine** — ship it deliberately via the **`/deploy-production`** skill.
### Demo data on staging (#2366)
Every **staging** and PR-preview deploy runs `crouton-seed` itself, once (the *Seed collection + demo data* (#1370)
step in `deploy-app.yml`), so the app gets its packages' demo data and the `test1` team the
review login joins — **no seed line in the app's `cf:staging` script**. The app only needs
`@fyit/crouton-cli` as a dependency. Opt out with `"seed": false` in `deploy.config.json`.
A failed seed warns on the run; it never fails the deploy. Production never seeds.
### Apps without a database or sign-in (#2377)
A standalone viewer (e.g. `pocs/loop-station`: no NuxtHub, no D1, no auth) deploys through the
same pipeline: the PR preview skips the D1 provision/migrate when the built config declares no
database, and `"reviewLogin": false` in `deploy.config.json` skips the review login + email and
turns the smoke into a plain "page answers 200" check. Without NuxtHub, set
`nitro.cloudflare.deployConfig: true` so the build writes `.output/server/wrangler.json`, which the
PR preview rewrites. Put any pre-build data step in a `build:before` hook, not only in `package.json`
scripts — the PR preview runs a bare `nuxt build`.
### Auto-seeded review login on staging previews (#608)
Every **staging** deploy auto-seeds a throwaway, loginable test account on the
preview's isolated D1 so a reviewer can open the URL and be **inside the app in one
step** — no register → create-team wall. `deploy-app.yml` runs
`scripts/seed-review-login.mjs` against the deployed Worker (the app's own
`/api/auth/sign-up/email` + a team via `organization/create` when the app doesn't
auto-make one). The PR's staging comment only says the login exists — the password
and the one-click sign-in link (which carries it) are **emailed to the owner** (Resend;
`vars.REVIEW_LOGIN_EMAIL`, else `vars.DIGEST_REPORT_EMAIL`), never posted: PR comments
and run summaries are public on this repo (#2358). Creds are **deterministic per
preview** (redeploys reuse the same login, no user pile-up), derived from the
**required** repo secret `REVIEW_SEED_SECRET` — no fallback salt; unset → no review
login. A rotated secret resets the existing account's password on the next deploy.
The step is best-effort (never fails the deploy); **production seeds nothing**.
## Migrating a Pages app → Workers
For an app still on the Pages setup (`wrangler.toml`, `pages_build_output_dir`,
`wrangler pages deploy`):
1. **`wrangler.toml` → `wrangler.jsonc`** in the Workers shape (see `apps/velo`):
drop `pages_build_output_dir`; keep `name`/`compatibility_*`; `d1_databases` (reuse
the existing prod `database_id`), `kv_namespaces`; add an `env.staging` block with a
**separate** `{app}-staging-db` + KV (id-less to auto-provision, or existing staging ids).
2. **Add** `scripts/sync-wrangler-ids.mjs`, `scripts/inject-wrangler-env.mjs`,
`drizzle.config.ts` (copy from `apps/velo`).
3. **package.json** — replace the Pages `cf:*` scripts with the Workers chain
(`NITRO_PRESET=cloudflare_module`, `sync:ids`, `db:migrate:staging`); keep the
guarded `postinstall`.
4. **nuxt.config.ts** — remove `nitro.preset: 'cloudflare-pages'` (keep the `nitro.alias` stubs).
5. **CI** — replace `deploy-{app}.yml` (+ any `-preview.yml`) with the thin caller from Step 4; delete the Pages strip-env step (not needed on Workers).
6. **Deploy + commit ids** as in Step 3.
## Credentials
The job/shell needs **`CLOUDFLARE_ACCOUNT_ID`** + **`CLOUDFLARE_API_TOKEN`**.
- **`CLOUDFLARE_ACCOUNT_ID`** — dashboard → Workers & Pages → Account ID (also the hex in the dashboard URL). Not secret.
- **`CLOUDFLARE_API_TOKEN`** — My Profile → API Tokens → **Create Custom Token**. For Workers + **auto-provisioning** the token needs (Account-scoped):
- **Workers Scripts: Edit**
- **D1: Edit**
- **Workers KV Storage: Edit**
- (**Workers R2 Storage: Edit** if the app uses blob)
Cloudflare shows a token's value **only once**, and GitHub never reveals a saved
secret — so mint a fresh dedicated token rather than reusing one.
> Note: this differs from the old Pages token (which used *Cloudflare Pages: Edit*).
> A Pages-only token will fail to auto-provision D1/KV.
## Troubleshooting
### `Couldn't find a D1 DB … missing database_id` (on migrate)
The first deploy provisioned the DB but the id isn't in `wrangler.jsonc` yet. Run
`pnpm sync:ids` (after a deploy) and commit the result. `cf:deploy`/`cf:staging` do
this automatically.
### `Configuration file does not support "env"` / redirected config rejects env
Wrangler 4.64+ rejects `env` in a *redirected* config. `scripts/inject-wrangler-env.mjs`
(run by `cf:staging`) re-injects `env` into `.output/server/wrangler.json` and removes
the redirect so `--env staging` deploys read it directly. No manual strip step.
### `papaparse` RollupError / passkey/tsyringe errors
Add the CF stubs + `nitro.alias` (see scaffolder output / `apps/velo`).
### KV namespace not found by `sync:ids`
It matches the auto-provisioned title `<worker-name>-<binding>` (e.g.
`{app}-KV`, `{app}-staging-KV`). The script logs the available titles if no match —
adjust only if your account names them differently.
### Build OOM
Set `NODE_OPTIONS='--max-old-space-size=8192'` (CI sets this).
## Deploy Learnings Location
Per-app deploy gotchas: `docs/projects/{app}/{app}-deploy.md`. Append new fixes there.
Reference implementation for everything above: **`apps/velo`**.
Wersje
| Repozytorium | Wynik | Licencja |
|---|---|---|
| Ta strona · friendlyinternet/nuxt-crouton | 100 | MIT |
| jeremylongshore/tons-of-skills-marketplace | 100 | MIT |
| zeitlos/lucity | 100 | AGPL-3.0 |
| microsoft/power-platform-skills | 100 | MIT |
| jikig-ai/soleur | 100 | Apache-2.0 |
| curiositech/windags-skills | 100 | Apache-2.0 |
| shakestzd/htmlgraph | 100 | MIT |
| microsoft/power-platform-skills | 100 | MIT |
| jazzyalex/agent-sessions | 100 | MIT |
Migawka bazy z 28.10.2026 · wersja paczki 00428758d716 (skrót SHA-256 całej paczki)
Pobrania w ostatnich 30 dniach: 0 · ranking
Zgłoś problem z tym skillem: szkodliwa treść, błędny opis albo prośba autora o usunięcie.
Podobne skille
- 100cloudflare
Wdraża aplikację Vibes na Cloudflare Workers przez Deploy API. - 100cloudflare-deploy
Wdraża aplikacje i infrastrukturę na Cloudflare przez Workers, Pages i powiązane usługi platformy. - 95Cloudflare
Wdraża aplikacje Workers i Pages w Cloudflare i wskazuje, gdzie szukać dokumentacji. - 100cloudflare-deploy
Wdraża aplikacje i infrastrukturę na Cloudflare z użyciem Workers, Pages i powiązanych usług platformy. - 100crouton-ci-and-deploy-map
Przedstawia mapę workflowów GitHub i potoku wdrożeniowego nuxt-crouton: co bramkuje każdy workflow, jak merge trafia na Cloudflare i gdzie są sekrety. - 100cloudflare-deploy
Wdraża aplikacje i infrastrukturę na Cloudflare z użyciem Workers, Pages i powiązanych usług platformy.