Date: 2026-02-20
Audience: Maintainers and integration owners (rlm-claude-code, loop-agent, io-rflx)
Can we get the full value of loop and rlm-core in downstream projects without doing a full Python-side orchestrator swap?
Short answer: you can get most of the practical value now, but not the full architectural unification value.
The core tension is simple:
- We already have strong shared primitives and adapter/runtime behavior in
rlm-core. - Python consumers still orchestrate some flows locally because binding surfaces are intentionally limited today.
This means we can move quickly now, but we still carry some long term drift risk.
Python currently exposes component-level surfaces such as context, memory, router, classifier, trajectory, and epistemic primitives.
It does not expose:
OrchestratorClaudeCodeAdapterReplHandleandReplPool
This is documented and currently accepted as scope policy.
rlm-core already has:
- A real
ClaudeCodeAdapterruntime - OODA-oriented end-to-end tests
- Orchestrator traits and fallback/runtime primitives
- REPL handle/pool implementations
So the gap is primarily at cross-language exposure and runtime boundary semantics, not at core capability existence.
You can get substantial value now via component delegation:
- Shared classifier behavior
- Shared memory semantics
- Shared routing and cost primitives
- Shared trajectory and epistemic primitives
What you do not get yet:
- One canonical orchestrator runtime path across Rust and Python
- Fully unified lifecycle semantics around orchestration and REPL control
- Single-place orchestration policy changes
Current integration is seam-oriented and optional by contract, so a Python orchestrator swap is not required to get most near-term value.
The current value path is deterministic optional adapters with strict fallback behavior.
Current integration is schema-first and contract-driven. It does not require a Python orchestrator swap to deliver value.
The primary leverage is stable trajectory/provenance/verification envelopes and versioned mapping policy.
A full Python-side orchestrator swap means Python consumers invoke Rust orchestration runtime surfaces directly for the full OODA loop, not just delegated components.
In practice, this includes:
- Exposing adapter and/or orchestrator runtime APIs in Python bindings
- Defining cross-runtime async semantics (timeouts, cancellation, backpressure)
- Defining stream/event lifecycle behavior at Python call sites
- Preserving compatibility contracts and migration windows for active consumers
- Less behavioral drift between Python and Rust orchestration paths
- Lower long-term maintenance in downstream Python orchestration code
- Cleaner policy enforcement and observability from one runtime core
- Simpler future feature rollout once boundaries are stable
- Async boundary complexity (
asyncioand Rust runtime interactions) - Cancellation and timeout semantics can diverge if not specified tightly
- REPL lifecycle edge cases can become harder to debug during migration
- Packaging and CI parity work increases (binary distribution and runtime matrix)
No one gets bonus points for two event loops that disagree about who timed out first.
This is the main impact area:
- Migration shims and flags are needed during rollout
- Existing invariants and tests must hold during dual-path windows
- Release timing must respect tuple-based compatibility policy
Indirect impact:
- Optional seam contracts should remain stable
- Deterministic fallback and sensitivity guardrails must not regress
Mostly contract impact:
- Keep schema versioning and migration notes strict
- Preserve deterministic confidence mapping behavior
Use this as a practical go/no-go filter:
- Do we have measurable drift or maintenance cost from split orchestration paths?
- Can we specify async/cancellation semantics as a testable contract before implementation?
- Can we run shadow mode and compare old vs new paths on representative scenarios?
- Do compatibility gates cover all impacted consumer tuples?
If the answer is "no" on any of these, defer the full swap and keep harvesting value via component delegation.
- Keep component delegation as default for active delivery work.
- Do adapter-first binding expansion before generic orchestrator trait exposure.
- Run shadow mode in
rlm-claude-codefor behavior and metadata diffing. - Promote only after compatibility gates are green for affected tuples.
- Keep a kill switch until stability is demonstrated over a sustained window.
The goal is less glue code, not more glue code with a nicer README.
You can move rlm-claude-code, loop-agent, and io-rflx forward now and get high practical value from loop and rlm-core without a full Python orchestrator swap.
A full swap is a strategic unification move, not a prerequisite for current product progress.
docs/migration-spec-rlm-claude-code.mddocs/execution-plan/DECISIONS.mddocs/execution-plan/contracts/CONSUMER-INTEGRATION.mddocs/execution-plan/contracts/LOOP-AGENT-RUNTIME-SEAM.mddocs/execution-plan/contracts/IO-RFLX-INTEROP-CONTRACT.mdrlm-core/src/pybind/mod.rsrlm-core/src/adapters/claude_code/adapter.rsrlm-core/src/orchestrator.rs