Monorepo bootstrap
A filesystem contract (.workflow/meta.json) + 37 agent skills that take a product from idea to production: web (Next.js 16) & mobile (Expo/RN), plus an eve agent engine and Linear/scrum. Runs on Claude Code, Codex, Copilot, Gemini, Cursor.
npx -y skills add lukedj78/dev-flow --skill monorepo-bootstrapAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Scaffold a turborepo monorepo, with shared packages (types, design tokens or shared UI, backend client). Uses pnpm workspaces + turborepo. Reads .workflow/meta.json with stack.framework="monorepo" and phase in {prd_drafted, design_extracted}. Supports three topologies, detected/asked in Step 1: web+mobile (Next.js web app AND an Expo + RN mobile app — the classic case), web+agent (Next.js web app + an eve agent in apps/agent, no mobile), or web-only (just the turborepo/shared-package tooling around one web app). Produces: root package.json + pnpm-workspace.yaml + turbo.json + packages/typescript-config + packages/eslint-config; apps/web/ scaffolded via design-md-to-app; apps/mobile/ scaffolded via rn-bootstrap ONLY for the web+mobile topology; packages/shared/ + packages/api/ skeletons, plus packages/design/ (web+mobile) or packages/ui/ (web-only / web+agent, shadcn monorepo layout). Always idempotent. Use when dev-flow routes here from prd_drafted+monorepo, or the user says "scaffolda il monorepo", "create a turborepo with web + mobile", "bootstrap il monorepo da PRD + DESIGN.md", "scaffolda un turborepo per web + agent eve". Not for: scaffolding only web with no monorepo tooling (use design-md-to-app), scaffolding only mobile (use rn-bootstrap), adding modules after scaffold (use module-add or rn-module-add).
SKILL.md
15.3 KB, as published. Nobody here has run it
monorepo-bootstrap — scaffold a turborepo monorepo
Contract
See references/contracts.md (vendored from dev-flow). Key facts:
- Reads
<project-root>/.workflow/meta.json#stack.framework— must be"monorepo". - Requires
meta.json#phasein{prd_drafted, design_extracted}. - Reads
PROJECT.md,PRD.md, andDESIGN.mdfrom project root (DESIGN.md required for tokens; falls back to defaults if absent). - Writes the monorepo at project root:
apps/{web,mobile}/,packages/{shared,design,api}/, root config files. - Transitions phase:
prd_drafted→monorepo_initialized(root scaffold done) →scaffolded(both apps + packages exist). - Always idempotent: re-running detects existing files, skips, reports.
When this skill applies
- Orchestrator routes here from
dev-flowwhenstack.framework="monorepo"andphase ∈ {prd_drafted, design_extracted}. - User says: "scaffolda il monorepo", "create a turborepo", "bootstrap il monorepo".
Knowledge dependencies (read these first)
rn-fundamentals/SKILL.md— Expo SDK + New Architecture + TS for the mobile side (web+mobile topology only).rn-bootstrap/SKILL.md— how the mobile side is scaffolded; this skill invokes it ONLY for the web+mobile topology.rn-styling/references/nativewind-setup.md— for the mobile Tailwind config (web+mobile topology only).design-md-to-app/SKILL.md— how the web side is scaffolded; this skill invokes it in every topology.design-md-to-app/references/<lib>-mapping.md— based onstack.monorepo.web.ui.design-md-to-app/references/shadcn-mapping.md→ "Monorepo (sharedpackages/ui)" — the shadcn monorepo layout used for the web-only / web+agent topologies.eve-agent/SKILL.md— scaffoldsapps/agent/for the web+agent topology; this skill does NOT build the agent itself, only the surrounding workspace.references/decision-tree.md→ "Thepackages/uirule" — which topology getspackages/designvspackages/ui.references/structure.md— full monorepo layout (this file lives in this skill's references).references/patterns.md— turborepo conventions, pnpm protocols.
Workflow
Step 1 — Verify preconditions and detect the topology
Read .workflow/meta.json. Abort with clear message if:
stack.framework != "monorepo"→ "Wrong stack. For mobile-only use rn-bootstrap; for web-only with no monorepo tooling use design-md-to-app directly."phase ∉ {prd_drafted, design_extracted, monorepo_initialized}→ "Expected phase prd_drafted/design_extracted/monorepo_initialized, got X."stack.monorepo.web.frameworkmissing → ask user (default:"next").stack.monorepo.web.uimissing → ask user (default:"shadcn").
Detect or ask the topology — every later step branches on this, most importantly Step 5:
- If
stack.monorepo.mobileis already populated inmeta.json→ topology ="web-mobile". - Else if
stack.agent == "eve", or the user has said they want an agent engine and no mobile app → topology ="web-agent". - Else if the user has explicitly said there is no mobile app and no agent (monorepo wanted only for shared-package tooling, future multi-web-app plans, etc.) → topology =
"web-only". - Else ask the user directly: "Is this monorepo web + mobile, web + an eve agent, or web-only?" Do not default to web+mobile — v1 of this skill assumed it silently, which is exactly the bug this step fixes.
Write the answer to meta.json#stack.monorepo.topology ("web-mobile" | "web-agent" | "web-only") so Step 5 (and any later re-run) doesn't have to re-derive it.
For topology "web-mobile" only, also resolve:
stack.monorepo.mobile.frameworkmissing → set to"expo-rn"(only valid value for v1).stack.monorepo.mobile.ui→ set to"nativewind"(only valid value).
For "web-agent" / "web-only", do NOT create a stack.monorepo.mobile key at all — its mere presence is what Step 5 uses as the mobile signal in idempotent re-runs.
If apps/ + packages/ + pnpm-workspace.yaml already exist at project root: print "Already initialized at phase X, skipping root scaffold" and proceed to Step 4.
Step 2 — Scaffold the root
Run scripts/init-monorepo.sh <project-root> <project-slug>:
- Writes
pnpm-workspace.yamllistingapps/*andpackages/*. - Writes
turbo.jsonwith the pipeline definition (build/dev/lint/test/typecheck). - Writes root
package.jsonwith name@<project-slug>/root, scripts that proxy to turbo. - Writes
packages/typescript-config/withbase.json(path aliases, strict mode),nextjs.json,react-native.jsonpreset extensions. Also writespackages/eslint-config/. Notsconfig.base.jsonin repo root — Turborepo official pattern. - Creates empty dirs:
apps/web/,apps/mobile/,packages/shared/,packages/design/,packages/api/.
Update meta.json:
stack_config.monorepo_tool = "turborepo"stack_config.workspace_pm = "pnpm"stack_config.shared_packages = [](filled by Step 6)phase = "monorepo_initialized"
Step 3 — Scaffold the shared design/UI package from DESIGN.md
Branch by topology (see Step 1 → stack.monorepo.topology, and references/decision-tree.md → "The packages/ui rule"):
Topology "web-mobile" → packages/design/ (tokens + Tailwind flavors, no components — components can't cross the React-DOM/React-Native boundary):
src/tokens.ts— parses.workflow/DESIGN.mdjson tokensblock, emits typed JS object.theme.css— an@themeblock built from the tokens. This is how the web app (Tailwind v4, whichcreate-next-app@16 --tailwindinstalls) consumes the tokens:apps/web/app/globals.cssdoes@import "@<slug>/design/theme.css";. Tailwind v4 is CSS-first and has no JSpresetsmechanism.src/tailwind-preset.ts— a v3-style JS preset, exported only as a fallback for a web app still on Tailwind v3 (scaffold-web.sh --patchauto-detects:tailwind.config.*present → patch this preset; absent → v4@importpath above).src/nativewind-preset.ts— exports a NativeWind preset (Tailwind 3.4 syntax) for mobile (NativeWind still tracks the v3 config shape).package.jsonwith name@<project-slug>/design, exports./tokens,./theme.css,./tailwind(v3 fallback),./nativewind.tsconfig.jsonextending@<slug>/typescript-config/<preset>.json(e.g.,nextjs.jsonfor apps/web,react-native.jsonfor apps/mobile).
This package is published as workspace:* to both apps.
Topology "web-agent" or "web-only" → packages/ui/ instead, following shadcn's official monorepo layout (@workspace/ui), NOT packages/design/. Defer the actual scaffold to design-md-to-app's shadcn init --monorepo flow in Step 4 (design-md-to-app/references/shadcn-mapping.md → "Monorepo (shared packages/ui)"); this step just reserves the empty packages/ui/ slot so Step 6/7 don't collide with it. packages/design/ does not exist in this topology — the tokens live in packages/ui/src/styles/globals.css.
Step 4 — Scaffold apps/web/ via design-md-to-app
Invoke design-md-to-app with:
- cwd =
<project-root>/apps/web/ - DESIGN.md path =
<project-root>/.workflow/DESIGN.md - stack.ui =
meta.json#stack.monorepo.web.ui(e.g. "shadcn") - Special instruction, topology
"web-mobile": in the generatedtailwind.config.js, thepresetsarray MUST includerequire("@<project-slug>/design/tailwind")— this is how the design tokens reach the web app. - Special instruction, topology
"web-agent"/"web-only": telldesign-md-to-appto use its shadcn monorepo mode (shadcn init --monorepo) targeting thepackages/ui/slot reserved in Step 3, instead of the single-appcomponents/ui/layout. - Skip the
/showcaseroute's auto-creation if user already wants minimalist setup; otherwise letdesign-md-to-appcreate it as normal.
Update meta.json#stack.monorepo.web with any user choices recorded by design-md-to-app.
Step 5 — Scaffold apps/mobile/ via rn-bootstrap (topology "web-mobile" only)
Check meta.json#stack.monorepo.topology first. If it is "web-agent" or "web-only" (or stack.monorepo.mobile is simply absent), skip this step entirely — do not create apps/mobile/, do not invoke rn-bootstrap, and do not generate a NativeWind preset (there is no packages/design/ in these topologies — see Step 3). Proceed straight to Step 6.
For topology "web-agent" specifically: apps/agent/ is scaffolded by invoking eve-agent in Scaffold mode instead, once the workspace root exists — that skill owns everything under apps/agent/; this skill's job stops at making sure pnpm-workspace.yaml / turbo.json already cover apps/* so eve-agent slots in without extra wiring.
Otherwise (topology "web-mobile"), invoke rn-bootstrap with:
- cwd =
<project-root>/apps/mobile/ - DESIGN.md path =
<project-root>/.workflow/DESIGN.md - Special instruction: the generated
tailwind.config.jsMUST includepresets: [require("@<project-slug>/design/nativewind")]so the design tokens reach the mobile app.
Update meta.json#stack.monorepo.mobile with any choices.
Step 6 — Scaffold packages/shared/ skeleton
Create minimal scaffold:
src/index.ts— barrel export.src/types/.gitkeep,src/validators/.gitkeep,src/utils/.gitkeep.package.jsonwith name@<project-slug>/shared, main./src/index.ts.tsconfig.jsonextending base.
Update meta.json#stack_config.shared_packages: ["@<project-slug>/shared", "@<project-slug>/design", "@<project-slug>/api"] for topology "web-mobile", or ["@<project-slug>/shared", "@<project-slug>/ui", "@<project-slug>/api"] for "web-agent" / "web-only" (see Step 3).
Step 7 — Scaffold packages/api/ skeleton
Create minimal scaffold (a wrapper that will be filled by module-add later):
src/index.ts— barrel.src/client.ts— placeholder for the backend client (Supabase / tRPC, decided whenauthmodule is added).package.jsonwith name@<project-slug>/api.tsconfig.jsonextending base.
Don't install the actual backend client here — that's module-add / rn-module-add's job. Just the skeleton.
Step 8 — Install dependencies + verify
Run from project root:
pnpm install --recursive
Then verify:
pnpm tsc --noEmitfromapps/web/, fromapps/mobile/(topology"web-mobile"only), and eachpackages/*/succeeds.pnpm turbo dev --dry-runlists every workspace that exists for the chosen topology (5 for"web-mobile": web, mobile, and the 3 packages; 4 for"web-agent"/"web-only": web, and the 3 packages —apps/agent/joins later onceeve-agentscaffolds it).
If any verify fails, do NOT bump phase. Report and stop.
Step 9 — Update meta.json + commit
{
"stack": { "framework": "monorepo", "monorepo": { "topology": "web-mobile", "web": {...}, "mobile": {...} }, ... },
"stack_config": {
"monorepo_tool": "turborepo",
"workspace_pm": "pnpm",
"shared_packages": ["@<project-slug>/shared", "@<project-slug>/design", "@<project-slug>/api"]
},
"phase": "scaffolded",
"history": [..., {"skill": "monorepo-bootstrap", "ran_at": "<iso>", "outputs": [...]}]
}
For topology "web-agent" / "web-only", stack.monorepo has no mobile key and shared_packages lists @<project-slug>/ui instead of @<project-slug>/design (see Step 3/Step 6).
If git repo: commit with chore: scaffold monorepo (web + mobile + shared packages) for "web-mobile", or chore: scaffold monorepo (web + shared packages, <topology> topology) otherwise.
Common anti-patterns (NEVER do)
- ❌ Try to use yarn or npm workspaces instead of pnpm — turborepo + Expo officially support pnpm best.
- ❌ Generate Tailwind config in
apps/web/without the@<project-slug>/design/tailwindpreset (topology"web-mobile") — design tokens won't reach the web app. - ❌ Generate
tailwind.config.jsinapps/mobile/without the nativewind preset — same problem mirrored. - ❌ Install backend client (supabase-js, tRPC) at root — must live in
packages/api/, consumed via workspace protocol. - ❌ Add
tsconfig.base.jsonin repo root — Turborepo recommends per-package configs that extend a shared package (packages/typescript-config). Don't centralize in root. - ❌ Use
framework="monorepo"on a project that already has scaffolded code (mid-project switch) — this skill is for fresh projects only. - ❌ Assume the topology is always
"web-mobile"and blindly invokern-bootstrap— Step 1 must detect/ask the topology first; Step 5 skipsrn-bootstrapentirely for"web-agent"/"web-only". This was v1's bug: it always scaffoldedapps/mobile/even for mobile-less projects. - ❌ Create both
packages/design/ANDpackages/ui/in the same project — they are mutually exclusive per topology (Step 3).
Updating meta.json (recommended pattern)
When this skill modifies state (artifact written, phase advanced, history appended), use the canonical script when available:
# Wherever dev-flow is installed (e.g. ~/.claude/skills/dev-flow/), invoke:
python3 .../dev-flow/scripts/update_meta.py <project-root> record-artifact \
--path <relative-path> --produced-by 'monorepo-bootstrap' [--derived-from <p1> <p2> ...]
python3 .../dev-flow/scripts/update_meta.py <project-root> set-phase <new_phase>
python3 .../dev-flow/scripts/update_meta.py <project-root> append-history \
--skill 'monorepo-bootstrap' --inputs '{...}' --outputs '{...}' --phase-after <new_phase>
The script enforces phase monotonicity, normalizes legacy kebab-case aliases (e.g. module-added → module_added), and writes the canonical sha256 + timestamp into meta.json#artifacts. Fall back to direct JSON editing only if the script is not on PATH (and warn the user).
Sources
- Spec:
docs/superpowers/specs/2026-05-29-monorepo-set-design.md - Official: https://turborepo.dev/docs
- Official: https://pnpm.io/workspaces
- Official: https://docs.expo.dev/guides/monorepos/
- Course: codewithbeto.dev/rnCourse — (no direct monorepo coverage; assembled from official sources).