# Pathrule Pattern: Monorepo (pnpm + Turborepo) (1.0.0)
# ::pathrule:package:monorepo-pnpm-turborepo

### [RULE] Every task declares outputs, inputs, and env  (path: /turbo.json)
<!-- scope: project | priority: medium | advisory -->

Turborepo only caches and replays a task correctly when its hash is complete. Configure each task in `turbo.json` so the hash reflects exactly what the task reads and writes.

- Set `outputs` to every artifact the task produces (for example `[".next/**", "!.next/cache/**"]` or `["dist/**"]`); a missing `outputs` means nothing is restored from cache.
- Add build-time `env` and `globalEnv` entries for any variable that changes output, and run with `envMode: "strict"` so undeclared vars cannot silently leak into a build.
- Use `dependsOn: ["^build"]` to build upstream packages first, and mark `dev`/`watch` tasks `persistent: true` with `cache: false`.
- Narrow `inputs` only when you understand the default; the safe default already hashes all tracked files in the package.

---

### [RULE] Import packages only through their public entry  (path: /packages)
<!-- scope: project | priority: medium | advisory -->

Internal packages are consumed by their name and `exports` map, never by reaching across folders. This keeps Turborepo Boundaries valid and the dependency graph honest.

- Import a workspace package as `@repo/ui` (resolved via its `package.json` `exports`), never as `../../packages/ui/src/...`.
- Declare every workspace package you use in that package's `package.json` with `"@repo/ui": "workspace:*"`; an undeclared import is an implicit dependency Turborepo cannot track.
- Keep each package's public surface in its `exports` field and avoid deep subpath imports unless they are explicitly exported.
- Run `turbo boundaries` in CI to catch cross-package imports and undeclared dependencies before merge.

---

### [MEMORY] Pin shared dependency versions with pnpm catalogs  (path: /pnpm-workspace.yaml)

This repo uses pnpm workspaces with catalogs as the single source of truth for shared dependency versions, so every package stays on the same React, TypeScript, and tooling versions.

- `pnpm-workspace.yaml` lists workspace globs under `packages:` (for example `apps/*` and `packages/*`) plus a `catalog:` block and optional named `catalogs:` for version sets.
- Packages reference shared deps as `"react": "catalog:"` (default catalog) or `"catalog:react19"` for a named one, instead of hard-coding a range.
- Bump a version in one place in the catalog and run `pnpm install`; pnpm rewrites the resolved lockfile entries across all packages.
- The content-addressable store hard-links shared deps, so a single committed `pnpm-lock.yaml` keeps installs fast and deterministic.

---

### [MEMORY] Share base configs as workspace packages  (path: /packages/config)

Tooling configuration is published as internal config packages (for example `@repo/typescript-config`, `@repo/eslint-config`) rather than duplicated or pushed to the repo root. Each app and package extends the base it needs.

- There is intentionally no root `tsconfig.json` for source; each package has its own `tsconfig.json` that does `"extends": "@repo/typescript-config/base.json"`.
- ESLint flat config and Tailwind/PostCSS presets are exported from config packages and imported, so a rule change ships once.
- List the config package as a `devDependency` with `workspace:*` so Turborepo treats a config change as an input and busts the cache.
- Keep the root `package.json` for workspace scripts and `turbo` only; per-package concerns stay in their own package.

---

### [SKILL] monorepo-pnpm-turborepo-review  (path: /)

---
name: monorepo-pnpm-turborepo-review
description: Review checklist for changes in a pnpm workspaces plus Turborepo monorepo, covering task hashing, caching, package boundaries, catalog-pinned versions, and shared configs. Use before merging any change that touches turbo.json, pnpm-workspace.yaml, package.json files, or cross-package imports.
---

# Monorepo (pnpm + Turborepo) review

- [ ] Every new or changed `turbo.json` task sets `outputs` covering all produced artifacts (and excludes cache dirs like `!.next/cache/**`).
- [ ] Build-affecting env vars are declared in the task `env` or `globalEnv`, and `envMode` is `strict`.
- [ ] `dependsOn` uses `^build` for upstream packages; `dev`/`watch` tasks are `persistent: true` and `cache: false`.
- [ ] New cross-package usage imports by package name (`@repo/*` via `exports`), never by relative or deep `src`/`dist` paths.
- [ ] Each used workspace package is declared with `workspace:*` in the consuming package's `package.json`.
- [ ] `turbo boundaries` and the build pass with a clean dependency graph; no implicit deps.
- [ ] Shared dependency versions use `catalog:` (or a named catalog) instead of hard-coded ranges.
- [ ] `pnpm-lock.yaml` is committed and reflects the install; only one version of each shared dep is resolved.
- [ ] TypeScript, ESLint, and Tailwind extend the shared `@repo/*-config` packages rather than duplicating config.
- [ ] `packageManager` is pinned in the root `package.json` and matches the pnpm version used in CI.
