Detailed plan for migrating recurse from pure Go to rlm-core CGO bindings
Project: recurse (Go TUI for RLM) Target: Replace Go RLM implementation with rlm-core CGO bindings Scope: ~520 Go files, ~80,000+ lines of code Strategy: Layered migration preserving Go TUI, replacing core RLM logic with Rust
Migration status note (2026-02-20):
- This spec is historical planning context.
- Authoritative live outcome is closed task
loop-p95(migration complete). - Phase checklist lines marked
[historical target]are archival and not the live backlog. - Live execution authority is
bd statusplus:docs/execution-plan/STATUS.mddocs/execution-plan/TASK-REGISTRY.mddocs/execution-plan/WORKBOARD.md
┌─────────────────────────────────────────────────────────────────┐
│ Go Application │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ TUI Layer (Bubble Tea) │ │
│ │ Chat, Budget Panel, Memory Dialog, Trace Viewer, etc. │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Application Layer │ │
│ │ App, RLMService, REPLManager, MemoryProvider │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ RLM Core Layer │ │
│ │ Orchestrator, Meta, Routing, Classifier, Compress │ │
│ │ ToT, LATS, Learning, Hallucination, Verify, REPL │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Data Layer │ │
│ │ Memory (Hypergraph), Budget, Session, Message │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Integration Layer │ │
│ │ Agent, LLM Providers, OAuth, LSP, Shell │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Go Application │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ TUI Layer (Bubble Tea) │ │
│ │ Chat, Budget Panel, Memory Dialog, Trace Viewer, etc. │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Application Layer │ │
│ │ App, RLMBridge, Adapters, Event Handlers │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ CGO FFI │
│ ════════════════════════════╪══════════════════════════════ │
│ │ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ rlm-core (Rust) │ │
│ │ Orchestrator, Memory, Routing, Epistemic, Trajectory │ │
│ │ REPL, Reasoning, Complexity, LLM Client │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Integration Layer (Go) │ │
│ │ Agent, LLM Providers, OAuth, LSP, Shell │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
These Go packages map directly to rlm-core equivalents:
| recurse Package | rlm-core Replacement | Notes |
|---|---|---|
rlm/orchestrator/ |
rlm_core::Orchestrator |
Core orchestration loop |
rlm/meta/ |
rlm_core::Orchestrator |
Meta-controller merged |
rlm/classifier.go |
rlm_core::PatternClassifier |
Task classification |
rlm/routing/ |
rlm_core::SmartRouter |
Model selection |
rlm/repl/ |
rlm_core::ReplPool, ReplHandle |
Python REPL |
memory/hypergraph/ |
rlm_core::SqliteMemoryStore |
Hypergraph memory |
memory/embeddings/ |
rlm_core::SqliteMemoryStore |
Integrated embeddings |
memory/tiers/ |
rlm_core::Tier enum |
Memory tiers |
memory/reasoning/ |
rlm_core::ReasoningTraceStore |
Trace storage |
rlm/tot/ |
rlm_core::reasoning module |
Tree of Thoughts |
rlm/lats/ |
rlm_core::reasoning module |
LATS integration |
rlm/compress/ |
rlm_core::context module |
Context compression |
rlm/hallucination/ |
rlm_core::epistemic module |
Claim verification |
rlm/verify/ |
rlm_core::epistemic::EpistemicVerifier |
Verification |
rlm/learning/ |
rlm_core::SqliteMemoryStore |
Memory evolution |
budget/ |
rlm_core::CostTracker |
Token tracking |
rlm/observability/ |
rlm_core::TrajectoryEvent |
Event streaming |
New Go code to bridge rlm-core:
| Go Bridge | Purpose |
|---|---|
rlmcore/context.go |
Session context FFI wrapper |
rlmcore/memory.go |
Memory store FFI wrapper |
rlmcore/orchestrator.go |
Orchestrator FFI wrapper |
rlmcore/trajectory.go |
Trajectory event FFI wrapper |
rlmcore/types.go |
Type conversions |
rlmcore/error.go |
Error handling |
These packages integrate with rlm-core but retain Go logic:
| Package | rlm-core Integration | Retained Logic |
|---|---|---|
app/rlm.go |
rlmcore.Orchestrator |
Service lifecycle |
app/memory_provider.go |
rlmcore.MemoryStore |
TUI adapter |
app/repl_provider.go |
rlmcore.ReplPool |
TUI adapter |
session/ |
rlmcore.SessionContext |
Go session management |
message/ |
rlmcore.TrajectoryEvent |
Message persistence |
These packages become obsolete:
| Package | Reason |
|---|---|
rlm/orchestrator/ |
Replaced by rlm-core orchestrator |
rlm/meta/ |
Merged into rlm-core orchestrator |
rlm/wrapper.go |
Handled by rlm-core |
rlm/service.go |
Replaced by bridge layer |
rlm/classifier.go |
Replaced by PatternClassifier |
rlm/routing/ |
Replaced by SmartRouter |
rlm/compute.go |
Integrated into rlm-core |
rlm/proactive.go |
Handled by rlm-core |
rlm/guarantees.go |
Handled by rlm-core |
rlm/progress.go |
Handled by trajectory events |
rlm/tot/ |
Replaced by rlm-core reasoning |
rlm/lats/ |
Replaced by rlm-core reasoning |
rlm/compress/ |
Replaced by rlm-core context |
rlm/cache/ |
Integrated into rlm-core LLM |
rlm/async/ |
Handled by rlm-core |
rlm/learning/ |
Replaced by memory evolution |
rlm/hallucination/ |
Replaced by rlm-core epistemic |
rlm/verify/ |
Replaced by rlm-core epistemic |
rlm/synthesize/ |
Handled by rlm-core |
rlm/decompose/ |
Handled by rlm-core |
rlm/checkpoint/ |
Handled by rlm-core |
memory/hypergraph/ |
Replaced by SqliteMemoryStore |
memory/embeddings/ |
Integrated into memory store |
memory/tiers/ |
Handled by rlm-core Tier |
memory/reasoning/ |
Replaced by ReasoningTraceStore |
budget/ (core logic) |
Replaced by CostTracker |
These packages remain in Go:
| Package | Reason |
|---|---|
cmd/recurse/ |
CLI entry point |
internal/cmd/ |
Command handlers |
internal/tui/ |
Bubble Tea UI (100+ files) |
internal/app/ |
Application wiring (adapted) |
internal/agent/ |
Agent coordination |
internal/config/ |
Go configuration |
internal/db/ |
Go database layer |
internal/oauth/ |
OAuth flows |
internal/lsp/ |
LSP client |
internal/shell/ |
Shell execution |
internal/env/ |
Environment utilities |
internal/home/ |
Home directory utilities |
internal/projects/ |
Project management |
internal/history/ |
File history |
// Context management
typedef struct RlmContext RlmContext;
RlmContext* rlm_context_new(const char* config_json);
void rlm_context_free(RlmContext* ctx);
int rlm_context_add_message(RlmContext* ctx, const char* role, const char* content);
char* rlm_context_get_messages_json(RlmContext* ctx);
// Memory store
typedef struct RlmMemoryStore RlmMemoryStore;
RlmMemoryStore* rlm_memory_store_new(const char* db_path);
void rlm_memory_store_free(RlmMemoryStore* store);
char* rlm_memory_store_query(RlmMemoryStore* store, const char* query_json);
int rlm_memory_store_upsert(RlmMemoryStore* store, const char* node_json);
// Orchestrator
typedef struct RlmOrchestrator RlmOrchestrator;
RlmOrchestrator* rlm_orchestrator_new(const char* config_json);
void rlm_orchestrator_free(RlmOrchestrator* orch);
char* rlm_orchestrator_execute(RlmOrchestrator* orch, const char* request_json);
// Trajectory events (callback-based)
typedef void (*RlmTrajectoryCallback)(const char* event_json, void* user_data);
void rlm_set_trajectory_callback(RlmOrchestrator* orch, RlmTrajectoryCallback cb, void* user_data);
// Error handling
char* rlm_get_last_error(void);
void rlm_free_string(char* s);// internal/rlmcore/orchestrator.go
package rlmcore
/*
#cgo LDFLAGS: -lrlm_core
#include "rlm_core.h"
*/
import "C"
import (
"encoding/json"
"unsafe"
)
type Orchestrator struct {
ptr *C.RlmOrchestrator
}
func NewOrchestrator(config Config) (*Orchestrator, error) {
configJSON, _ := json.Marshal(config)
cConfig := C.CString(string(configJSON))
defer C.free(unsafe.Pointer(cConfig))
ptr := C.rlm_orchestrator_new(cConfig)
if ptr == nil {
return nil, getLastError()
}
return &Orchestrator{ptr: ptr}, nil
}
func (o *Orchestrator) Execute(req Request) (*Response, error) {
reqJSON, _ := json.Marshal(req)
cReq := C.CString(string(reqJSON))
defer C.free(unsafe.Pointer(cReq))
cResp := C.rlm_orchestrator_execute(o.ptr, cReq)
if cResp == nil {
return nil, getLastError()
}
defer C.rlm_free_string(cResp)
var resp Response
json.Unmarshal([]byte(C.GoString(cResp)), &resp)
return &resp, nil
}
func (o *Orchestrator) Close() {
if o.ptr != nil {
C.rlm_orchestrator_free(o.ptr)
o.ptr = nil
}
}// internal/rlmcore/trajectory.go
package rlmcore
/*
#include "rlm_core.h"
extern void goTrajectoryCallback(char* event_json, void* user_data);
*/
import "C"
import (
"encoding/json"
"sync"
)
var (
callbackMu sync.RWMutex
callbacks = make(map[uintptr]func(TrajectoryEvent))
nextID uintptr
)
//export goTrajectoryCallback
func goTrajectoryCallback(eventJSON *C.char, userData unsafe.Pointer) {
id := uintptr(userData)
callbackMu.RLock()
cb, ok := callbacks[id]
callbackMu.RUnlock()
if ok {
var event TrajectoryEvent
json.Unmarshal([]byte(C.GoString(eventJSON)), &event)
cb(event)
}
}
func (o *Orchestrator) SetTrajectoryCallback(cb func(TrajectoryEvent)) {
callbackMu.Lock()
id := nextID
nextID++
callbacks[id] = cb
callbackMu.Unlock()
C.rlm_set_trajectory_callback(
o.ptr,
C.RlmTrajectoryCallback(C.goTrajectoryCallback),
unsafe.Pointer(id),
)
}Duration: 2-3 days Risk: Low
-
Build rlm-core as shared library:
cd /path/to/rlm-core cargo build --release --features ffi -
Add CGO configuration to recurse:
// internal/rlmcore/cgo.go package rlmcore /* #cgo CFLAGS: -I${SRCDIR}/../../rlm-core/ffi/include #cgo LDFLAGS: -L${SRCDIR}/../../rlm-core/target/release -lrlm_core */ import "C"
-
Create feature flag:
// internal/config/features.go var UseRlmCore = os.Getenv("RLM_USE_CORE") == "true"
-
Create minimal bridge layer with type definitions
Exit Criteria:
- [historical target] rlm-core library links successfully
- [historical target] Basic FFI calls work (create/destroy context)
- [historical target] Feature flag toggles implementations
- [historical target] Existing tests pass with flag off
Duration: 1 week Risk: Medium (data migration)
-
Replace
memory/hypergraph/with rlm-core bridge:// Before store := hypergraph.NewStore(dbPath) results := store.Query(query) // After store := rlmcore.NewMemoryStore(dbPath) results := store.Query(query)
-
Migrate data schema:
- Create migration script for existing SQLite databases
- Map Go node types to rlm-core
NodeTypeenum - Map Go tiers to rlm-core
Tierenum - Preserve embeddings during migration
-
Update memory providers:
app/memory_provider.go→ Use rlmcore.MemoryStore- TUI memory dialog → Consume rlm-core types
-
Update tests:
memory/hypergraph/*_test.go- Integration tests for memory operations
Migration Script:
// cmd/migrate-memory/main.go
func migrateDatabase(oldPath, newPath string) error {
// 1. Open old Go SQLite database
// 2. Read all nodes and edges
// 3. Transform to rlm-core types
// 4. Write to new schema via FFI
// 5. Verify data integrity
}Exit Criteria:
- [historical target] Existing memories migrate without data loss
- [historical target] Semantic search produces equivalent results
- [historical target] Tier operations work correctly
- [historical target] Memory tests pass
- [historical target] TUI memory dialog renders correctly
Duration: 3-4 days Risk: Low
-
Replace
rlm/classifier.go:// Before classifier := rlm.NewClassifier() classification := classifier.Classify(query, context) // After classifier := rlmcore.NewPatternClassifier() decision := classifier.ShouldActivate(query, context)
-
Replace
rlm/routing/:// Before router := routing.NewRouter(profiles) model := router.SelectModel(query, constraints) // After router := rlmcore.NewSmartRouter(config) model := router.Route(query, context)
-
Update callers in orchestration layer
Exit Criteria:
- [historical target] Classification produces equivalent results
- [historical target] Model routing works correctly
- [historical target] Performance within 10% of original
Duration: 4-5 days Risk: Medium (subprocess management)
-
Replace
rlm/repl/:// Before manager := repl.NewManager(config) result := manager.Execute(code) // After pool := rlmcore.NewReplPool(config) handle := pool.GetHandle() result := handle.Execute(code)
-
Bridge callbacks:
- LLM callback → Bridge to Go LLM providers
- Memory callback → Bridge to rlm-core memory
-
Handle resource management:
- Subprocess lifecycle
- Timeout enforcement
- Resource limits
Exit Criteria:
- [historical target] Code execution produces same results
- [historical target] Callbacks work correctly
- [historical target] Timeouts enforced
- [historical target] Resource cleanup on exit
Duration: 2-3 days Risk: Low
-
Replace
rlm/observability/with rlm-core events:// Before emitter := observability.NewEmitter() emitter.Emit(EventRLMStart, data) // After (callback-based) orchestrator.SetTrajectoryCallback(func(event TrajectoryEvent) { // Handle event })
-
Update TUI trace viewer to consume rlm-core events
-
Update budget panel to use cost tracking events
Exit Criteria:
- [historical target] All event types map correctly
- [historical target] TUI trace viewer renders events
- [historical target] Budget tracking accurate
Duration: 3-4 days Risk: Low
-
Replace
rlm/hallucination/:// Before detector := hallucination.NewDetector() result := detector.Check(claim, evidence) // After verifier := rlmcore.NewEpistemicVerifier(config) result := verifier.VerifyClaim(claim, evidence)
-
Replace
rlm/verify/:- Proof checking → rlm-core verifier
- Output gate → rlm-core memory gate
Exit Criteria:
- [historical target] Hallucination detection rate maintained
- [historical target] Memory gate rejects ungrounded facts
- [historical target] Verification tests pass
Duration: 4-5 days Risk: Medium (complex logic)
-
Replace
rlm/tot/(Tree of Thoughts):// Before tot := tot.NewExplorer(config) result := tot.Explore(query, context) // After orchestrator := rlmcore.NewOrchestrator(config) result := orchestrator.ExecuteWithReasoning(query, context, ReasoningToT)
-
Replace
rlm/lats/(Language Agent Tree Search):- Similar pattern to ToT
-
Replace
rlm/compress/:- Hierarchical compression → rlm-core context module
- Incremental compression → rlm-core context module
Exit Criteria:
- [historical target] ToT produces equivalent exploration
- [historical target] LATS search works correctly
- [historical target] Compression maintains quality
- [historical target] Reasoning tests pass
Duration: 1-2 weeks Risk: High (core functionality)
-
Replace
rlm/orchestrator/andrlm/service.go:// Before service := rlm.NewService(config) result := service.Execute(request) // After orchestrator := rlmcore.NewOrchestrator(config) result := orchestrator.Execute(request)
-
Replace
rlm/wrapper.go:- Prompt preparation → rlm-core
- Response processing → rlm-core
-
Wire up application layer:
app/rlm.go→ Use rlmcore.Orchestrator- Event dispatch to TUI
-
Handle async execution:
- Parallel operations
- Budget-aware execution
Exit Criteria:
- [historical target] End-to-end orchestration works
- [historical target] Recursive calls function correctly
- [historical target] Meta-control decisions correct
- [historical target] All orchestration tests pass
Duration: 3-4 days Risk: Low
-
Replace
learning/:- Continuous learning → rlm-core memory evolution
- Corrections → rlm-core memory metadata
-
Replace
budget/:// Before manager := budget.NewManager(limits) manager.Track(tokens) // After (via trajectory events) // Cost tracking integrated into orchestrator orchestrator.SetTrajectoryCallback(func(e TrajectoryEvent) { if e.Type == EventCostUpdate { updateBudgetUI(e.Cost) } })
Exit Criteria:
- [historical target] Learning state migrated
- [historical target] Budget tracking accurate
- [historical target] Budget UI updates correctly
Duration: 3-4 days Risk: Low
- Remove legacy packages (see Section 2.4)
- Remove feature flags
- Update go.mod dependencies
- Update documentation
- Update build scripts
- Tag release
Exit Criteria:
- [historical target] No legacy RLM code remains
- [historical target] All tests pass
- [historical target] Build clean without warnings
- [historical target] Documentation updated
| Category | Approach |
|---|---|
| Unit tests | Run with both implementations during migration |
| Integration tests | Test FFI boundary thoroughly |
| Regression tests | Compare outputs between old and new |
| Performance tests | Benchmark critical paths |
| E2E tests | Full TUI interaction tests |
func TestFFIMemoryRoundtrip(t *testing.T) {
store := rlmcore.NewMemoryStore(":memory:")
defer store.Close()
// Store node
node := Node{ID: "test-1", Content: "test content"}
err := store.Upsert(node)
require.NoError(t, err)
// Query back
results, err := store.Query(Query{Content: "test"})
require.NoError(t, err)
require.Len(t, results, 1)
assert.Equal(t, node.Content, results[0].Content)
}
func TestFFITrajectoryCallback(t *testing.T) {
orchestrator := rlmcore.NewOrchestrator(config)
defer orchestrator.Close()
var events []TrajectoryEvent
orchestrator.SetTrajectoryCallback(func(e TrajectoryEvent) {
events = append(events, e)
})
_, err := orchestrator.Execute(request)
require.NoError(t, err)
assert.NotEmpty(t, events)
assert.Equal(t, EventRlmStart, events[0].Type)
}func TestRegressionOrchestration(t *testing.T) {
// Run same query through both implementations
oldResult := oldOrchestrator.Execute(query, context)
newResult := newOrchestrator.Execute(query, context)
// Compare outputs (allow for non-determinism)
assertEquivalentResults(t, oldResult, newResult)
}| Metric | Target |
|---|---|
| FFI call overhead | < 1ms per call |
| Memory query | < 200ms (semantic search) |
| Orchestration latency | < 50ms added overhead |
| Memory usage | < 10% increase |
Each phase includes rollback capability:
- Feature flag: Set
RLM_USE_CORE=falseto revert - Version pinning: Keep old code until phase complete
- Database backup: Backup memory before migration
- Git tags: Tag before each phase for easy revert
- Dual binary: Can build with or without rlm-core
| Risk | Impact | Probability | Mitigation |
|---|---|---|---|
| FFI memory leaks | High | Medium | Careful resource management, leak detection |
| CGO build complexity | Medium | Medium | CI/CD pipeline testing |
| Memory data loss | High | Low | Backup + migration script + verification |
| Performance regression | Medium | Medium | Benchmarks per phase |
| Callback deadlocks | High | Low | Careful lock management |
| TUI integration issues | Medium | Medium | Incremental integration |
| Cross-platform builds | Medium | High | Test on Linux, macOS, Windows |
# rlm-core/Cargo.toml
[features]
ffi = ["cbindgen"]
[lib]
crate-type = ["cdylib", "staticlib", "rlib"]// build flags for different platforms
// +build cgo
/*
#cgo linux LDFLAGS: -L${SRCDIR}/lib -lrlm_core -ldl -lm -lpthread
#cgo darwin LDFLAGS: -L${SRCDIR}/lib -lrlm_core -ldl -lm -lpthread
#cgo windows LDFLAGS: -L${SRCDIR}/lib -lrlm_core -lws2_32 -luserenv
*/
import "C"# .github/workflows/build.yml
jobs:
build-rlm-core:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- run: cargo build --release --features ffi
- uses: actions/upload-artifact@v4
with:
name: rlm-core-${{ matrix.os }}
path: target/release/librlm_core.*
build-recurse:
needs: build-rlm-core
runs-on: ${{ matrix.os }}
steps:
- uses: actions/download-artifact@v4
- run: go build ./cmd/recurse| Phase | Duration | Cumulative |
|---|---|---|
| Phase 1: Add dependency | 2-3 days | 2-3 days |
| Phase 2: Memory | 5-7 days | 7-10 days |
| Phase 3: Classification/Routing | 3-4 days | 10-14 days |
| Phase 4: REPL | 4-5 days | 14-19 days |
| Phase 5: Trajectory | 2-3 days | 16-22 days |
| Phase 6: Epistemic | 3-4 days | 19-26 days |
| Phase 7: Reasoning | 4-5 days | 23-31 days |
| Phase 8: Orchestrator | 7-10 days | 30-41 days |
| Phase 9: Learning/Budget | 3-4 days | 33-45 days |
| Phase 10: Cleanup | 3-4 days | 36-49 days |
Total: ~5-7 weeks
# Build rlm-core shared library
cd /path/to/rlm-core
cargo build --release --features ffi
# Copy library to recurse
cp target/release/librlm_core.* /path/to/recurse/lib/
# Run with rlm-core enabled
RLM_USE_CORE=true go run ./cmd/recurse
# Run tests with both implementations
go test ./... -tags=rlmcore
go test ./... -tags=legacy
# Run memory migration
go run ./cmd/migrate-memory --old-db ~/.recurse/memory.db --new-db ~/.recurse/memory_v2.db
# Benchmark FFI overhead
go test ./internal/rlmcore/... -bench=. -benchmem
# Check for memory leaks
go test ./internal/rlmcore/... -race -count=100Migration is complete when:
- [historical target] All recurse tests pass
- [historical target] No regression in functionality
- [historical target] Performance within 10% of original
- [historical target] Memory migration works without data loss
- [historical target] TUI renders correctly with rlm-core backend
- [historical target] Cross-platform builds work (Linux, macOS, Windows)
- [historical target] Feature flag removed
- [historical target] Legacy RLM code deleted
- [historical target] Documentation updated
- [historical target] Release tagged
internal/rlm/
├── orchestrator/ # → rlm-core orchestrator
│ ├── orchestrator.go
│ ├── core.go
│ ├── intelligent.go
│ ├── steering.go
│ └── checkpoint.go
├── meta/ # → rlm-core orchestrator
├── routing/ # → rlm-core SmartRouter
├── repl/ # → rlm-core ReplPool
├── tot/ # → rlm-core reasoning
├── lats/ # → rlm-core reasoning
├── compress/ # → rlm-core context
├── cache/ # → rlm-core LLM
├── async/ # → rlm-core
├── learning/ # → rlm-core memory
├── hallucination/ # → rlm-core epistemic
├── verify/ # → rlm-core epistemic
├── synthesize/ # → rlm-core
├── decompose/ # → rlm-core
├── checkpoint/ # → rlm-core
├── observability/ # → rlm-core trajectory
├── service.go # → rlmcore bridge
├── wrapper.go # → rlm-core
├── classifier.go # → rlm-core PatternClassifier
├── compute.go # → rlm-core
├── proactive.go # → rlm-core
├── guarantees.go # → rlm-core
└── progress.go # → rlm-core trajectory
internal/memory/
├── hypergraph/ # → rlm-core SqliteMemoryStore
├── embeddings/ # → rlm-core memory
├── tiers/ # → rlm-core Tier
└── reasoning/ # → rlm-core ReasoningTraceStore
internal/budget/ # → rlm-core CostTracker (core logic only)
internal/
├── rlmcore/ # NEW: FFI bridge (~10 files)
├── tui/ # KEEP: 100+ files
├── app/ # KEEP: ~10 files (adapted)
├── agent/ # KEEP: ~15 files
├── cmd/ # KEEP: ~10 files
├── config/ # KEEP: ~5 files
├── db/ # KEEP: ~10 files
├── oauth/ # KEEP: ~5 files
├── lsp/ # KEEP: ~5 files
├── shell/ # KEEP: ~3 files
├── session/ # KEEP: ~5 files (adapted)
├── message/ # KEEP: ~5 files (adapted)
└── [utilities] # KEEP: ~20 files
Estimated reduction: ~200+ Go files removed, ~180 files remaining