Development Setup

Set up the pair development environment from scratch, prerequisites, install, dev commands, testing, and quality gates.

Step-by-step instructions to get the pair monorepo running locally.

Prerequisites

ToolVersionInstall
Node.js18+ (LTS recommended)nodejs.org
pnpm10.15.0+npm install -g pnpm@10.15.0
Git2.x+git-scm.com

Clone and install

git clone https://github.com/foomakers/pair.git
cd pair
pnpm install

pnpm install also sets up Husky git hooks automatically.

Running the dev server

Use pnpm --filter to run commands in a specific package:

# Documentation site
pnpm --filter @pair/website dev
 
# CLI tool
pnpm --filter @pair/pair-cli dev

Running tests

Tests use Vitest, orchestrated by Turborepo:

# All tests across the monorepo
pnpm test
 
# Single package
pnpm --filter @pair/pair-cli test
pnpm --filter @pair/content-ops test
 
# Single test by name
pnpm vitest run -t "test name"
 
# With coverage
pnpm test:coverage
 
# Playwright E2E tests (builds + starts Next.js)
pnpm --filter @pair/website e2e
 
# CLI smoke tests (e2e release process)
pnpm smoke-tests

Testing conventions

  • In-memory test doubles over mocks (e.g., InMemoryFileSystemService instead of mocking fs).
  • 1:1 mapping between source modules and test files.
  • TDD discipline: RED (failing test) → GREEN (minimal implementation) → REFACTOR.

Quality gate

Before committing, always run:

pnpm quality-gate

This runs (in order): ts:check, test, lint, format:check (prettier + markdownlint, check mode), gate:composition, hygiene:check, docs:staleness, skills:conformance, dup:check.

The gate never formats. It is the pre-push hook, where the commits already exist: a write-mode formatter would rewrite the working tree without touching what is being pushed, so it only pollutes the next diff. On a format:check failure, run pnpm format and commit the result.

Exit 2 instead of 1 means a formatter wrapper itself failed (a broken install, not drift), read its output rather than running pnpm format.

Two-step remedy: if pnpm format touched packages/knowledge-hub/dataset/**, re-sync the generated .claude/skills/** and .pair/knowledge/** copies (pnpm mirrors:regenerate) in the same commit, or a mirror guard fails later in the same gate, the dataset copy is inside format scope, its generated twin is not (.claude/ and root .pair/ are not workspace members), and the mirror guards assert each twin equals the OUTPUT of the real pair-cli update transform, never the dataset source itself, which the corpus is transformed away from.

gate:composition guards the gate against a write-mode step (formatter or eslint autofix) creeping back in. pnpm mirrors:regenerate regenerates from the working tree's own dataset, offline; pair-cli update installs the latest PUBLISHED knowledge base and is not the remedy for local drift.

See ADL the pre-push gate is check-only.

Gate registry

OrderGateCommandRequired
1Quality Gatepnpm quality-gateYes
2Smoke Testspnpm smoke-testsYes
3E2E Testspnpm --filter @pair/website e2eYes

Git hooks (Husky)

Husky is configured to run checks automatically:

  • Pre-commit: Type checking (pnpm ts:check).
  • Pre-push: The full quality gate (pnpm quality-gate), formatting included in check mode.

Troubleshooting hooks

ProblemSolution
Hooks not runningRun pnpm install after cloning. Verify .husky/ exists.
Permission errorschmod +x .husky/*
Pre-commit failsRun the hook command manually (pnpm ts:check) to debug.
Pre-push fails on formattingRun pnpm format, commit the result, push again: the gate never formats for you.
Pre-push fails on a mirror guardRun pnpm mirrors:regenerate and commit the regenerated files, never hand-edit a mirror.

Common commands

pnpm install              # Install all dependencies
pnpm quality-gate         # Full quality check (never writes - formatting is checked only)
pnpm format               # Apply formatting (prettier + markdownlint, write mode)
pnpm format:check         # Check formatting only - what the gate runs
pnpm mirrors:regenerate   # Realign the generated mirrors with the LOCAL dataset (offline)
pnpm build                # Build all packages
pnpm test                 # Run all tests
pnpm lint                 # Lint all packages
pnpm lint:fix             # Auto-fix linting issues
pnpm ts:check             # Type-check all TypeScript
pnpm prettier:check       # Check formatting (prettier only)
pnpm prettier:fix         # Auto-format code (prettier only)
pnpm mdlint:check         # Check markdown only (markdownlint)
pnpm clean                # Clean build artifacts and caches

Dependency management

Shared dependency versions are managed via the pnpm catalog in pnpm-workspace.yaml:

pnpm sync-deps            # Update all dependencies recursively
pnpm deps:outdated        # Show outdated packages
pnpm catalog:update       # Update pnpm catalog
pnpm catalog:check        # Show catalog contents

When adding a new shared dependency, add it to the catalog first.

Changesets

We use @changesets/cli for version management. Every PR carries a changeset (or the no-changeset label):

pnpm exec changeset add

Select the affected package(s) and bump type (patch/minor/major). Name it .changeset/<story-id>.md and mirror the PR description. Releases are cut with pnpm release <pre|rc|final>.

See the Release Process for the full workflow.

Platform notes

  • macOS / Linux: Fully supported. All commands work as documented.
  • Windows: Use WSL2 or Git Bash. Native Windows may have issues with symlinks (skills distribution falls back to copy mode).

On this page