Skip to content

Prototype LLRT native executor and package#14

Merged
robinbraemer merged 4 commits into
mainfrom
codex/llrt-executor-poc
Jun 16, 2026
Merged

Prototype LLRT native executor and package#14
robinbraemer merged 4 commits into
mainfrom
codex/llrt-executor-poc

Conversation

@robinbraemer

@robinbraemer robinbraemer commented Jun 10, 2026

Copy link
Copy Markdown
Member

Summary

This PR prototypes an LLRT-first execution path for codemode and prepares a standalone TypeScript-friendly @robinbraemer/llrt package.

It includes:

  • A new packages/llrt package with a napi-rs Rust binding around LLRT's Rust VM API.
  • A JSON-safe LlrtRuntime.callJson<TInput, TOutput>() API with typed success/failure results, memory/wall-time/stack options, host callbacks, fresh VM per call, and tests for errors, isolation, callbacks, memory, timeout, and stress behavior.
  • Optional native package layout for darwin/linux arm64/x64, native artifact verification scripts, packed-install smoke testing, and a GitHub Actions native matrix workflow.
  • Codemode integration via LlrtNativeExecutor, createExecutor() preference for LLRT when installed, and fallback executors left in place.
  • An LLRT process executor proof of concept for comparison.
  • Benchmark tooling and a saved report comparing llrt-native, isolated-vm, and QuickJS WASM.
  • Design and implementation notes under internal/superpowers/.
  • Release-ready package metadata for @robinbraemer/llrt@0.1.0 and @robinbraemer/codemode@0.3.0.

Verification

