Thanks for your interest in contributing! This document covers everything you need to get started.
- Node.js ≥ 22 (the test runner uses
node:testAPIs that require it) - pnpm ≥ 10 — install with
npm install -g pnpm
git clone https://github.com/stackables/bridge.git
cd bridge
pnpm installThat's it — no separate build step needed for development. The test suite uses tsx to run TypeScript directly.
# All packages
pnpm test
# Just the main package (faster iteration)
cd packages/bridge
pnpm test
# Single test file
cd packages/bridge
node --import tsx/esm --test test/parser-compat.test.tsTests use the built-in node:test runner. No Jest, no Vitest. Output is TAP-style with a summary at the end.
pnpm build # all packages
cd packages/bridge && pnpm build # just the runtimeThe build outputs to packages/bridge/build/ and is what gets published to npm. You never need to build to run tests — tsx handles TypeScript directly.
This project uses strict TypeScript. The tsconfig enforces:
| Flag | Why |
|---|---|
strict |
All standard strict checks (noImplicitAny, strictNullChecks, etc.) |
noUnusedLocals |
Unused imports and variables are compile errors |
noUnusedParameters |
Unused function parameters are compile errors |
noImplicitReturns |
Every code path must return |
noFallthroughCasesInSwitch |
Switch cases must not silently fall through |
packages/
bridge/ — The main runtime package (@stackables/bridge)
src/ — TypeScript source (edit here)
test/ — Test files
build/ — Compiled output (committed; not for editing)
bridge-syntax-highlight/ — VS Code extension for .bridge files
examples/ — Runnable examples (weather-api, builtin-tools, composed-gateway)
docs/ — Language guide, developer notes
For a detailed walkthrough of the internals, see docs/developer.md.
The parser is in packages/bridge/src/parser/. It uses Chevrotain:
- Tokens are defined in
lexer.ts - Grammar rules live in
parser.ts(theBridgeParserclass, ~line 90) - CST → AST transformation is also in
parser.ts(thetoBridgeAstvisitor, ~line 820)
If you add a new keyword or syntax:
- Add a token in
lexer.tswithlonger_alt: Identifierso it doesn't steal valid identifiers - Add the grammar rule to
BridgeParser - Add the visitor logic in
toBridgeAst - Add a
parser-compat.test.tssnapshot for the new construct - Update
docs/bridge-language-guide.md
Tools live in packages/bridge/src/tools/. Each tool is a TypeScript file that exports a function matching ToolCallFn:
// src/tools/my-tool.ts
export function myTool(
input: Record<string, any>,
): Promise<Record<string, any>> {
// ...
}Then register it in src/tools/index.ts under the std namespace:
export const std = { ..., myTool };Add tests in test/builtin-tools.test.ts.
The execution engine is src/ExecutionTree.ts. It is pull-based: field resolution starts from a GraphQL request, travels backward through wire declarations, and invokes tools only when their output is actually needed.
If you change execution semantics, add a test in test/executeGraph.test.ts or the relevant feature test file.
| File | What it covers |
|---|---|
parser-compat.test.ts |
Parse → serialize round-trips (snapshot-style) |
bridge-format.test.ts |
Bridge text formatting |
executeGraph.test.ts |
End-to-end execution with a real GraphQL schema |
tool-features.test.ts |
Tool inheritance, wires, onError |
builtin-tools.test.ts |
std namespace tools |
resilience.test.ts |
Error fallback, null coalescing |
scheduling.test.ts |
Concurrency and deduplication of tool calls |
tracing.test.ts |
Trace output shape |
logging.test.ts |
Logger integration |
http-executor.test.ts |
httpCall tool |
chained.test.ts |
Pipe operator chains |
scope-and-edges.test.ts |
Handle scoping, define blocks |
- Keep PRs focused — one feature or fix per PR
- All tests must pass (
pnpm test) tsc --noEmitmust be clean (the strict flags will catch issues)- For language changes, update
docs/bridge-language-guide.md - For new tools, add them to the built-in tools example
Open a GitHub Discussion or file an issue.