Contributing to StateLoom
Guide for setting up the development environment, making changes, and submitting contributions.
Prerequisites
| Tool | Version | Install |
|---|---|---|
| Node.js | 20+ | nvm install 20 |
| pnpm | 9+ | corepack enable && corepack prepare pnpm@latest --activate |
| Git | 2.30+ | System package manager |
Setup
git clone https://github.com/stateloom/stateloom.git
cd stateloom
corepack enable
pnpm install
pnpm build # build all packages in dependency order
pnpm test # run all testsVerify everything works before making changes.
Development Workflow
Working on a Package
# Build and watch a specific package
pnpm turbo watch build --filter=@stateloom/core
# Run tests for a specific package
pnpm turbo run test --filter=@stateloom/core
# Run tests in watch mode
pnpm turbo run test:watch --filter=@stateloom/core
# Type check a specific package
pnpm turbo run typecheck --filter=@stateloom/coreWorking with Examples
# Start React Vite example (with hot reload)
pnpm dev:react-vite
# Start Next.js App Router example
pnpm dev:next-appFull Validation
Before submitting any changes, run:
pnpm lint # lint all packages
pnpm typecheck # type check all packages
pnpm build # build all packages
pnpm test # run all testsAll four must pass.
Making Changes
Branch Naming
feat/<description> # new features
fix/<description> # bug fixes
refactor/<description> # refactoring
docs/<description> # documentation only
test/<description> # test changes onlyCommit Convention
Use Conventional Commits:
feat(core): add custom equality comparator to signal
fix(react): prevent double-render in StrictMode
docs(store): add middleware composition example
test(atom): add diamond dependency test case
refactor(proxy): extract snapshot logic to separate module
chore: update pnpm to 9.15Format: <type>(<scope>): <description>
- type:
feat,fix,docs,test,refactor,chore,perf - scope: package name without
@stateloom/prefix (e.g.,core,react,store) - description: imperative mood, lowercase, no period
Code Standards
All code must follow the Coding Guidelines. Key rules:
- Strict TypeScript — no
any, no enums,import typefor types - Named exports only
- 95%+ test coverage for every package
- No
console.login library code
Testing Requirements
Every code change must include tests:
- Write tests alongside code changes
- Run
pnpm turbo run test --filter=@stateloom/<package> -- --coverage - Ensure 95%+ coverage (statements, branches, functions, lines)
- Include type tests using
expectTypeOffor public API changes
Documentation Updates
If your change affects public API:
- Update the relevant package README in
docs/api/ - Update code examples to reflect new behavior
- Update Mermaid diagrams if architecture changed
Changeset Workflow
StateLoom uses Changesets for versioning and publishing.
When You Change Published Code
pnpm changesetThis prompts you to:
- Select which packages changed
- Choose version bump type (patch, minor, major)
- Write a description of the change
A changeset file is created in .changeset/. Commit it with your changes.
What Gets a Changeset
| Change Type | Needs Changeset |
|---|---|
| Bug fix in published package | Yes (patch) |
| New feature in published package | Yes (minor) |
| Breaking change in published package | Yes (major) |
| Test-only changes | No |
| Documentation-only changes | No |
| Example app changes | No |
| CI/tooling changes | No |
Release Process
Releases are automated via GitHub Actions:
- Changesets accumulate on
main - The Changesets GitHub Action opens a "Version Packages" PR
- Merging that PR triggers
pnpm changeset publish→ npm publish
Syncing Example Versions
Examples use real npm version ranges (not workspace:^) so that StackBlitz can load them directly from the repo. After bumping package versions, sync the examples:
pnpm sync-example-versions # reads version from packages/core
pnpm sync-example-versions 1.2.0-beta.0 # explicit version overrideThis must be run after every version bump. Forgetting this step will break StackBlitz demos.
Adding a New Package
pnpm new-package # interactive scaffoldThis generates:
packages/<name>/src/index.tspackages/<name>/__tests__/packages/<name>/package.json(with correct exports, peer deps)packages/<name>/tsconfig.jsonpackages/<name>/tsup.config.tspackages/<name>/vitest.config.ts
After scaffolding:
- Implement the feature in
src/ - Write tests in
__tests__/ - Create documentation in
docs/api/<name>/README.md - Run full validation:
pnpm lint && pnpm typecheck && pnpm build && pnpm test
CI Pipeline
Every PR runs:
| Step | Command | Purpose |
|---|---|---|
| Lint | pnpm lint | ESLint + Prettier |
| Type Check | pnpm typecheck | TypeScript strict mode |
| Build | pnpm build | tsup (ESM + CJS + dts) |
| Test | pnpm test | Vitest with coverage |
| Size Check | pnpm size | Bundle size budget |
All steps must pass for the PR to be mergeable.
Architecture Reference
Before contributing, familiarize yourself with:
- Design Philosophy — Why StateLoom exists and its core principles
- Architecture Overview — Layer diagram, dependency rules, build order
- Layer Scoping — What each package owns and does not own
- Monorepo Tooling — Complete tooling stack and configuration