corsa-bind
Rust bindings, orchestration layers, and JS runtime bindings for Corsa over stdio.
[!WARNING] This repository is still evolving. The local Rust and Node API/LSP surfaces are now hardened for production-style use, but distributed orchestration remains behind the
experimental-distributedcargo feature and some upstream-facing endpoints remain explicitly experimental.
[!IMPORTANT]
corsa-bindis intentionally built around upstream-supported Corsa workflows. We follow Corsa's recommended stdio/API/LSP integration points, keepref/corsa-upstreamas an exact upstream checkout, and preserve a strictno forks, no patchespolicy.
What This Is
corsa-bind is a multi-crate workspace for talking to Corsa from Rust and JavaScript runtimes without patching upstream, with a Rust-backed native FFI layer that exposes Corsa API, virtual-document, and utils surfaces across C-family and other native languages.
Naming Note
corsa-bind is the repository and distribution name for bindings around the
Corsa effort: the native TypeScript 7 implementation line we track here in the
typescript-go codebase.
The TypeScript roadmap describes this as the JS-based TypeScript 6 line versus
the native TypeScript 7 line, and it also uses Strada for the original
TypeScript codename and Corsa for this effort:
TypeScript Native Port: Versioning Roadmap.
We keep corsa for crate, binary, and upstream-facing labels where that matches
the implementation surface, instead of the more generic tsc or tsgo labels
that are easy to misread in docs, code, and release notes.
In practice, that means:
- use Corsa through the interfaces it already intends consumers to use
- track upstream by exact commit so behavior is reproducible and auditable
- never maintain a fork and never carry local patches against Corsa upstream
- implement hot paths in Rust, keep them zero-cost and high-performance, and
expose them to JS through
napi-rsso end users can author custom plugins and custom rules in JS/TS
Current focus:
- Full Rust-side stdio bindings for the Corsa API
- stdio LSP bindings with virtual-file support
- zero-cost-lean hot paths with msgpack-first defaults
napi-rsbindings that surface Rust performance to JS/TS authoring workflows- Rust-backed Corsa API,
utils, and virtual-document bindings for C, C++, Go, Zig, C#, Swift, and MoonBit - local multi-process orchestration, cache reuse, and experimental replicated state
- strict upstream pinning by exact Corsa upstream commit
- regression tests and benchmarks against the real pinned upstream server
Current Status
- License: MIT
- Upstream policy:
ref/corsa-upstreamis pinned and tracked by exact commit, with no local patching - Default API transport:
SyncMsgpackStdio - Runtime: custom in-house runtime, no
tokio - Fast-path bias:
CompactString,SmallVec,bumpalo,memchr,phf,FxHash - JS toolchain: Vite+ (
vp) with vp-managed Node24, pnpm10,oxfmt, andoxlint - Repo automation:
scripts/*.tsexecuted directly through Node24with--strip-types - JS bindings:
@corsa-bind/napi(src/bindings/nodejs/corsa_node) andcorsa oxlint(src/bindings/nodejs/corsa_oxlint, published ascorsa-oxlint) (public npm packages that still expect a caller-managed Corsa executable) - Distributed orchestration:
experimental-distributedcargo feature - TS benchmark project:
bench - Example workspace:
examples - Default request timeout:
30s - Default graceful shutdown timeout:
2s - Default outbound queue capacity:
256 - Unstable upstream endpoints such as
printNodeare opt-in - Structured event sink:
CorsaObserver/CorsaEvent
Corsa upstream snapshot at the time of writing:
- Repository:
https://github.com/microsoft/typescript-go.git - Commit:
f4a1d2a1d0d5df4333f2440500e3a6c4b4702d9a - Lock file:
corsa_ref.lock.toml, which is the source of truth for the exact upstream ref and tree.
Sponsors
CI/CD runners for this project are supported by Blacksmith.
Workspace Layout
corsa_core: shared errors, process handles, and fast-path primitivescorsa_jsonrpc: stdio JSON-RPC framing and connection managementcorsa_client: typed Corsa stdio client bindings for JSON-RPC and msgpackcorsa_lsp: LSP client support plus virtual-document overlayscorsa_orchestrator: local orchestration, caching, and experimental replicated state / Raft corecorsa_runtime: lightweight custom runtime and task primitivescorsa_ref: exact upstream pin, sync, and verification toolingcorsa: top-level facade crate, mock server, and native benchmark binariessrc/bindings/c/corsa_ffi: shared C ABI over the Rustcorsa_client::ApiClient,corsa_core::utils, andcorsa_lsp::VirtualDocumentsurfacessrc/bindings/cpp,src/bindings/go,src/bindings/zig,src/bindings/csharp,src/bindings/swift,src/bindings/moonbit: thin language bindings layered on top ofcorsa_ffisrc/bindings/nodejs/corsa_node:napi-rsnative bindings and the@corsa-bind/napiTypeScript wrapper packagesrc/bindings/nodejs/corsa_oxlint: type-aware Oxlint rule framework powered by Corsabench: Vitest benchmark project for the Node bindingexamples: curatedexamples/nodejs,examples/rust, andexamples/corsa_oxlintflows from minimal start to real-project runs
For a detailed architecture walkthrough, design strategy, and implementation tips, see docs/project_guide.md. The generated Ox Content documentation site starts at docs/index.md. For deployment-oriented defaults, supported scope, and release checks, see docs/production_readiness.md. For support guarantees, compatibility, and semver expectations, see docs/support_policy.md. For distribution decisions and release dry-runs, see docs/release_guide.md. For dependency-policy and release-hardening expectations, see docs/supply_chain_policy.md.
Once trusted publishing is bootstrapped, a release is cut from main with:
Quick Start
Enter the Nix dev shell first. It includes the toolchains for every binding
target under src/bindings:
The Nix shell itself is authored in flake.tnix and compiled
to flake.nix with tnix:
flake.tnix is intentionally kept as a thin tnix entrypoint, while the full
outputs implementation lives in nix/flake-outputs.nix.
That split avoids current tnix edges around some larger flake constructs.
See docs/tnix_notes.md for the current limitations and
the reasoning behind the layout.
Sync and verify the Corsa upstream checkout:
Build everything through Vite+:
Build the Ox Content documentation site and deploy it with Void:
Repository automation scripts now assume Node 24 so they can run TypeScript
directly through node --strip-types. The published npm packages themselves
target Node 22+, Deno 2.0+, and Bun 1.2+.
Examples
The repository now ships executable examples for Rust, @corsa-bind/napi, and
corsa oxlint under examples/, from
minimal virtual-document edits up through checker-query walkthroughs and
opt-in upstream printer flows.
Run the smoke-tested examples with:
Run only the Rust smoke examples with:
Run only the Node / TypeScript smoke examples with:
Run the real pinned Corsa examples with:
Run the experimental distributed Rust example with:
Type-Aware Oxlint
corsa oxlint lets us write Oxlint JS plugins with a compact, self-hosted
type-aware authoring model while sourcing type information from the pinned
Corsa binary. The heavy lifting stays in Rust, then napi-rs binds
that implementation into JS so end users can keep writing custom plugins and
custom rules in JS/TS.
import { OxlintUtils } from "corsa-oxlint";
const createRule = OxlintUtils.RuleCreator((name) => `https://example.com/rules/${name}`);
export const noStringPlusNumber = createRule({
name: "no-string-plus-number",
meta: {
type: "problem",
docs: {
description: "forbid string + number",
requiresTypeChecking: true,
},
messages: {
unexpected: "string plus number is forbidden",
},
schema: [],
},
defaultOptions: [],
create(context) {
const services = OxlintUtils.getParserServices(context);
const checker = services.program.getTypeChecker();
return {
BinaryExpression(node) {
if (node.operator !== "+") {
return;
}
const left = checker.getTypeAtLocation(node.left);
const right = checker.getTypeAtLocation(node.right);
if (!left || !right) {
return;
}
if (
checker.typeToString(checker.getBaseTypeOfLiteralType(left) ?? left) === "string" &&
checker.typeToString(checker.getBaseTypeOfLiteralType(right) ?? right) === "number"
) {
context.report({ node, messageId: "unexpected" });
}
},
};
},
});
The rule-side type-aware config lives under settings.corsaOxlint. Package
details and caveats are documented in src/bindings/nodejs/corsa_oxlint/README.md.
corsa oxlint exposes a TS-native type-aware rule set and plugin via corsa-oxlint/rules:
import { corsaOxlintPlugin } from "corsa-oxlint/rules";
export default [
{
plugins: {
typescript: corsaOxlintPlugin,
},
rules: {
"typescript/no-floating-promises": "error",
"typescript/prefer-promise-reject-errors": "error",
"typescript/restrict-plus-operands": ["error", { allowNumberAndString: false }],
},
},
];
The rule framework is self-hosted and does not depend on third-party
TypeScript lint helper packages. Upstream tsgolint/internal/rules is now
used as a parity target and drift oracle rather than as a runtime bridge.
The intended rule architecture has two lanes:
- user-defined type-aware rules keep the
typescript-eslint-style JS/TS authoring model throughOxlintUtils.RuleCreator()and parser services - common built-in rules can move onto the Rust hot path through
corsa::lint::RustLintRule, then surface back through the samecorsa-oxlint/rulesOxlint JS plugin shape
This keeps the public integration point aligned with Oxlint's JS plugin API
while leaving room for Rust-authored rule crates, in the spirit of swc-style
Rust extension points. The Rust-authored builtin set now covers the tracked
upstream tsgolint/internal/rules surface exposed by
corsa-oxlint/rules.
Example
use ;
Benchmarks
The repo ships two benchmark layers:
- Native Rust benchmark:
vp run -w bench_native - Native profiling benchmark:
vp run -w bench_native_profile - Tooling comparison benchmark:
vp run -w bench_tooling_compare - Node binding benchmark:
vp run -w bench_ts corsa oxlintchecker benchmark:vp test bench --config ./vite.config.ts bench/src/corsa_oxlint.bench.tscorsa oxlintnative-rule benchmark:vp test bench --config ./vite.config.ts bench/src/corsa_oxlint_rules.bench.ts- Combined benchmark + budget guard:
vp run -w bench
The TS benchmark writes machine-readable output to .cache/bench_ts.json.
The native benchmark writes machine-readable output to .cache/bench_native.json.
The native profiling benchmark writes machine-readable output to .cache/bench_native_profile.json.
The native Rust benchmark uses the real pinned Corsa binary through bench_real_corsa.
Latest native measurements are documented in docs/performance.md.
Benchmarking rationale, implementation notes, and usage tips are documented in docs/benchmarking_guide.md.
CI structure, local reproduction steps, and troubleshooting notes are documented in docs/ci_guide.md.
On the exact Corsa upstream commit and bundled datasets, msgpack was consistently faster than async JSON-RPC, which is why ApiSpawnConfig::new() defaults to SyncMsgpackStdio.
Regression Strategy
The repository is intentionally aggressive about change detection because Corsa upstream is still unstable.
cargo test --workspaceincludes mock-server integration tests, policy tests, and real-Corsa regression tests when.cache/corsais availablesrc/bindings/rust/corsa/tests/real_corsa_baseline.rslocks a real-server API summary to the pinned upstream commitsrc/bindings/rust/corsa/tests/real_corsa_regression.rschecks both transports against the real pinned Corsa binary- the real-Corsa regression suite includes a hot-path guard that fails if msgpack falls too far behind JSON-RPC on the same machine
vp run -w bench_nativeandvp run -w bench_tsgive repeatable transport-level measurements for Rust and Nodevp run -w bench_verifyregenerates both reports and fails if benchmark samples disappear or hot-path budgets regresscorsa_refenforces detached-HEAD exact-commit verification forref/corsa-upstream- CI structure and local reproduction notes live in
docs/ci_guide.md
Upstream Tracking
Corsa upstream is under heavy development, so reproducibility is treated as a hard requirement.
- exact commit metadata lives in
corsa_ref.lock.toml - sync and drift tooling lives in
docs/corsa_upstream_dependency.md - CI and local reproduction details live in
docs/ci_guide.md ref/corsa-upstreammust remain on detachedHEAD- dirty upstream worktrees fail verification
Known Limitations
- Public APIs are still
0.x, so compatibility should be treated as conservative rather than frozen. printNodeis disabled by default because the pinned Corsa upstream commit can panic ininternal/printeron real project data; opt in only when you accept that risk.- The distributed layer currently includes an in-process Raft core; full network transport between nodes is not finished yet.
- Some binary API surfaces are still exposed as opaque encoded payloads rather than fully decoded Rust AST types.
Development
Useful commands: