| name | project-init |
| description | Personalizes a fork of this Cloudflare multi-worker monorepo—Alchemy application ids (`await alchemy` literals + `--app`), npm workspace names (`--filter`), README, and UI—so Cloudflare dashboards and Turbo filters are not confusing. Use when the user created a repo from the template, wants to deploy their own app, or asks to rename workers, rebrand, or remove generic starter kit copy. **Skip** when `origin` matches root **`package.json`** **`repository.url`** (canonical template maintenance) unless the user explicitly asks. |
Project initialization (personalize your fork)
Use this skill when someone is building their app on top of this starter kit—not when maintaining the canonical template (see project-init.mdc: compare origin with root repository.url).
Guard: If you are on the canonical template checkout, do not run this flow unless the user explicitly requests renaming or templating work.
Note — infra naming is code-first
- Set
PRODUCT_PREFIX once in worker-peer-scripts.ts (ALCHEMY_APP_IDS derives each Alchemy appId).
deploy / destroy / dev scripts use the alchemy-cli workspace bin with alchemy.app in each package.json — don’t duplicate --app strings by hand.
- Keep
await alchemy("…") literals in each alchemy.run.ts aligned with that table, then bun run typegen.
- Worker branding lives in TypeScript, not env vars. See multiworker-workflow and multiworker-gotchas.
Adding a DO package or worker binding after fork setup — use the small focused skills, not one giant doc:
1. Gather information
Ask the user (or infer from context):
- Product slug / prefix — short literal used in
alchemy("myslug-frontend") style (not $VAR + "-frontend"). Example: skybook → skybook-frontend, skybook-database, … (see root README — Name your product → Code-first infra names).
- Workspace package names (
package.json name) — often skybook-web, skybook-db, … — separate from Alchemy --app — used mainly for turbo run … --filter=….
- One-line description — README, meta tags, home hero copy.
- Chatroom DO —
durable-objects/chatroom-do; web binds ChatroomDo; internal secret CHATROOM_INTERNAL_SECRET (already in env flows).
- D1 —
packages/db + optional D1_DATABASE_NAME / D1_DATABASE_ID in .env.local / .env.production for remote/local debugging; ALCHEMY_APP_IDS.database (packages/db/alchemy.run.ts) drives migrations (alchemy-cli --stage prod deploy from packages/db, etc.).
2. Code-first Alchemy ids and Workers
- Each deployable
alchemy.run.ts has one await alchemy(<appId>, { … }); STAGE comes from alchemy-cli --stage (or CI STAGE).
alchemy("…") must match ALCHEMY_APP_IDS for that package (frontend, chatroom, …).
alchemy-cli resolves alchemy dev|deploy|destroy --app … from package.json → alchemy.app (same keys as ALCHEMY_APP_IDS) — avoid extra hard-coded --app strings that can drift.
Where PRODUCT_PREFIX drives ids
ALCHEMY_APP_IDS + PRODUCT_PREFIX — Canonical Alchemy appId strings. package.json → alchemy.app uses those keys (frontend, chatroom, ping, other, database, stateHub, admin) plus arbitrary suffix segments for ${PRODUCT_PREFIX}-<suffix> (generator-created DO packages). Forks change PRODUCT_PREFIX once.
| Package folder | Typical appId (PRODUCT_PREFIX = starter) | Turbo --filter uses workspace name (starter) |
|---|
apps/web | starter-frontend (ALCHEMY_APP_IDS.frontend) | @internal/web |
durable-objects/chatroom-do | starter-chatroom | chatroom-do |
durable-objects/ping-do | starter-ping | ping-do |
durable-objects/other-worker | starter-other | other-worker |
packages/db | starter-database | @internal/db |
packages/state-hub | ${PRODUCT_PREFIX}-state-hub (ALCHEMY_APP_IDS.stateHub) | state-hub |
- Resource ids (short):
Worker(DEFAULT_WORKER_RESOURCE_ID) with DEFAULT_WORKER_RESOURCE_ID = "worker"; ReactRouter uses DEFAULT_REACT_ROUTER_WEB_RESOURCE_ID ("web"); D1 D1Database(DEFAULT_D1_DATABASE_RESOURCE_ID) with db. Omit explicit name: so Cloudflare script names derive from ${alchemyAppId}-${resource}-${stage}.
- Cyclic stubs (
ping-do ↔ other-worker): omitDefaultPhysicalWorkerScriptName(<peer-alchemy-app>, app.stage) feeds WorkerRef.service / WorkerStub.name, matching omit-default Worker("worker") physical names — see cf-worker-rpc-turbo.
Cross-package consumers still import provider ./alchemy exports (hub bindings from web). className on DurableObjectNamespace must match your TS exported class (PingDo…).
After edits: bun run typegen from the repo root. env.d.ts reflects exported ./alchemy.
3. Package names (package.json)
- Root
package.json: set "name" to the fork project slug (replaces cloudflare-multiworker-template).
apps/web/package.json: set "name" (e.g. my-saas-web) — Turbo filter usage; add "alchemy": { "app": "frontend" } (id still matches alchemy.run.ts + ALCHEMY_APP_IDS.frontend …).
- Each DO/worker
package.json: alchemy.app must match ALCHEMY_APP_IDS ↔ alchemy("…") in alchemy.run.ts; deploy/destroy/dev run alchemy-cli --stage ….
packages/state-hub: alchemy.run.ts stays on ALCHEMY_APP_IDS.stateHub; alchemy.app is stateHub and scripts use alchemy-cli --stage … (provision-only shared Cloudflare Alchemy state for non-local STAGE).
workspace:* dependencies: If you rename a workspace package (chatroom-do folder / name), update every consumer and bun install.
4. README
Rewrite README.md for the product:
- Title, description,
bun install, bun run dev, bun run deploy:prod (and deploy:staging / deploy:preview as needed).
- Update or shorten template links/marketing unless you keep attribution.
- Keep CI, scripts,
ALCHEMY_PASSWORD/CHATROOM_INTERNAL_SECRET — cf-workers-env-local.
- Mention liter Alchemy
--app IDs (starter-* (with your PRODUCT_PREFIX) → your slug) alongside **workspace **name****.
5. UI and meta copy
6. CONTRIBUTING
7. Optional: grep / nested docs
Search for cloudflare-multiworker-template, your-org/cloudflare-multiworker-template, old alchemy("web") / alchemy("ping-do") if any remain. Nested READMEs under apps/web, durable-objects/*.
8. Verification
bun run typegen
bun run typecheck
bun run lint
bun run build
Fix any failures before considering initialization complete.