Cross-language native dependency manager. Detect host lang, add libs via CLI, expose them in-process with equilibrium-ffi.
rig add --rust <crate>
rig up
rig ui <pkg>
rig dr
Host projects consume native libs in-process; any cargo crate can be exposed into a non-Rust host, and a TypeScript host builds with scriptc through equilibrium-ffi --ffi bindings.
cargo install rigpkgOr from git:
cargo install --git https://github.com/tschk/rigBoth install the rig binary.
rig initWrites rig.toml + empty rig.lock. Detects host language from markers (Cargo.toml, build.zig, *.nimble, tsconfig.json, ...).
rig add --rust <crate>
rig i --cargo <crate>
rig add --zig some_libAliases: i, install (short package-manager aliases).
Resolves the package, pins it in rig.toml / rig.lock, and auto-exposes a native in-process surface:
- Rust host <- cargo crate: adds the dep to
Cargo.tomland generatessrc/rig_bindings/<pkg>.rs(re-export + markers). - Zig host <- cargo crate: builds a
{crate}_fficdylib facade (markers:{crate}_abi_version/_version/_name), writessrc/rig_bindings/<pkg>_bindings.zig, and patchesbuild.zigwith// rig-expose-beginlink markers. - Nim host <- cargo crate: builds the same facade and writes
src/rig_bindings/<pkg>.nim(importc+passLlink hints). - C/C++ host <- cargo crate: builds the same facade and writes
src/rig_bindings/<pkg>.h(declarations +-L/-lmetadata macros). - C# host <- cargo crate: builds the same facade and writes
src/rig_bindings/<pkg>.cs(DllImportP/Invoke wrappers). - D host <- cargo crate: builds the same facade and writes
src/rig_bindings/<pkg>.d(extern(C)+pragma(lib)). - V host <- cargo crate: builds the same facade and writes
modules/<pkg>/<pkg>.v(#flag+fn C.decls +pub fnwrappers so a host canimport pkgand callpkg.add(...)). - Odin host <- cargo crate: builds the same facade and writes
src/rig_bindings/<pkg>.odin(foreign import+foreignblock). - Hare host <- cargo crate: builds the same facade and writes
src/rig_bindings/<pkg>.ha(@symbolC ABI decls +-L/-lhints). - TypeScript host <- cargo crate: builds the same facade and writes
src/rig_bindings/<pkg>.ts(export declare functiondecls) plus that dependency's<pkg>.ffi.json, merged into the host manifestsrc/rig_bindings/rig.ffi.jsonthat scriptc builds with. - C/C++/Zig/Nim/V/Odin/Hare/C#/D/TypeScript host <- path/git c|cpp|zig|nim|v|odin|hare: compiles into
target/rig/<pkg>/lib*_native.{dylib,so}when feasible (flat sources, Makefile$OUT, CMake, meson, or language toolchain); clear error if the toolchain is missing. Simple C prototypes from discovered headers (and Zigexport fnwhen the dep is Zig) are emitted into Nim/V/Zig/Odin/Hare/C#/D binders; the TypeScript binder parses those headers into scriptc declarations. Hare path/git is skipped with that error whenhareis not onPATH(rig does not install a toolchain). - Rust host <- foreign lang: generates an equilibrium-ffi
loadpath stub.
Ecosystem flags (mutually exclusive): --cargo/--rust, --zig, --nim, --c, --cpp, --v, --d, --odin, --hare, --csharp/--cs.
rig up
rig upgrade <pkg>rig ui <pkg>
rig rm <pkg>Aliases: rm, ui, uninstall.
rig ls
rig s serde
rig search --nim jester
rig search --d vibe
rig search --csharp Newtonsoft.Json
rig search --zig http # GitHub hints; no central Zig registry
rig search --c foo # clear unsupported (use path:/git+)
rig show <pkg>
rig info --nim jester
rig outdatedRegistry-backed today: cargo (crates.io), nim (nimble packages.json), d (code.dlang.org), csharp (NuGet).
zig accepts path: / git+ / https:// pins (search is hint-only).
c / cpp / v / odin / hare are path/git pins only.
rig lock
rig syncrig dr
rig check --fix --full
rig buildrig build runs the host toolchain with the exposed surface wired in: cargo build for a Rust host, zig build for a Zig host, and for a TypeScript host it runs scriptc build <entry>.ts --ffi <merged manifest>, passing anything after -- through:
rig build -- src/main.ts -o host # scriptc: build src/main.ts into ./hostrig init # tsconfig.json / package.json -> host: typescript
rig add --rust crc32fast # any cargo crate, or --c/--zig/... for path/git
rig build -- src/main.ts -o host
./hostrig add writes one declaration module per dependency and merges every dependency's manifest into src/rig_bindings/rig.ffi.json, because scriptc takes a single --ffi manifest per build. Import the module and call the functions; rig has no npm resolver, so the ecosystem is always named (--rust, --c, …).
scriptc's consumer classes are narrower than a C header — f64/bool/u8/u32/i32/void returns, the same scalar parameters, and length-delimited const uint8_t * + size_t spans (as Uint8Array) — so signatures outside that surface (pointer/struct returns, out-buffers, i64) are skipped with a warning naming the reason instead of being mistyped. Native libraries are recorded by absolute path, so the built host keeps running until the project moves; rig sync / rig build re-links it.
examples/zig-host-multi: Zig <- multiple cargo crates (rx4+sha2) via the generic facade.examples/zig-host-rx4: Zig <-rx4via a thinrx4_ffifacade + equilibrium-ffi.examples/c-host-sha2: C <-sha2markers +sha2_hash_256/sha2_hash_512(cc+-lsha2_ffi).examples/c-host-libm: C <- auto-wrappedlibm(libm_sqrt, ...) beyond markers.examples/ts-host-crc32fast: TypeScript <-crc32fastvia scriptc--ffibindings.
cd examples/zig-host-multi
rig sync
zig build runFor every rig add --rust <crate> on a Zig (or other non-Rust) host, rig generates a thin cdylib under .rig/shims/<crate>/ (unless the crate already ships crate-type = ["cdylib"], in which case that library is linked through):
| Symbol | Meaning |
|---|---|
{crate}_abi_version |
Facade ABI revision (u32) |
{crate}_version |
Null-terminated version string |
{crate}_name |
Null-terminated crate name |
Known enrichments (today: rx4, sha2, crc32fast, md-5, hex, base64) may export additional methods beyond the markers (e.g. rx4_prompt_smoke, sha2_hash_256, hex_encode, base64_encode).
For other crates, rig auto-wraps a scanned public surface when sources are available (cargo registry / path / crates.io fetch):
- Existing
#[no_mangle] extern "C"functions are re-exported under the same name. - Plain
pub fn/pub const fnwith only FFI-safe scalar/pointer types become{crate}_{fn}exports (facade ABI 2). &strand&[u8]auto-wrap as a (*const u8,usizelen) pair (explicit length; not NUL-terminated).- Host binders (Zig/Nim/C/C#/D/V) emit the discovered declarations; V also emits
pub fnwrappers overC.<export>. See.rig/shims/<crate>/surface.json.
- Skipped: generics,
async,implmethods/traits, tuples/arrays, other refs,String/Vec,f16/f128,Option<scalar>(non-niche), and other non-FFI-safe types. - Wrapped slices:
&str/&[u8]as pointer+len (UTF-8 checked for&str; invalid UTF-8 early-returns). - Wrapped niches (safe):
Option<*T>/Option<NonNull<T>>/NonNull<T>/NonZero*/*const ()/*mut (), plus morecore::ffi::c_*aliases;extern "C-unwind"treated likeextern "C". - cbindgen runs only when the crate ships
cbindgen.tomland thecbindgenbinary is onPATH(provenance header only; scan remains canonical). - Crates with
#![forbid(unsafe_code)]still work: unsafe lives only in the generated facade. - Auto-wrap caps at 256 symbols per crate; enrichments remain intentional for trait-heavy APIs (e.g.
sha2_hash_256). - Rust hosts keep the native Cargo re-export path (
src/rig_bindings/<pkg>.rs); the cdylib facade is for cross-language hosts.
See committed example rig.toml. Schema:
[host].language: rust | zig | nim | c | cpp | v | d | odin | hare | csharp[dependencies.<name>]: ecosystem, version, git/path, features, expose[expose].dir: defaultsrc/rig_bindings(usesrc/vendorfor Zig/C imports)
Lockfile: rig.lock (commit it).
| Language | Markers |
|---|---|
| Rust | Cargo.toml |
| Zig | build.zig, build.zig.zon |
| Nim | *.nimble, nimble.paths |
| D | dub.json, dub.sdl |
| C# | *.csproj, *.sln |
| V | v.mod |
| Odin | ols.json, *.odin |
| Hare | *.ha |
| C / C++ | CMakeLists.txt, meson.build, Makefile + sources |
Equilibrium-supported set: V, Zig, C, C++, C#, Rust, D, Nim, Odin, Hare.
ISC
GitHub Actions runs fmt / clippy -D warnings / cargo test on Ubuntu + macOS (+ Windows tests).
An optional path-c-smoke job on Ubuntu exercises flat-C and CMake path/git fixtures via scripts/ci-smoke-path-c.sh (cmake/ninja; meson when present).
scripts/ci-smoke-path-extra.sh tries a Zig path fixture when zig is on PATH (skipped otherwise). Nim/V/Odin/Hare e2e compile smokes run locally when those toolchains are present (cargo test skips them quietly on stock CI).