Pulled ALL skills from 15 source repositories: - anthropics/skills: 16 (docs, design, MCP, testing) - obra/superpowers: 14 (TDD, debugging, agents, planning) - coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth) - better-auth/skills: 5 (auth patterns) - vercel-labs/agent-skills: 5 (React, design, Vercel) - antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo) - Plus 13 individual skills from various repos Mosaic Stack is not limited to coding — the Orchestrator and subagents serve coding, business, design, marketing, writing, logistics, analysis, and more. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
4.9 KiB
4.9 KiB
Repository Structure
Detailed guidance on structuring a Turborepo monorepo.
Workspace Configuration
pnpm (Recommended)
# pnpm-workspace.yaml
packages:
- "apps/*"
- "packages/*"
npm/yarn/bun
// package.json
{
"workspaces": ["apps/*", "packages/*"]
}
Root package.json
{
"name": "my-monorepo",
"private": true,
"packageManager": "pnpm@9.0.0",
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev",
"lint": "turbo run lint",
"test": "turbo run test"
},
"devDependencies": {
"turbo": "latest"
}
}
Key points:
private: true- Prevents accidental publishingpackageManager- Enforces consistent package manager version- Scripts only delegate to
turbo run- No actual build logic here! - Minimal devDependencies (just turbo and repo tools)
Always Prefer Package Tasks
Always use package tasks. Only use Root Tasks if you cannot succeed with package tasks.
// packages/web/package.json
{
"scripts": {
"build": "next build",
"lint": "eslint .",
"test": "vitest",
"typecheck": "tsc --noEmit"
}
}
// packages/api/package.json
{
"scripts": {
"build": "tsc",
"lint": "eslint .",
"test": "vitest",
"typecheck": "tsc --noEmit"
}
}
Package tasks enable Turborepo to:
- Parallelize - Run
web#lintandapi#lintsimultaneously - Cache individually - Each package's task output is cached separately
- Filter precisely - Run
turbo run test --filter=webfor just one package
Root Tasks are a fallback for tasks that truly cannot run per-package:
// AVOID unless necessary - sequential, not parallelized, can't filter
{
"scripts": {
"lint": "eslint apps/web && eslint apps/api && eslint packages/ui"
}
}
Root turbo.json
{
"$schema": "https://turborepo.dev/schema.v2.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**", "!.next/cache/**"]
},
"lint": {},
"test": {
"dependsOn": ["build"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
Directory Organization
Grouping Packages
You can group packages by adding more workspace paths:
# pnpm-workspace.yaml
packages:
- "apps/*"
- "packages/*"
- "packages/config/*" # Grouped configs
- "packages/features/*" # Feature packages
This allows:
packages/
├── ui/
├── utils/
├── config/
│ ├── eslint/
│ ├── typescript/
│ └── tailwind/
└── features/
├── auth/
└── payments/
What NOT to Do
# BAD: Nested wildcards cause ambiguous behavior
packages:
- "packages/**" # Don't do this!
Package Anatomy
Minimum Required Files
packages/ui/
├── package.json # Required: Makes it a package
├── src/ # Source code
│ └── button.tsx
└── tsconfig.json # TypeScript config (if using TS)
package.json Requirements
{
"name": "@repo/ui", // Unique, namespaced name
"version": "0.0.0", // Version (can be 0.0.0 for internal)
"private": true, // Prevents accidental publishing
"exports": { // Entry points
"./button": "./src/button.tsx"
}
}
TypeScript Configuration
Shared Base Config
Create a shared TypeScript config package:
packages/
└── typescript-config/
├── package.json
├── base.json
├── nextjs.json
└── library.json
// packages/typescript-config/base.json
{
"compilerOptions": {
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"moduleResolution": "bundler",
"module": "ESNext",
"target": "ES2022"
}
}
Extending in Packages
// packages/ui/tsconfig.json
{
"extends": "@repo/typescript-config/library.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
No Root tsconfig.json
You likely don't need a tsconfig.json in the workspace root. Each package should have its own config extending from the shared config package.
ESLint Configuration
Shared Config Package
packages/
└── eslint-config/
├── package.json
├── base.js
├── next.js
└── library.js
// packages/eslint-config/package.json
{
"name": "@repo/eslint-config",
"exports": {
"./base": "./base.js",
"./next": "./next.js",
"./library": "./library.js"
}
}
Using in Packages
// apps/web/.eslintrc.js
module.exports = {
extends: ["@repo/eslint-config/next"],
};
Lockfile
A lockfile is required for:
- Reproducible builds
- Turborepo to understand package dependencies
- Cache correctness
Without a lockfile, you'll see unpredictable behavior.