Architecture Overview & C ABI
Relevant source files
The following files were used as context for generating this wiki page:
The RunAnywhere project utilizes a cross-platform architecture where a single C++ core library, known as runanywhere-commons, implements all AI business logic. This core library exposes a pure C ABI (Application Binary Interface) prefixed with rac_*, allowing various platform SDKs—such as Swift, Kotlin, React Native, Flutter, and Web—to bind to it consistently. The architecture follows the principle that logic stays at the lowest possible layer to serve all consumers, ensuring that features like LLM, STT, and TTS are handled uniformly across all 5 SDKs.
Sources: AGENTS.md:73-82, core/README.md:3-10, core/AGENTS.md:12-16
The core library manages model lifecycles, plugin registries, download orchestration, and inference routing. It acts as the "source of truth" while platform-specific SDKs serve as thin bridges that provide I/O services, such as file access and network transport, back to the C++ core through inversion-of-control structures.
Sources: AGENTS.md:30-41, core/AGENTS.md:92-105
Core Architecture Layers
The architecture consists of a multi-layer stack that separates high-level API definitions from low-level hardware inference.
Diagram shows the flow from platform-specific SDKs through the C ABI into the core registry, which then dispatches tasks to specific backend engines.
Sources: core/README.md:13-39, core/AGENTS.md:89-105
C ABI and Plugin vtable
All backends publish a rac_engine_vtable_t with 10 active primitive slots. The rac_plugin_find() function performs an ABI-versioned vtable handshake to select the highest-priority plugin for a specific primitive. The current version, ABI v9, widened the streaming callback function to include token deltas and added token count estimations.
Sources: core/AGENTS.md:144-159, AGENTS.md:138-144
| Primitive | vtable Field | Key Backends |
|---|---|---|
| GENERATE_TEXT | llm_ops | llamacpp, qhexrt, platform, neurt (Apple) |
| TRANSCRIBE | stt_ops | sherpa, qhexrt |
| SYNTHESIZE | tts_ops | sherpa, platform, qhexrt |
| VLM | vlm_ops | llamacpp, qhexrt |
| EMBED | embedding_ops | llamacpp, onnx |
| DETECT_VOICE | vad_ops | sherpa, energy-based (built-in) |
| Sources: core/AGENTS.md:161-172, core/README.md:46-56 |
Inversion of Control (Platform Adapters)
The C++ core never calls platform APIs directly. Instead, it uses rac_platform_adapter_t, a C struct of function pointers populated by each SDK during initialization. This allows the core to remain agnostic of the underlying operating system.
Sources: AGENTS.md:133-136, core/AGENTS.md:174-177
Sequence diagram illustrating how the C++ core delegates platform-specific I/O tasks back to the host SDK via the platform adapter.
Sources: core/AGENTS.md:174-185, bindings/kotlin/AGENTS.md:69-75
The platform adapter includes mandatory and optional slots:
- Mandatory Slots:
file_exists,file_read,file_write,file_delete,secure_get/set/delete,log, andnow_ms. - Optional Slots:
get_memory_info,http_download/cancel, andfile_list_directory.
Sources: core/AGENTS.md:178-185
Initialization Phases
Initialization occurs in two distinct phases across all SDKs to ensure low-latency startup.
Sources: AGENTS.md:137-141, bindings/kotlin/AGENTS.md:77-87
Phase 1: Synchronous Setup
Executes in approximately 1-5ms. It performs the following:
- Loads native libraries (e.g.,
System.loadLibraryon Android). - Registers the platform adapter and HTTP transport hooks.
- Configures logging and telemetry.
- Sets up model-path base directories.
Sources: bindings/kotlin/AGENTS.md:79-82, bindings/react-native/AGENTS.md:214-220
Phase 2: Asynchronous Services
Handles network-bound and heavy I/O tasks:
- Authenticates with the backend.
- Registers the device.
- Fetches model assignments.
- Discovers already downloaded models.
Sources: bindings/kotlin/AGENTS.md:84-87, bindings/react-native/AGENTS.md:221-224
Data Models and Protobuf
The project uses Protobuf IDL schemas (idl/*.proto) as the canonical source for all data structures. These schemas are used to generate type-safe bindings for every supported language. Platform SDKs often exchange data with the C++ core by passing serialized Protobuf byte arrays.
Sources: AGENTS.md:108-111, bindings/react-native/AGENTS.md:243-247, bindings/kotlin/AGENTS.md:112-118
JNI and Bridge Mechanisms
Depending on the platform, the C ABI is wrapped using different bridge technologies:
- Kotlin (Android): Uses JNI (
librunanywhere_jni.so) to bridge therac_*functions to theRunAnywhereBridgeexternal function declarations. - React Native: Uses NitroModules (JSI HybridObject) for a zero-serialization bridge, providing direct access to native memory.
- Swift: Uses XCFrameworks and a module map to expose the C headers as a Swift module.
Sources: AGENTS.md:92-100, bindings/kotlin/AGENTS.md:90-95, bindings/react-native/AGENTS.md:113-118
Subsystem Management
The core library implements specialized managers for different aspects of the AI lifecycle:
- Lifecycle Manager: Manages model loading and unloading with reference counting to prevent unloading during active inference.
- Plugin Registry: Handles static and dynamic loading of backends. Backends like
llamacppandsherpa-onnxregister their vtables here. - Event System: Emits
runanywhere.v1.SDKEventpayloads for telemetry and public SDK notifications.
Sources: core/AGENTS.md:236-241, core/AGENTS.md:212-219
Class diagram showing the relationship between the global SDK state and the plugin vtables used for inference.
Sources: core/AGENTS.md:212-215, core/AGENTS.md:144-150
Conclusion
The RunAnywhere architecture centers on a robust C++ core and a stable C ABI. This design ensures that complex AI logic, such as RAG session management and model download orchestration, remains consistent across platforms. By utilizing inversion-of-control via platform adapters and standardized Protobuf schemas, the project achieves high portability and performance while allowing platform-specific SDKs to remain thin, ergonomic wrappers.
Sources: core/README.md:120-128, AGENTS.md:133-144, core/AGENTS.md:89-105