Skip to content

ADR-0007: Use Python as the Host Runtime and Extension Interface

  • Status: Accepted
  • Date: 2026-05-19

Context

runex targets a specific operational shape:

  • local-first runtime
  • low operational overhead
  • weak-hardware-friendly deployment
  • extension by dropping files into an extension directory
  • minimal dependency footprint

The project is intended to run not only on developer laptops, but also on lower-performance environments such as:

  • Raspberry Pi class devices
  • small ARM machines
  • embedded or edge-like local systems

runex also relies on a dynamic extension model:

  • KERNELS modules
  • DataSourceSpec source extensions
  • SinkSpec sink extensions

These extensions are discovered and loaded at runtime from Python files.

This makes the host language choice architecturally significant. The question is not only "what language implements the engine fastest?" but:

what host runtime best supports low-friction extension, local deployment, and weak-hardware operation?

Decision

We use Python as the host runtime and extension interface language.

This decision is paired with SQLite as the local durable store.

The key point is:

Python is not only the implementation language; it is also the extension interface language of the runtime

That means:

  1. kernels are registered as Python callables
  2. source and sink extensions are authored as Python modules
  3. extension loading is based on direct runtime import, not a compiled plugin ABI
  4. the deployment target remains low-friction and weak-hardware-friendly

Why

This decision is not primarily about raw implementation speed. It is about preserving the product and extension model.

Python gives the current system several properties that directly matter:

  • runtime import of .py modules with minimal ceremony
  • functions as first-class values for register_kernel(...)
  • no user-side compile step for extension authors
  • low barrier for agents and humans to author extensions
  • broad support across ARM/x86 local devices
  • a credible low-dependency path for embedded local use

These properties align with runex's architecture more closely than a compiled-plugin-first host would.

Alternatives Considered

1. Rust as the host runtime

Rejected for the current architecture target.

Reason:

  • it improves some performance characteristics, but changes the extension model significantly
  • a direct "drop in a .py file and load it" workflow disappears unless Python is embedded again
  • plugin systems would likely move toward:
    • compiled dynamic libraries
    • WASM modules
    • embedded CPython
  • each option increases user and deployment complexity relative to the current target

2. Go as the host runtime

Rejected for the current architecture target.

Reason:

  • Go offers a strong single-binary deployment story, but does not naturally preserve the current extension model
  • dynamic plugin loading is more constrained and operationally fragile across platforms than Python module loading
  • extension authors would face a meaningfully higher friction path than writing a Python file

3. Python only as a helper layer around a Rust/Go core

Rejected as the default architecture.

Reason:

  • it reintroduces a split-brain host model
  • the system would need to define which layer is truly authoritative for extensions
  • much of the current simplicity comes from host runtime and extension interface being the same language

Consequences

Positive

  • preserves the low-friction extension model
  • supports weak-hardware and local-first deployment goals
  • keeps the path open for agent-authored extensions without a compiled toolchain
  • aligns with SQLite and the project's low-ops runtime character

Negative / Tradeoffs

  • raw throughput and memory profile are less optimal than a carefully tuned Rust implementation
  • some critics will see Python as less serious for runtime systems on principle
  • the project must continue to exercise discipline around dependency minimization and runtime footprint

We accept these tradeoffs because the architecture optimizes for extension friction, deployment simplicity, and runtime malleability over maximum throughput.

Implications

  • new runtime features should preserve the "drop in a Python extension" workflow where possible
  • dependency choices should be evaluated partly against weak-hardware goals, not only laptop ergonomics
  • proposals to rewrite the host in Rust/Go should be evaluated as architecture changes, not mere implementation swaps