Ibex is the JavaScript/TypeScript runtime used by Exact and Snapback. It embeds Hermes and exposes a small, stable host ABI so native hosts can create runtimes, evaluate JS/HBC, and install host calls.
Analogous in spirit to node, bun, or deno — a runtime, not an app
framework. The ibex runtime binary lives in this repo. The Exact project CLI
and app framework live in the exact repo.
Status: extracted "for now." This repository was split out of the Exact monorepo as a history-preserving extraction. It will be re-homed under the
expoorg later.
- The
ibex-runtimeRust crate (Hermes bindings insrc/engine/*.cc, the host ABI insrc/host, the module loader, vendored Brotli). - The
ibexruntime binary (src/bin/ibex) for running JavaScript and TypeScript files. - The Hermes build scripts (
scripts/build-hermes-*.sh,download-hermes.sh).
Consumers depend on a deliberately narrow surface (see LLP 0002):
- The lifecycle/evaluation C ABI: production construction uses
ex_hermes_create_armed; the historicalex_hermes_createsymbol always refuses, andex_hermes_create_diagnosticis explicitly non-production. Runtime driving continues throughex_hermes_destroy,ex_hermes_eval,ex_hermes_free_string, and the diagnostic-onlyex_hermes_set_host_call. Armed runtimes silently reject the generic host bridge and expose only dedicated native APIs. - The Rust host ABI:
ibex_runtime::host::{install_host, Host}.
Ibex needs Hermes headers + a prebuilt libhermesvm. Install/build them with
./scripts/download-hermes.sh, which delegates to the platform source builder
and defaults to Hermes 260318099.0.0-stable. The platform-specific entry
points are ./scripts/build-hermes-linux.sh on Linux and
./scripts/build-hermes.sh on macOS/iOS. They install ignored native artifacts
into linux/, ios/Frameworks/, and tools/hermes/. Then:
# default profile
cargo build
# runtime binary
cargo build --bin ibex
# full runtime CLI profile
cargo build --bin ibex --features host-http-server,cli-notify
# full native crypto on Linux
cargo build --features openssl-cryptoRun the local binary with:
cargo run --bin ibex -- --versionbuild.rs auto-detects the standalone layout; HERMES_INCLUDE_DIR and
HERMES_LIB_DIR override the Hermes locations. HERMES_VERSION can override
the source ref passed to the build scripts; scripts/hermes-version.sh holds
the repo default.
The opt-in portable macOS arm64 build path consumes one already installed checkout-local artifact and retained transport instead of the legacy path overrides. It must be entered through the production runner; exporting the selectors and invoking Cargo directly is deliberately refused:
./scripts/run-portable-hermes-cargo.mjs \
--artifact-id "$ARTIFACT_ID" \
--archive-digest "$ARCHIVE_DIGEST" \
--expected-source-revision "$ARTIFACT_SOURCE_REVISION" \
-- build --bin ibexThe runner first invokes the fixed production store verifier. Its checked
promotion admission keeps the artifact source revision A distinct from the
clean checkout revision: diagnostic A has authorized:false and current A;
an admitted production checkout has pairwise-distinct source A, promotion
topic P, and merge C with authorized:true. Any other D checkout is refused,
not downgraded to diagnostic mode. Only after fresh offline provenance and
reconstructive store verification does the runner mint a random, private,
one-use capability and launch Cargo itself. build.rs claims that live
capability before opening any artifact or host tool; it rechecks no-follow
ancestry, ownership, modes, ACLs, link counts, the checked Cargo target map,
rustc wrapper, and canonical LF-terminated promotion admission, then joins the
receipt back to the exact manifest, installation receipt, policy, bundle,
archive, and fresh verifier result. Stale/copied receipts and direct Cargo
invocations fail closed. The checked admission is embedded as a separate
compile-time record so A and C retain the same frozen build-consumption v1
artifact identity; legacy builds embed exactly null\n for that record.
Every portable hermesc version probe and compilation runs through its
digest-bound compatibility contract with a cleared environment, empty stdin,
exact argv[0], a fresh private working directory, and one deadline covering
the entire supervised process group, pipe drain, and pinned output checks. A
tool that leaves descendants behind is refused. The output-aware rustc wrapper
derives Cargo's checked executable set and gives each normal bin, unit/integration
test, example, or bench exactly one depth-correct loader-relative rpath; it
does not install both possible depths. Absolute checkout/store rpaths remain
for legacy non-authoritative builds only.
This is still a Phase 1 build-input slice. A real private offline-verifiable artifact corpus is required for the production runner, and the post-link and runtime-mapping gates must land before this can enable production REPL, conformance promotion, target attestations, or advertisements.
Linux native networking requires pkg-config and libcurl >= 7.86 so Fetch and
WebSocket use libcurl. For constrained local builds only,
IBEX_ALLOW_CURL_CLI_FALLBACK=1 enables a degraded fetch-only fallback that
shells out to curl; WebSocket remains unavailable in that fallback profile.
Android builds consume the same Maven/PREFAB artifacts Android apps already use:
com.facebook.hermes:hermes-android for Hermes and
com.facebook.react:react-android for JSI. Install/extract them, then build
through the NDK wrapper:
./scripts/install-android-hermes.sh
ANDROID_TARGET=aarch64-linux-android ./scripts/cargo-android.shAndroid currently requires --features openssl-crypto; the wrapper includes it
by default. Native Android fetch/WebSocket use OkHttp through the Android
Java/JNI bridge in platform/android/java/dev/ibex/runtime/IbexNetworking.java.
The same bridge provides Android clipboard, raw DNS, location, camera
permission/device metadata, locale, screen, appearance/accessibility, app
lifecycle/configuration/deep-link events, and platform-version data to the JS
runtime.
Embedding apps must include that Java source, add OkHttp to the Android
classpath (for example implementation("com.squareup.okhttp3:okhttp:5.4.0")),
and call ex_android_initialize(JavaVM*, Context) before creating a runtime
that should observe Android platform data or use networking APIs. The wrapper
also sets EXACT_ALLOW_FALLBACK=1 unless already set, so
AAR-based builds can use bootstrap JS source when no matching host hermesc is
installed. HERMES_ANDROID_VERSION, REACT_ANDROID_VERSION,
ANDROID_HERMES_VARIANT, and ANDROID_API are overrideable. The default
Android artifact pair is hermes-android:250829098.0.14 with
react-android:0.86.0, because Maven Central does not yet publish
hermes-android:260318099.0.0 and the JSI PREFAB must include
jsi/hermes-interfaces.h.
openssl-crypto— full native crypto on Linux via OpenSSL, including hashing/HMAC, AES, PBKDF2/scrypt/HKDF, asymmetric sign/verify/key generation, and key import/export. Optional on macOS.- Android — currently uses the
openssl-cryptoprofile with vendored OpenSSL. - default (no OpenSSL) — uses platform crypto on Apple/Windows. On Linux it
now builds without OpenSSL and provides the reduced portable surface used by
core runtime flows: MD5/SHA-1/SHA-2 hashing, HMAC, PBKDF2, scrypt, and HKDF.
Linux AES and asymmetric crypto still require
openssl-crypto.
MIT — see LICENSE. Vendored and linked third-party software is inventoried in THIRD-PARTY-NOTICES.md, including the MIT-licensed Hermes engine this runtime embeds and patches.