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
craftCLI 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 integrationspackages/cli: thecraftCLIpackages/testing: test utilities (testContext,mockAdapter, spy logger)packages/os: system-native adapters (shell(),agentBrowser())packages/eslint-plugin-routecraftandpackages/prettier-plugin-routecraft: lint rules and DSL formattingpackages/create-routecraft: the project scaffolderapps/routecraft.dev: documentation siteexamples/: 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 orunknownwith narrowing. - Keep capabilities small, composable, and isolated. Use
.fromfor sources, pure steps for processing,.tofor 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(...)orCraftContextstore. - 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-passedcheck, which covers every CI job, passes.
Releasing
- Versioning and publishing are owned by changesets. Never hand-edit
package.jsonversions. - 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
minorbumps, nevermajor: the whole 0.x line is the breaking window, andmajoris reserved for the deliberate 1.0.0 release.
Questions and help
Open a GitHub discussion or issue for questions.
Related
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.