Community

Contribution guide

How to contribute to Routecraft.

Getting started

  • Fork the repository and create a feature branch from main.
  • Make focused, incremental changes with clear commit messages.
  • Run quality checks and tests locally before opening a PR.

Prerequisites

  • Bun 1.1.0+ (the workspace is Bun-managed; the craft CLI also requires Bun)
  • Node.js 22+ (some scripts and the embedding test path run on Node)
  • Git

Local development

# Clone and install
git clone https://github.com/routecraftjs/routecraft.git
cd routecraft
bun install

# Build, lint, typecheck, and test
bun run build
bun run lint
bun run typecheck
bun run test

# Run example capabilities
bun run craft run ./examples/dist/hello-world.js

# Run docs site locally
bun run docs

Project structure

  • packages/routecraft: core library (builder, DSL, context, adapters)
  • packages/ai: AI and MCP integrations
  • packages/cli: the craft CLI
  • packages/testing: test utilities (testContext, mockAdapter, spy logger)
  • packages/os: system-native adapters (shell(), agentBrowser())
  • packages/eslint-plugin-routecraft and packages/prettier-plugin-routecraft: lint rules and DSL formatting
  • packages/create-routecraft: the project scaffolder
  • apps/routecraft.dev: documentation site
  • examples/: runnable routes and tests

Development workflow

Branching

Use a short, descriptive branch name with a prefix:

  • feat/<feature-name>
  • fix/<bug-name>
  • docs/<docs-change>
  • refactor/<scope>

Example:

git checkout main && git pull
git checkout -b feat/add-batch-consumer-option

Conventional commits

Follow the Conventional Commits spec:

feat(adapter): add retry option to timer adapter
fix(cli): handle missing route files more gracefully
docs(contributing): clarify testing commands
refactor(builder): simplify type inference for map()

Coding standards

  • TypeScript everywhere; avoid any. Prefer precise types or unknown with narrowing.
  • Keep capabilities small, composable, and isolated. Use .from for sources, pure steps for processing, .to for side effects.
  • One function per step; accept a single options object or one adapter instance.
  • Validate external inputs with a Standard Schema in .input(), and use .filter(fn) for business rules.
  • Prefer purity for .transform, .process, .filter, .tap.
  • Avoid cross-capability globals; use direct(...) or CraftContext store.
  • Match existing formatting and structure; keep functions short and readable.

Testing

  • Write unit tests for core behavior (packages/routecraft/test/*).
  • Use example routes under examples/ to verify end-to-end behavior.
  • Run tests and coverage locally:
bun run test
bun run test:coverage

Pull request checklist

Before opening a PR:

bun run format        # check formatting
bun run lint          # lint all packages
bun run typecheck     # TypeScript checks
bun run test          # run tests
bun run build         # build all packages

Or run the bundled bun run all, which executes lint --fix, format:write, typecheck, build, and test in one pass.

If you edited a documentation page, run the example typecheck as well, from apps/routecraft.dev:

bun run check:examples

It compiles every fenced ts block on the docs site against the workspace packages. A block that is not meant to compile says so on its fence, with a reason:

```ts skip="fragment: dest is illustrative"
```ts expect-error="json() takes path, not file"

Use skip when the block is not a complete program and therefore does not compile, such as a chain shown without its route or a method signature shown as reference prose (agent(options): Enricher<T, R>, not a statement a program can contain). A standalone type alias or interface is a complete program and compiles on its own, so it does not qualify. Use expect-error when the block is meant to be wrong, which is what a migration guide's "before" example is. Both need a non-empty reason, and both are checked: if a block carrying either marker turns out to compile, the build fails, so a marker cannot be carried through a rewrite and quietly leave the block unchecked.

Include in your PR description:

  • What changed and why
  • Screenshots/logs if relevant
  • Testing notes (steps to verify)

CI and auto-merge

  • CI runs formatting, linting, type checks, tests, build, and example runs.
  • Dependabot PRs are auto-approved and auto-merged once the required ci-passed check, which covers every CI job, passes.

Releasing

  • Versioning and publishing are owned by changesets. Never hand-edit package.json versions.
  • Every PR with a user-facing change adds a changeset: run bunx changeset, pick the affected packages and bump level, and describe the change.
  • The auto-maintained "Version Packages" PR is the release gate: merging it publishes to npm, creates the GitHub releases, and tags the release.
  • During v0, breaking changes are minor bumps, never major: the whole 0.x line is the breaking window, and major is reserved for the deliberate 1.0.0 release.

Questions and help

Open a GitHub discussion or issue for questions.


Testing

Test capabilities with testContext, mockAdapter and the spy adapter.

Linting

Every rule in the Routecraft ESLint plugin.

Formatting

Keep DSL chains compact with the Prettier plugin.

Previous
Errors
Next
FAQ