Local verification:

  • mise exec -- task ci
  • mise exec -- pnpm --filter @robinbraemer/llrt exec vitest run test/package-publication.test.ts test/native-artifact-verifier.test.ts
  • mise exec -- pnpm --filter @robinbraemer/codemode exec vitest run test/package-publication.test.ts
  • mise exec -- pnpm --filter @robinbraemer/llrt run verify:native-artifacts
  • mise exec -- pnpm --filter @robinbraemer/llrt run smoke:packed-install
  • mise exec -- pnpm --filter @robinbraemer/codemode run benchmark:executors -- --report internal/superpowers/reports/2026-06-10-llrt-executor-benchmark.md --json internal/superpowers/reports/2026-06-10-llrt-executor-benchmark.json
  • mise exec -- go run github.com/rhysd/actionlint/cmd/actionlint@latest .github/workflows/*.yml

GitHub verification on head e74ef1f:

  • CI: pass
  • LLRT Native Packages / Build darwin-arm64: pass
  • LLRT Native Packages / Build darwin-x64: pass
  • LLRT Native Packages / Build linux-arm64-gnu: pass
  • LLRT Native Packages / Build linux-x64-gnu: pass
  • LLRT Native Packages / Package LLRT: pass

Current verdict

LLRT is now a strong default candidate for codemode. This PR proves the practical package boundary: importable TypeScript API, napi-rs bridge, fresh VM isolation, JSON-safe host callbacks, resource controls, codemode executor compatibility, reproducible native artifacts across the target runner matrix, and packed-install smoke coverage.

The production adoption still needs a separate CNAP-side package consumption change after this package is merged/released. Keep fallback engine selection available for emergency rollback while LLRT becomes the preferred/default executor.

Handoff prompt for the next AI agent

You are continuing the LLRT-first runtime adoption work after this cnap-tech/codemode PR. Preserve the current direction unless evidence contradicts it: standalone @robinbraemer/llrt package first, codemode consumes it through a thin adapter, fallback engines remain available for rollback.

Completed in this PR:

  • packages/llrt exists as a standalone Node/TypeScript package backed by a Rust napi-rs addon.
  • Public API is LlrtRuntime.callJson<TInput, TOutput>() with typed LlrtResult<TOutput>.
  • Host callbacks are explicit and JSON-safe; no arbitrary live object injection.
  • Each execution creates a fresh LLRT VM.
  • Runtime/call options include memoryMB, wallTimeMs, cpuTimeMs placeholder, and maxStackBytes.
  • Native binding uses LLRT/rquickjs APIs and reports typed errors such as TIMEOUT, MEMORY_LIMIT, SERIALIZATION_ERROR, EVALUATION_ERROR, NATIVE_LOAD_ERROR, and RUNTIME_DISPOSED.
  • Codemode has LlrtNativeExecutor; createExecutor() prefers LLRT when @robinbraemer/llrt is installed, falls back only when the LLRT package itself is missing, and fails loudly when installed LLRT is broken.
  • isolated-vm, QuickJS WASM, and LlrtProcessExecutor remain available.
  • Native packages are laid out under packages/llrt/npm/* for darwin/linux arm64/x64.
  • .github/workflows/llrt-native.yml builds and packages all native artifacts.
  • verify:native-artifacts validates optional native package manifests; strict mode also requires .node files after artifacts are downloaded.
  • smoke:packed-install packs main + current native package and tests import/execution from a temporary consumer project.
  • Benchmark tooling exists at packages/codemode/scripts/benchmark-executors.ts, with a saved report at internal/superpowers/reports/2026-06-10-llrt-executor-benchmark.md.
  • Design/spec notes live at internal/superpowers/specs/2026-06-10-standalone-llrt-typescript-runtime-design.md and internal/superpowers/plans/2026-06-10-standalone-llrt-calljson.md.

Recommended next steps:

  1. Merge this PR and publish @robinbraemer/llrt@0.1.0 plus @robinbraemer/codemode@0.3.0 using the repository's release process.
  2. In the CNAP repo, update the codemode dependency to the released codemode package and explicitly install @robinbraemer/llrt so the optional peer is present in production.
  3. Change CNAP's codemode service executor selection to use the LLRT executor by default on Node, keeping a direct fallback switch to isolated-vm or QuickJS for rollback.
  4. Add CNAP-side tests around executor selection and at least one representative codemode execution path.
  5. Run focused CNAP verification for the codemode domain package, then the repo-required preflight if preparing a CNAP PR.
  6. Only remove fallback engines after production telemetry shows LLRT is stable under real CNAP workloads.

Important local caveats:

  • Use mise exec -- ... for codemode verification so Node stays at the pinned Node 24 ABI. Running raw task ci under Node 26 can fail because isolated-vm was built for Node 24.
  • .codex/ is unrelated and should not be committed.
  • Generated native binaries, dist/, node_modules/, packages/llrt/vendor/, packages/llrt/native/target/, *.node, and *.tgz are intentionally ignored.

Rationale: Explore LLRT as the preferred lightweight execution runtime by adding a standalone TypeScript-friendly @robinbraemer/llrt package, napi-rs native bridge, codemode executor adapter, native packaging workflow, and benchmark/stress evidence.

Rejected: Do not replace the fallback executors yet; LLRT still needs a real GitHub Actions native matrix run and artifact inspection before production-default adoption. Do not embed LLRT directly into codemode; the standalone package keeps native packaging and runtime API reusable.

Risk: Introduces a new Rust/native package and release workflow. The prototype is intentionally JSON-safe and fresh-VM-per-call, which is safer but may leave reusable-VM performance for later.

Tested: mise exec -- task ci; mise exec actionlint -- actionlint .github/workflows/*.yml; mise exec -- pnpm --filter @robinbraemer/llrt run verify:native-artifacts; mise exec -- npm pack --dry-run from packages/llrt; benchmark:executors report generation.

Not-tested: Real GitHub Actions native matrix run across macOS and Linux runners; publishing to npm; CNAP repository consumption of the published package.
Rationale: Clean CI failed because codemode typechecked and tested against the LLRT workspace package before its dist entry existed, and the native packaging workflow installed the whole workspace, pulling in codemode's isolated-vm dependency on macOS x64. Build LLRT before recursive typecheck, scope native packaging installs to the LLRT workspace, and run native-only LLRT suites only when a native binding is available or after the native matrix builds one.

Rejected: A root tsconfig path alias to LLRT source broke codemode's rootDir boundary. A full duplicated LLRT declaration in codemode would reduce build coupling but created a larger drift surface, so the peer declaration is limited to the runtime shape codemode consumes. Building LLRT native in regular CI was also rejected because the existing native matrix is the right owner for platform-specific native execution coverage.

Risk: The lint task now does one small LLRT tsup build before typecheck. Regular CI skips native-only LLRT runtime coverage when no binary exists, but the native matrix now forces that suite after each platform build with LLRT_REQUIRE_NATIVE_TESTS=1. The codemode optional-peer declaration can drift if the LLRT runtime call shape changes, but it is intentionally narrow and CI still builds/tests against the real workspace package.

Tested: rm -rf packages/llrt/dist && mise exec -- pnpm --filter @robinbraemer/codemode run typecheck

Tested: mise exec -- pnpm --filter @robinbraemer/llrt exec vitest run test/native-loader.test.ts test/native-prebuild-workflow.test.ts

Tested: mise exec -- pnpm --filter @robinbraemer/codemode exec vitest run test/llrt-native-executor.test.ts

Tested: no-native simulation: temporarily move packages/llrt/*.node and packages/llrt/native/*.node, then mise exec -- task ci

Tested: mise exec -- go run github.com/rhysd/actionlint/cmd/actionlint@latest .github/workflows/*.yml

Tested: mise exec -- task ci
@robinbraemer robinbraemer force-pushed the codex/llrt-executor-poc branch from f10087a to d0120d1 Compare June 16, 2026 10:43
Rationale: The LLRT executor PR now has green native builds, but the new packages still used placeholder 0.0.0 versions and codemode declared an unusable exact LLRT peer. This prepares the first publishable LLRT package and the codemode release that can consume it.

Rejected: Keeping the peer dependency tied to the local workspace version was avoided because codemode should encode the LLRT API floor instead of forcing every compatible LLRT patch release as the new minimum.

Risk: Consumers must install @robinbraemer/llrt ^0.1.0 when they opt into the LLRT executor; the package remains an optional peer from codemode's perspective.

Tested: mise exec -- pnpm --filter @robinbraemer/llrt exec vitest run test/package-publication.test.ts test/native-artifact-verifier.test.ts

Tested: mise exec -- pnpm --filter @robinbraemer/codemode exec vitest run test/package-publication.test.ts

Tested: mise exec -- pnpm --filter @robinbraemer/llrt run verify:native-artifacts

Tested: mise exec -- task ci
@robinbraemer robinbraemer marked this pull request as ready for review June 16, 2026 11:42
Rationale: npm trusted publishing performs its OIDC token exchange through npm publish, so release jobs should publish from package directories with the npm CLI instead of pnpm publish.

Rejected: Keeping --no-git-checks was avoided because npm treats it as an unknown git-checks config and warns that this will stop working in a future major version.

Risk: Release publishing behavior changes only at the final npm publish steps; build, pack, native artifact, and smoke checks stay unchanged before publish.

Tested: mise exec -- pnpm --filter @robinbraemer/llrt exec vitest run test/native-prebuild-workflow.test.ts

Tested: mise exec -- pnpm --filter @robinbraemer/codemode exec vitest run test/package-publication.test.ts

Tested: mise exec -- go run github.com/rhysd/actionlint/cmd/actionlint@latest .github/workflows/*.yml

Tested: mise exec -- task ci
@robinbraemer robinbraemer merged commit af74c78 into main Jun 16, 2026
6 checks passed
@robinbraemer robinbraemer deleted the codex/llrt-executor-poc branch June 16, 2026 12:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant