This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Node-RC is a high-performance runtime controller for executing code across multiple programming languages (Python, JavaScript, TypeScript, C, Java, Ruby, Go) from TypeScript. It uses Rust via NAPI bindings for maximum performance. JavaScript and TypeScript use QuickJS embedded interpreter for fast cold starts (<200μs) and predictable performance metrics ideal for AI agent tracing.
LLVM 18 is REQUIRED - This is a hard dependency that must be installed and properly configured:
# macOS
brew install llvm@18
export LLVM_SYS_180_PREFIX=$(brew --prefix llvm@18)
# Linux
wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh 18
export LLVM_SYS_180_PREFIX=/usr/lib/llvm-18
# Add to ~/.bashrc or ~/.zshrc to persist# ALWAYS set LLVM path first
export LLVM_SYS_180_PREFIX=$(brew --prefix llvm@18) # macOS
# export LLVM_SYS_180_PREFIX=/usr/lib/llvm-18 # Linux
# Build everything (native + TypeScript)
npm run build
# Build components separately
npm run build:native # Rust NAPI bindings (requires LLVM 18 + Rust toolchain)
npm run build:ts # TypeScript compilation
# Testing
npm test # Run all tests
npm run test:watch # Watch mode
npm run test:coverage # With coverage report
jest path/to/test.ts # Run specific test file
# Performance benchmarks
npm run bench
# Development workflow (typical order)
export LLVM_SYS_180_PREFIX=$(brew --prefix llvm@18) # Set LLVM first
cd native && cargo check # Quick Rust syntax check
npm run build:native # Build Rust bindings
npm run build:ts # Compile TypeScript
npm test # Verify everything worksjest --testNamePattern="Python" # Test Python interpreter only
jest --testNamePattern="JavaScript" # Test JavaScript interpreter only
jest --testNamePattern="Ruby" # Test Ruby interpreter only
# etc...-
TypeScript API Layer (
/src)RuntimeControllerclass provides the main entry point- Each language has its own interpreter class extending
BaseInterpreter - Simple API design:
rc.PythonInterpreter().execute(code) - All interpreters share common interfaces from
types.ts
-
Rust NAPI Layer (
/native)- Actual runtime implementations using native libraries
lib.rsexposes NAPI bindings to TypeScript- Each language has its own runtime module:
python_runtime.rs→ PyO3 for native Python executionjavascript_runtime.rs→ Porffor AOT compiler to WASMtypescript_runtime.rs→ Porffor native TypeScript to WASMc_runtime.rs→ LLVM/clang to WASM compilationjava_runtime.rs→ javac compilation with WASM executionruby_runtime.rs→ System Ruby or mrubygo_runtime.rs→ Go/TinyGo to WASM compilationwasm_runtime.rs→ Wasmtime for WASM execution
- Lazy Initialization: Native NAPI bindings are loaded lazily on first use to avoid startup costs
- Interpreter Lifecycle: Each interpreter maintains an
instanceIdfor tracking in Rust - Execution Flow: TypeScript → NAPI call → Rust runtime → Result with metrics
- Native Module Structure:
native/index.js- Platform-specific loader for .node filesnative/package.json- NAPI configuration and build metadatanative/build.rs- Python linking configuration for PyO3
- Controller Pattern:
RuntimeControllermanages native binding initialization and interpreter creation - Tracing: When enabled, captures variables, call stacks, and memory snapshots
- Sandboxing: Three levels (strict/moderate/relaxed) enforced at Rust level
- WASM Compilation: C, Java, and Go compile to WASM for sandboxed execution
- Error Handling: All runtimes gracefully handle missing dependencies (e.g., clang, javac)
| Language | Runtime | Implementation Status |
|---|---|---|
| Python | PyO3 | ✅ Fully functional |
| JavaScript | QuickJS embedded | ✅ Production ready (full ECMA-262) |
| TypeScript | QuickJS + type stripping | ✅ Production ready (regex-based TS support) |
| C | LLVM/clang → WASM | ✅ Fully functional |
| Java | javac + WASM wrapper | ✅ Fully functional |
| Ruby | System Ruby / mruby | ✅ Fully functional |
| Go | Go/TinyGo → WASM | ✅ Fully functional |
jest src/__tests__/runtime-controller.test.ts -t "should execute simple Python code"RUST_BACKTRACE=1 npm test # Get full backtrace on Rust panics
RUST_LOG=debug npm test # Enable Rust debug logging
# Rebuild after Rust changes
cd native && cargo clean && cd .. && npm run build:native# If getting "cannot find module" errors for native binding
npm run build:native # Ensure native module is built
ls native/*.node # Verify .node files exist
# If getting Python symbol errors
export LLVM_SYS_180_PREFIX=$(brew --prefix llvm@18) # Set LLVM path
cd native && cargo clean && cargo build --release # Clean rebuildnpm run test:coverage -- --detectLeaks- LLVM 18 is REQUIRED - Must be installed and
LLVM_SYS_180_PREFIXset for inkwell crate - Python runtime requires PyO3 and Python dev headers
- Java runtime requires javac (JDK) installed
- Ruby runtime requires Ruby or mruby installed
- Go runtime requires Go or TinyGo installed
- Use
cargo checkfor quick syntax validation before full build - Release builds use aggressive optimizations (LTO, strip, opt-level=3)
build.rshandles Python linking configuration for PyO3 integration- Native module files (
native/index.js,native/package.json) are critical for NAPI builds
- Lazy Initialization Pattern: Native bindings loaded via
controller.getNativeController() - RuntimeController handles native module initialization and lifecycle
- Base interpreter class provides common functionality (tracing, error handling, etc.)
- All interpreter classes extend
BaseInterpreterinsrc/interpreters/base.ts - Each interpreter has unique
instanceIdfor Rust-side tracking - All public types exported from
src/types.ts - Tests use Jest with ts-jest preset
- Create Rust runtime in
native/src/{language}_runtime.rs - Add runtime module to
native/src/lib.rs(import and execution match) - Add compile/execute methods to
native/src/lib.rsRuntimeController impl - Create TypeScript interpreter in
src/interpreters/{language}.tsextendingBaseInterpreter - Add language to
Languageenum insrc/types.ts - Export from
src/interpreters/index.ts - Add factory method to
RuntimeControllerclass insrc/index.ts - Write tests in
src/__tests__/runtime-controller.test.ts - Update native type definitions in
native/index.d.ts
- Cold start: <1ms (achieving 100-200μs for JS/TS with QuickJS, 100-1000μs for others)
- Memory overhead: <10MB per interpreter (1-2MB for JS/TS with QuickJS)
- Concurrent execution: 100+ interpreters
- Compilation time: <5ms for QuickJS validation, <50ms for WASM compilation
- Windows support untested
- QuickJS has full ECMA-262 support but runs as embedded interpreter (not compiled)
- WASI threading limitations (single-core only)
- TeaVM integration pending for improved Java → WASM compilation
- Native bindings must be built locally (not pre-compiled)
- TypeScript support uses regex-based type stripping (not full TSC)