.node-version or CI config)corepack enable)# Enable pnpm via corepack (one-time)
corepack enable
# Install dependencies
pnpm install
# Start all apps in dev mode
pnpm dev
Dev URLs:
| App | URL |
|---|---|
| Frontend | http://localhost:5173 |
Run from the repository root:
| Command | Description |
|---|---|
pnpm dev | Start all apps in watch mode |
pnpm build | Build everything (respects dependency order) |
pnpm test | Run all tests |
pnpm lint | Lint all packages |
pnpm typecheck | Type-check all packages |
pnpm fix | Auto-fix lint and formatting (Ultracite/Biome) |
pnpm check:deps | Verify workspace dependency consistency |
pnpm fix:deps | Auto-fix dependency inconsistencies |
To target a specific package, use Turborepo's --filter:
pnpm build --filter=@syntropy/frontend
pnpm test --filter=@syntropy/utils
Create the app directory:
mkdir -p apps/my-app/src
Create apps/my-app/package.json:
{
"name": "@syntropy/my-app",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"build": "tsc",
"dev": "tsx watch src/index.ts",
"start": "node dist/index.js",
"clean": "rm -rf dist",
"lint": "biome check .",
"typecheck": "tsc --noEmit",
"test": "vitest run --passWithNoTests"
},
"devDependencies": {
"@syntropy/tsconfig": "workspace:*",
"typescript": "catalog:"
}
}
Create apps/my-app/tsconfig.json extending a shared config:
{
"extends": "@syntropy/tsconfig/base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}
Run pnpm install to link the new workspace package.
If the app should be deployed, update:
Dockerfile (add build output COPY and turbo prune target)scripts/entrypoint.sh (add a new case entry)Create the package directory:
mkdir -p packages/my-package/src
Create packages/my-package/package.json:
{
"name": "@syntropy/my-package",
"version": "0.1.0",
"private": true,
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"clean": "rm -rf dist",
"lint": "biome check .",
"typecheck": "tsc --noEmit",
"test": "vitest run"
},
"devDependencies": {
"@syntropy/tsconfig": "workspace:*",
"typescript": "catalog:"
}
}
Create packages/my-package/tsconfig.json:
{
"extends": "@syntropy/tsconfig/node-library.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}
Run pnpm install.
Add the dependency in consuming packages:
"@syntropy/my-package": "workspace:*"
After creating a new app or package, use the /verify-setup skill in Claude Code to check that everything follows the monorepo conventions:
/verify-setup apps/my-app
/verify-setup packages/my-package
This runs automated checks against package.json, tsconfig.json, and the directory structure, reporting [PASS]/[FAIL] for each convention with fix suggestions on failures. Checks include:
@syntropy/<dir-name>), private, and type fieldsbuild, dev, clean, lint, typecheck, test)workspace:* for internal deps, catalog: for catalog deps)main, types, exports) for packages under packages/tsconfig.json structure (extends, include, outDir, rootDir)src/ directory existenceLefthook runs automatically on commit. It applies Ultracite (Biome) formatting and linting to staged files and re-stages the fixes (stage_fixed: true).
The GitHub Actions pipeline runs on every push:
pnpm check:deps — dependency consistencypnpm lint --affected — lint changed packages onlypnpm typecheck --affected — type-check changed packagespnpm test --affected — test changed packagesTests use Vitest. Each package runs vitest run (or vitest run --passWithNoTests for apps).
# Run all tests
pnpm test
# Run tests for a specific package
pnpm test --filter=@syntropy/utils
# Watch mode (in a specific package directory)
cd packages/utils && npx vitest