Tooling and Dependencies
Toolchain (proto)
- Tool versions (bun, pnpm, node, moon, gh) are pinned in
.prototools and
managed by proto; its shims put the pinned
versions on PATH inside the repo. proto use installs everything after a pin
changes.
- Bump a tool by editing
.prototools only — never install tools globally or
pin versions elsewhere. moon's version is additionally enforced by
versionConstraint in .moon/workspace.yml and mirrored as the
@moonrepo/cli catalog entry (for Vercel builders without proto); keep all
three in sync.
- CI and local shells resolve the same toolchain: CI installs it with
moonrepo/setup-toolchain, which runs proto install against the same
.prototools.
Package Manager and Runtime
- Use
pnpm for package operations: install, add, remove, dedupe, lockfile,
package-runner, and publish work.
- Do not use
bun, npm, yarn, npx, or other package runners for package
operations unless there is a specific documented reason.
- Bun remains the direct TypeScript runtime and Bun test runner where current
moon tasks use it. Local scripts may still be
.ts files without a separate
compile step.
Dependency Catalog
This monorepo uses the catalog in pnpm-workspace.yaml.
- Never add a version directly to an individual package's
package.json by
default.
- To add a dependency:
- Add the exact version to
pnpm-workspace.yaml under catalog, for example
"new-package": "1.2.3".
- Reference it from the package with
"new-package": "catalog:".
- Do not run
pnpm add <package> inside a package directory; it writes direct
versions and breaks the catalog pattern unless you manually normalize them.
- Published packages may intentionally use ranges for end-user compatibility.
apps/docs should use catalog versions; published packages such as
packages/diffs may use ranges only when that is intentional.
Tasks
- All build/dev/test/lint entrypoints are moon tasks; package.json scripts exist
only for npm lifecycle hooks (
prepublishOnly). Never add task scripts back
to a package.json.
- Tasks are defined in
.moon/tasks/*.yml (inherited) and each project's
moon.yml. Repo-wide tooling (format, lint, icons, clean) lives on the root
project.
- Run tasks from anywhere in the repo:
moon run <project>:<task>
moonx <project>:<task> # same engine; shorthand for moon exec
moonx <project>:<task> -- --flags # forward arguments after --
moon run :test # a task across every project that has it
moon tasks <project> # discover a project's tasks
moon run and moonx (an alias binary for moon exec) execute the same action
pipeline: identical dependency resolution, caching, and affected support. Use
them interchangeably; docs write moon run for canonical commands and moonx
in interactive examples. The one practical difference: moonx/moon exec
exposes CI-behavior overrides (--ignore-ci-checks, --ci <bool>) that
moon run lacks. moon ci is a third thing — the affected-aware orchestrator
used only by .github/workflows/ci.yml; never reach for it locally.
moon builds dependency projects first (deps: ['^:build']), caches outputs, and
skips tasks whose inputs have not changed. Local-only tasks set explicit options
instead of moon presets (presets force runInCI: skip, which moon refuses to
run in CI-detected shells; agent harnesses export CI=1):
- No graph edges at all (formatters, benchmarks, wt, servers spawned by
playwright): use
runInCI: 'always' — runnable everywhere, and never in the
CI pipeline because a task with no deps or dependents is never affected
through the graph.
- Connected to the build graph (dev/prod, e2e variants, publish guards): keep
runInCI: 'skip' — moon ci --include-relations runs affected
runInCI-enabled tasks even when unrequested, which would pull them into CI.
Run them in CI-marked shells with moonx <target> --ignore-ci-checks (works
regardless of the shell's CI env). For non-moon commands that CI-gate
themselves, unset the var instead: CI= pnpm publish --dry-run.
1---2name: tooling-and-dependencies3description: Use when running repo scripts, adding or changing dependencies, editing package.json files, installing packages, publishing packages, or deciding when pnpm package operations versus Bun runtime commands should be invoked.4---56# Tooling and Dependencies78## Toolchain (proto)910- Tool versions (bun, pnpm, node, moon, gh) are pinned in `.prototools` and11 managed by [proto](https://moonrepo.dev/docs/proto); its shims put the pinned12 versions on PATH inside the repo. `proto use` installs everything after a pin13 changes.14- Bump a tool by editing `.prototools` only — never install tools globally or15 pin versions elsewhere. moon's version is additionally enforced by16 `versionConstraint` in `.moon/workspace.yml` and mirrored as the17 `@moonrepo/cli` catalog entry (for Vercel builders without proto); keep all18 three in sync.19- CI and local shells resolve the same toolchain: CI installs it with20 `moonrepo/setup-toolchain`, which runs `proto install` against the same21 `.prototools`.2223## Package Manager and Runtime2425- Use `pnpm` for package operations: install, add, remove, dedupe, lockfile,26 package-runner, and publish work.27- Do not use `bun`, `npm`, `yarn`, `npx`, or other package runners for package28 operations unless there is a specific documented reason.29- Bun remains the direct TypeScript runtime and Bun test runner where current30 moon tasks use it. Local scripts may still be `.ts` files without a separate31 compile step.3233## Dependency Catalog3435This monorepo uses the `catalog` in `pnpm-workspace.yaml`.3637- Never add a version directly to an individual package's `package.json` by38 default.39- To add a dependency:40 1. Add the exact version to `pnpm-workspace.yaml` under `catalog`, for example41 `"new-package": "1.2.3"`.42 2. Reference it from the package with `"new-package": "catalog:"`.43- Do not run `pnpm add <package>` inside a package directory; it writes direct44 versions and breaks the catalog pattern unless you manually normalize them.45- Published packages may intentionally use ranges for end-user compatibility.46 `apps/docs` should use catalog versions; published packages such as47 `packages/diffs` may use ranges only when that is intentional.4849## Tasks5051- All build/dev/test/lint entrypoints are moon tasks; package.json scripts exist52 only for npm lifecycle hooks (`prepublishOnly`). Never add task scripts back53 to a package.json.54- Tasks are defined in `.moon/tasks/*.yml` (inherited) and each project's55 `moon.yml`. Repo-wide tooling (format, lint, icons, clean) lives on the `root`56 project.57- Run tasks from anywhere in the repo:5859```bash60moon run <project>:<task>61moonx <project>:<task> # same engine; shorthand for moon exec62moonx <project>:<task> -- --flags # forward arguments after --63moon run :test # a task across every project that has it64moon tasks <project> # discover a project's tasks65```6667`moon run` and `moonx` (an alias binary for `moon exec`) execute the same action68pipeline: identical dependency resolution, caching, and affected support. Use69them interchangeably; docs write `moon run` for canonical commands and `moonx`70in interactive examples. The one practical difference: `moonx`/`moon exec`71exposes CI-behavior overrides (`--ignore-ci-checks`, `--ci <bool>`) that72`moon run` lacks. `moon ci` is a third thing — the affected-aware orchestrator73used only by `.github/workflows/ci.yml`; never reach for it locally.7475moon builds dependency projects first (`deps: ['^:build']`), caches outputs, and76skips tasks whose inputs have not changed. Local-only tasks set explicit options77instead of moon presets (presets force `runInCI: skip`, which moon refuses to78run in CI-detected shells; agent harnesses export `CI=1`):7980- No graph edges at all (formatters, benchmarks, wt, servers spawned by81 playwright): use `runInCI: 'always'` — runnable everywhere, and never in the82 CI pipeline because a task with no deps or dependents is never affected83 through the graph.84- Connected to the build graph (dev/prod, e2e variants, publish guards): keep85 `runInCI: 'skip'` — `moon ci --include-relations` runs affected86 runInCI-enabled tasks even when unrequested, which would pull them into CI.87 Run them in CI-marked shells with `moonx <target> --ignore-ci-checks` (works88 regardless of the shell's CI env). For non-moon commands that CI-gate89 themselves, unset the var instead: `CI= pnpm publish --dry-run`.