contributor-context
Contributor context for coding agents working in this repository. Human contributors should start with `README.md` and…
<!-- GENERATED from docs/api/rust.md by scripts/build-agent-skill.mjs. Do not edit. -->
$ npx -y skills add crossbind/crossbind --agent claude-codeHow it fires
How this agent gets triggered: by you, by Claude, or both.
Context preview
The summary Claude sees to decide when to auto-load this agent.
<!-- GENERATED from docs/api/rust.md by scripts/build-agent-skill.mjs. Do not edit. -->
<!-- GENERATED from docs/api/rust.md by scripts/build-agent-skill.mjs. Do not edit. -->
> Import plain Rust into JavaScript the same way you import a C++ header: > classes, methods, free functions — one import line, no proc-macros, no > hand-written glue. Works on web (emscripten embind), and on iOS, Android and > Node.js addons for macOS, Linux (glibc and musl) and Windows (embind-jsi), with > the same JS code; `platform: 'wasi'` skips Rust (no wasm32-wasip3 Rust target yet). The wasm `mt` runtime works too but needs > nightly Rust: crossbind rebuilds std with the atomics/bulk-memory features via > `-Zbuild-std` (run `rustup toolchain install nightly --component rust-src` > once; without it the build fails with that exact instruction).
The engine does not depend on the Rust layer — the consumer declares it:
pnpm add -D @crossbind/core-embind-rust@beta
Bundler plugins (`@crossbind/plugin-vite`, `-rollup`, `-webpack`, `-react-native`) already carry it as a dependency, so plugin users usually get it transitively. Builds in the toolchain images need no Rust on your machine: each image carries the pinned toolchain and the std of every target it builds. iOS and macOS builds, and every build under `RUNNER=LOCAL`, use your own Rust toolchain (`cargo` + the platform targets). cargo itself is the incremental cache — rebuilds are no-ops when nothing changed.
Import straight from a crates.io crate — no local Rust file at all. Declare the crate in `crossbind.config.js`, then import with the `cargo:` prefix (the `node:`/`npm:` convention: the prefix names the store):
// crossbind.config.js — top level, next to `dependencies`
cargoDependencies: {
uuid: '{ version = "1", features = ["v4"] }',
semver: '1',
},import { initNative } from './native/native.h';
import { Uuid } from 'cargo:uuid'
import { Version, VersionReq } from 'cargo:semver'
await initNative()
const id = Uuid.newV4().toString()
const ok = new VersionReq('^1.2').matches(new Version('1.4.0'))crossbind reads the crate's own sources (following `mod` trees, `pub use` re-exports, modules declared inside macros and enabled feature gates) and generates the bridge crate from what it finds. An undeclared `cargo:` import is a hard error — add the crate to `cargoDependencies`.
A crate that keeps its API in modules is imported one public module at a time, with `/` between the crate and each module level. xxhash-rust, for one, exports nothing from its root:
// cargoDependencies: { 'xxhash-rust': '{ version = "0.8", features = ["xxh3"] }' }
import { xxh364, Xxh3 } from 'cargo:xxhash-rust/xxh3'
const digest = xxh364(new TextEncoder().encode('crossbind'))The module has to be public all the way from the crate root and switched on by the features you declare. A private module, one behind a feature you did not enable, or an inline `mod x { … }` block fails the import with the module's name. Every import of one crate shares a single bridge, so a type reached through the root and through a module is the same JS class: a `Params` built with the `params` module's builder goes straight into the root's `Argon2`.
Metro (React Native) resolves against the file list it builds when it starts, so crossbind finds module imports by scanning the app's own JavaScript and TypeScript sources as it loads, skipping `node_modules`, `ios`, `android` and build output. A module specifier assembled at run time, or written in a package outside the app, is missing from that scan; it resolves from the next Metro start, once the first attempt has written its marker.
Two crates may export the same type name (`semver::Version` and `uuid::Version` both do). Each crate registers its bindings under names of its own (prefixed with the crate and the module that defines each item) and the generated module maps them back, so the names you import stay the crate's own — reach for the `cargo:` import rather than the runtime module object, which carries the prefixed spelling.
Write a Rust file next to your other native sources and import it like a header. Upstream crates it uses go into the same `cargoDependencies`:
// src/native/geo_surface.rs
use geo::{ConvexHull, MultiPoint, Point};
pub struct Hull { points: Vec<Point<f64>> }
impl Hull {
pub fn new() -> Self { Hull { points: Vec::new() } }
pub fn add(&mut self, x: f64, y: f64) { self.points.push(Point::new(x, y)); }
pub fn wkt(&self) -> String { /* … */ }
}import { initNative } from './native/native.h';
import { Hull } from './native/geo_surface.rs'A whole crate published as a crossbind package: `export.type: 'cargo'` in its `crossbind.config.js` (see [`crossbind-config.md`](./crossbind-config.md)). crossbind runs `cargo build --release --target <triple>` per platform and stages the `.a` like any prebuilt; consumers import the package name exactly like a C++ package. An app build first builds, in the dependency's own package, a prebuilt that is missing or was built from another embind-rs: each prebuilt records its embind-rs in `crossbind-embind-rs.fingerprint`, because archives from two embind-rs sources do not link together. The wasm `mt` prebuilt builds through the same nightly `-Zbuild-std` path described above (st and mt cargo outputs are kept in separate target dirs — they share a triple but not their std features).
A Node.js app built with `crossbind build -e node` links its Rust packages this way and binds its own `.rs` and `cargo:` imports through the import hooks the build writes ([Node.js](../playbooks/integration/nodejs.md#importing-headers-and-rust-directly)).
| Rust | JavaScript | |------|------------| | `struct` + `impl` methods | class with methods (`Type::new` → constructor) | | a struct with `Default` (derived or `impl D
Import C++ and Rust like JavaScript modules (WebAssembly & React Native)
Contributor context for coding agents working in this repository. Human contributors should start with `README.md` and…
<!-- GENERATED from docs/api/app.md by scripts/build-agent-skill.mjs. Do not edit. -->
<!-- GENERATED from docs/api/build-state.md by scripts/build-agent-skill.mjs. Do not edit. -->
<!-- GENERATED from docs/api/conan.md by scripts/build-agent-skill.mjs. Do not edit. -->
<!-- GENERATED from docs/api/cpp-binding-rules.md by scripts/build-agent-skill.mjs. Do not edit. -->