Skip to content

Commit ea5ce7b

Browse files
randclaude
andauthored
feat: bundle rlm-core as required dependency (#10)
* feat: bundle rlm-core as required dependency via git submodule - Vendor rlm-core at vendor/loop as git submodule (replaces optional pip install) - Add `id` and `last_accessed` params to rlm_core.Node PyO3 bindings - Add `update_fields()` with access_count support to rlm_core.MemoryStore - Fix memory_store.py to use correct rlm_core APIs (add_node, update_fields, etc.) - Fix WAL corruption: use persistent Python connection, create all schemas before rlm_core.open(), move decisions table to _init_database - Fix edge/node deletion cascade (manual cleanup with FKs disabled) - Fix complexity classifier tests for rlm_core's PatternClassifier scoring - Remove USE_RLM_CORE/use_rlm_core references from README and config - Remove setup-rlm-core.sh (replaced by maturin build from submodule) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore: bump version to 0.7.0, apply ruff formatting Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent f94e4ed commit ea5ce7b

150 files changed

Lines changed: 1918 additions & 2413 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/release.yml

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
name: Build and Release Wheels
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
build:
13+
strategy:
14+
matrix:
15+
include:
16+
- os: macos-latest
17+
target: aarch64-apple-darwin
18+
- os: macos-13
19+
target: x86_64-apple-darwin
20+
- os: ubuntu-latest
21+
target: x86_64-unknown-linux-gnu
22+
- os: ubuntu-latest
23+
target: aarch64-unknown-linux-gnu
24+
runs-on: ${{ matrix.os }}
25+
steps:
26+
- uses: actions/checkout@v4
27+
with:
28+
submodules: recursive
29+
30+
- uses: actions/setup-python@v5
31+
with:
32+
python-version: '3.12'
33+
34+
- name: Install Rust toolchain
35+
uses: dtolnay/rust-toolchain@stable
36+
with:
37+
targets: ${{ matrix.target }}
38+
39+
- name: Build wheel
40+
uses: PyO3/maturin-action@v1
41+
with:
42+
target: ${{ matrix.target }}
43+
args: --release --out dist
44+
manylinux: auto
45+
46+
- name: Upload wheel artifact
47+
uses: actions/upload-artifact@v4
48+
with:
49+
name: wheel-${{ matrix.target }}
50+
path: dist/*.whl
51+
52+
release:
53+
needs: build
54+
runs-on: ubuntu-latest
55+
steps:
56+
- name: Download all wheel artifacts
57+
uses: actions/download-artifact@v4
58+
with:
59+
path: dist
60+
merge-multiple: true
61+
62+
- name: Create GitHub Release
63+
uses: softprops/action-gh-release@v2
64+
with:
65+
files: dist/*.whl
66+
generate_release_notes: true

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "vendor/loop"]
2+
path = vendor/loop
3+
url = https://github.com/rand/loop

CHANGELOG.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
11
# Changelog
22

3+
## [0.7.0] - 2026-02-02
4+
5+
### Changed
6+
- **rlm-core is now a required bundled dependency** — no more optional/fallback mode
7+
- `USE_RLM_CORE` / `RLM_USE_CORE` environment variable removed (always enabled)
8+
- `use_rlm_core` config option removed from `rlm-config.json`
9+
- Memory store delegates node CRUD to rlm_core's Rust SQLite backend
10+
- Build system uses maturin for rlm-core PyO3 bindings
11+
- rlm-core vendored as git submodule at `vendor/loop`
12+
13+
### Added
14+
- `id` parameter on `rlm_core.Node()` constructor for creating nodes with pre-existing UUIDs
15+
- `update_fields()` method on `rlm_core.MemoryStore` for field-level updates without Node immutability issues
16+
17+
### Fixed
18+
- Node immutability crash (`updated.id = node_id`) by using `update_fields()` convenience method
19+
- Foreign key constraint failures when Python SQLite and rlm_core share the same database file
20+
- In-memory store connection lifecycle (persistent connection for `:memory:` mode)
21+
- Evolution log schema compatibility with rlm_core's `node_id`/`reason` column names
22+
- Provenance round-trip fidelity via metadata storage
23+
324
## [0.6.1] - 2026-02-02
425

526
### Fixed
@@ -27,7 +48,7 @@
2748
- Unit tests for hookio, events, and config packages
2849

2950
### Changed
30-
- **rlm-core enabled by default** (`USE_RLM_CORE=true`) — set `RLM_USE_CORE=false` to disable
51+
- **rlm-core enabled by default** — now a required dependency as of v0.7.0
3152
- rlm-core PyO3 bindings now support metadata, provenance, and embedding parameters
3253
- rlm-core uses separate `-core.db` file to avoid schema conflicts with Python SQLite
3354
- hooks.json now uses Go binaries + prompt-based hooks

README.md

Lines changed: 38 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Transform Claude Code into a Recursive Language Model (RLM) agent with intelligent orchestration, unbounded context handling, persistent memory, and REPL-based decomposition.
44

5-
**rlm-core integration**: This project uses [rlm-core](https://github.com/rand/loop) by default as the unified RLM orchestration library, providing shared implementations with [recurse](https://github.com/rand/recurse). rlm-core provides Rust-based pattern classification (10-50x faster) via PyO3 bindings. Falls back to Python automatically when rlm-core is not installed.
5+
**rlm-core integration**: This project bundles [rlm-core](https://github.com/rand/loop) as a required dependency, providing shared Rust-based implementations with [recurse](https://github.com/rand/recurse). rlm-core provides 10-50x faster pattern classification via PyO3 bindings. Pre-built wheels are available for common platforms.
66

77
## What is RLM?
88

@@ -24,61 +24,34 @@ This results in better accuracy on complex tasks while optimizing cost through i
2424

2525
- **Python 3.12+**: `brew install python@3.12` or [python.org](https://python.org)
2626
- **uv** (Python package manager): `curl -LsSf https://astral.sh/uv/install.sh | sh`
27-
- **Rust 1.75+** (optional): `rustup update stable` (only if building rlm-core)
27+
- **Rust 1.75+** (for dev builds): `rustup update stable` — not needed if installing from pre-built wheels
2828

29-
### Installation
29+
### Installation (from pre-built wheel)
3030

31-
```bash
32-
# Clone the repository
33-
git clone https://github.com/rand/rlm-claude-code.git
34-
cd rlm-claude-code
35-
36-
# Install dependencies
37-
uv sync --all-extras
38-
39-
# Run tests to verify setup
40-
uv run pytest tests/ -v
41-
```
42-
43-
### Building rlm-core (Enabled by Default)
44-
45-
rlm-core is enabled by default for 10-50x faster pattern classification. Build the [rlm-core](https://github.com/rand/loop) Rust library with Python bindings:
31+
Download the wheel for your platform from [GitHub Releases](https://github.com/rand/rlm-claude-code/releases), then:
4632

4733
```bash
48-
# Clone rlm-core (if not already present)
49-
git clone https://github.com/rand/loop.git ~/src/loop
50-
51-
# Install maturin (Rust-Python build tool)
52-
uv tool install maturin
53-
54-
# Build the Python bindings
55-
cd ~/src/loop/rlm-core
56-
PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1 uv run maturin develop --release
57-
58-
# Verify the build succeeded
59-
ls -la ~/src/loop/rlm-core/python/rlm_core*.so
34+
pip install rlm_claude_code-*.whl
6035
```
6136

62-
To use rlm-core with the standalone package (not plugin):
37+
### Installation (from source, requires Rust)
6338

6439
```bash
65-
cd /path/to/rlm-claude-code
40+
# Clone with submodules (rlm-core is bundled)
41+
git clone --recurse-submodules https://github.com/rand/rlm-claude-code.git
42+
cd rlm-claude-code
6643

67-
# Link rlm_core to your venv
68-
echo "$HOME/src/loop/rlm-core/python" > .venv/lib/python3.12/site-packages/rlm_core.pth
44+
# Build and install (compiles rlm-core Rust library)
45+
maturin develop --release
6946

70-
# Verify import works
71-
uv run python -c "import rlm_core; print('OK:', rlm_core.PatternClassifier)"
47+
# Install Python dependencies
48+
uv sync --all-extras
7249

73-
# Enable via config (persistent) or environment (temporary)
74-
# Config method - add to ~/.claude/rlm-config.json:
75-
# "use_rlm_core": true
76-
# Environment method:
77-
export RLM_USE_CORE=true
50+
# Verify
51+
python -c "import rlm_core; print(rlm_core.version())"
52+
uv run pytest tests/ -v
7853
```
7954

80-
**Without rlm-core**: All functionality works using Python fallback implementations. You'll see warnings but everything operates correctly.
81-
8255
### As a Claude Code Plugin
8356

8457
#### Step 1: Install the Plugin
@@ -93,50 +66,18 @@ claude plugin install rlm-claude-code@rlm-claude-code
9366

9467
#### Step 2: Set Up the Plugin Environment
9568

96-
The plugin requires a Python virtual environment with dependencies. After installation:
69+
The plugin includes rlm-core (bundled via maturin). After installation:
9770

9871
```bash
9972
# Navigate to the plugin directory (adjust version number as needed)
100-
cd ~/.claude/plugins/cache/rlm-claude-code/rlm-claude-code/$(ls ~/.claude/plugins/cache/rlm-claude-code/rlm-claude-code/ | sort -V | tail -1)
101-
102-
# Create venv and install dependencies
103-
uv venv && uv sync
104-
```
105-
106-
#### Step 3: Install rlm-core for Performance (Enabled by Default)
107-
108-
rlm-core is enabled by default. Install for 10-50x faster pattern classification:
109-
110-
```bash
111-
# First, build rlm-core if you haven't already (see "Building rlm-core" section above)
112-
113-
# Get the plugin version directory
11473
PLUGIN_DIR=~/.claude/plugins/cache/rlm-claude-code/rlm-claude-code/$(ls ~/.claude/plugins/cache/rlm-claude-code/rlm-claude-code/ | sort -V | tail -1)
74+
cd "$PLUGIN_DIR"
11575

116-
# Link rlm_core to the plugin's venv
117-
echo "$HOME/src/loop/rlm-core/python" > "$PLUGIN_DIR/.venv/lib/python3.12/site-packages/rlm_core.pth"
118-
119-
# Verify it works
120-
"$PLUGIN_DIR/.venv/bin/python" -c "import rlm_core; print('rlm_core OK:', rlm_core.PatternClassifier)"
76+
# Create venv and install (includes rlm-core)
77+
uv venv && uv sync
12178

122-
# Enable rlm-core by default (add to your config)
123-
cat > ~/.claude/rlm-config.json << 'EOF'
124-
{
125-
"use_rlm_core": true,
126-
"activation": {
127-
"mode": "complexity",
128-
"fallback_token_threshold": 80000
129-
},
130-
"depth": {
131-
"default": 2,
132-
"max": 3
133-
},
134-
"trajectory": {
135-
"verbosity": "normal",
136-
"streaming": true
137-
}
138-
}
139-
EOF
79+
# Verify rlm-core is available
80+
"$PLUGIN_DIR/.venv/bin/python" -c "import rlm_core; print('rlm_core OK:', rlm_core.version())"
14081
```
14182

14283
#### Step 4: Verify Installation
@@ -161,8 +102,7 @@ claude plugin update rlm-claude-code@rlm-claude-code
161102
PLUGIN_DIR=~/.claude/plugins/cache/rlm-claude-code/rlm-claude-code/$(ls ~/.claude/plugins/cache/rlm-claude-code/rlm-claude-code/ | sort -V | tail -1)
162103
cd "$PLUGIN_DIR" && uv venv && uv sync
163104

164-
# Re-link rlm_core if using it
165-
echo "$HOME/src/loop/rlm-core/python" > "$PLUGIN_DIR/.venv/lib/python3.12/site-packages/rlm_core.pth"
105+
# rlm-core is bundled — no extra linking needed
166106
```
167107

168108
---
@@ -241,45 +181,29 @@ Final Answer
241181

242182
---
243183

244-
## rlm-core Integration (Optional)
184+
## rlm-core Integration
245185

246-
RLM-Claude-Code optionally integrates with the [rlm-core](https://github.com/rand/loop) Rust library for improved performance.
186+
RLM-Claude-Code bundles [rlm-core](https://github.com/rand/loop), a Rust library providing high-performance pattern classification, memory storage, and trajectory tracking via PyO3 bindings.
247187

248-
### Enabling rlm-core
188+
rlm-core is a required dependency — there is no Python fallback mode.
249189

250-
There are two ways to enable rlm-core (in priority order):
251-
252-
**1. Environment variable** (highest priority, good for testing):
253-
```bash
254-
export RLM_USE_CORE=true
255-
```
256-
257-
**2. Config file** (persistent, recommended for regular use):
258-
259-
Add `"use_rlm_core": true` to `~/.claude/rlm-config.json`:
260-
```json
261-
{
262-
"use_rlm_core": true,
263-
"activation": { ... }
264-
}
265-
```
190+
### Configuration
266191

267192
| Setting | Behavior |
268193
|---------|----------|
269-
| `use_rlm_core: true` or unset | Use rlm-core Rust bindings (default, requires installation) |
270-
| `use_rlm_core: false` | Use Python fallback (always works) |
271-
272-
When rlm-core is enabled but not installed, a warning is logged and Python fallback is used automatically.
194+
| `activation.mode` | `"complexity"` (default), `"always"`, `"never"` |
195+
| `depth.default` | Default recursion depth (default: 2) |
196+
| `depth.max` | Maximum recursion depth (default: 3) |
273197

274-
### Performance Comparison
198+
### Performance
275199

276-
| Component | Python Fallback | With rlm-core |
277-
|-----------|-----------------|---------------|
278-
| Pattern Classifier | Python regex | Rust via PyO3 (10-50x faster) |
279-
| Trajectory Events | Python classes | Rust types via PyO3 |
280-
| Memory Store | Python + SQLite | Python + SQLite primary, rlm-core secondary (`-core.db`) |
200+
| Component | Implementation |
201+
|-----------|---------------|
202+
| Pattern Classifier | Rust via PyO3 |
203+
| Trajectory Events | Rust types via PyO3 |
204+
| Memory Store | rlm_core SQLite (nodes/edges) + Python SQLite (auxiliary tables) |
281205

282-
### Benefits of rlm-core
206+
### Benefits
283207

284208
- **Consistency**: Same classification logic as recurse TUI
285209
- **Performance**: Rust pattern matching is significantly faster
@@ -288,17 +212,13 @@ When rlm-core is enabled but not installed, a warning is logged and Python fallb
288212
### Python Bindings Usage
289213

290214
```python
291-
import os
292-
os.environ["RLM_USE_CORE"] = "true"
293-
294215
from src.complexity_classifier import should_activate_rlm, extract_complexity_signals
295216
from src.types import SessionContext, Message, MessageRole
296217

297-
# The bridge code auto-converts types and delegates to rlm_core when available
218+
# Delegates to rlm_core.PatternClassifier
298219
ctx = SessionContext(messages=[Message(role=MessageRole.USER, content="test")])
299220
signals = extract_complexity_signals("Find security vulnerabilities", ctx)
300221
activate, reason = should_activate_rlm("Find security vulnerabilities", ctx)
301-
# Returns: (True, "complexity_score:2:cross_context+pattern_search")
302222
```
303223

304224
---
@@ -486,7 +406,6 @@ RLM stores configuration at `~/.claude/rlm-config.json`:
486406

487407
```json
488408
{
489-
"use_rlm_core": true,
490409
"activation": {
491410
"mode": "complexity",
492411
"fallback_token_threshold": 80000
@@ -504,7 +423,6 @@ RLM stores configuration at `~/.claude/rlm-config.json`:
504423

505424
| Key | Type | Description |
506425
|-----|------|-------------|
507-
| `use_rlm_core` | bool | Enable rlm-core Rust bindings (default: `true`) |
508426
| `activation.mode` | string | `"micro"`, `"complexity"`, `"always"`, `"manual"` |
509427
| `depth.default` | int | Default recursion depth (1-3) |
510428
| `trajectory.verbosity` | string | `"minimal"`, `"normal"`, `"verbose"`, `"debug"` |
@@ -515,7 +433,6 @@ RLM stores configuration at `~/.claude/rlm-config.json`:
515433
|----------|---------|
516434
| `ANTHROPIC_API_KEY` | Anthropic API access (uses Claude Code's key) |
517435
| `OPENAI_API_KEY` | OpenAI API access (optional, for GPT models) |
518-
| `RLM_USE_CORE` | Enable rlm-core Rust bindings (`true`/`false`) |
519436
| `RLM_CONFIG_PATH` | Custom config file location |
520437
| `RLM_DEBUG` | Enable debug logging |
521438

pyproject.toml

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "rlm-claude-code"
3-
version = "0.6.1"
3+
version = "0.7.0"
44
description = "Recursive Language Model integration for Claude Code"
55
readme = "README.md"
66
requires-python = ">=3.12"
@@ -35,18 +35,15 @@ local = [
3535
"sentence-transformers>=2.0.0", # SetFit dependency
3636
"gliner>=0.2.0", # Entity/signal extraction for complexity detection
3737
]
38-
rlm-core = [
39-
# rlm-core Python bindings - build from ~/src/loop/rlm-core
40-
# Install with: pip install -e ~/src/loop/rlm-core --features python
41-
# Or: maturin develop --features python (from rlm-core directory)
42-
]
43-
4438
[build-system]
45-
requires = ["hatchling"]
46-
build-backend = "hatchling.build"
39+
requires = ["maturin>=1.4,<2.0"]
40+
build-backend = "maturin"
4741

48-
[tool.hatch.build.targets.wheel]
49-
packages = ["src"]
42+
[tool.maturin]
43+
manifest-path = "vendor/loop/rlm-core/Cargo.toml"
44+
features = ["python"]
45+
python-source = "."
46+
module-name = "rlm_core"
5047

5148
[tool.ruff]
5249
line-length = 100

0 commit comments

Comments
 (0)