# Project export: Monolith

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: TreeHacks 2026
- Tagline: Shared coding agent context powered by RLMs. One Context, Run Everywhere.
- Devpost: https://devpost.com/software/monolith-z10684
- GitHub: https://github.com/WingchunSiu/Monolith
- Video: https://www.youtube.com/embed/Ie0ZMGYPhS8?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Result: winner ([Modal] Sandbox Challenge)
- Team: 3 GitHub contributor(s) — Michael Siu (10 commits), Pranav Jadhav (8 commits), dmku33 (1 commits)

## Devpost submission (written by the team)

### Inspiration

RLMs are an elegant solution to the problem of context rot that let LLMs easily scale to millions of tokens, basically for free. Monolith lets you take advantage of RLMs for coding agents by giving each repo its own single chat history across devs working on the repo. This gives the agent a native understanding of your previous sessions and insights, such as design decisions, from other devs' sessions without you doing anything.

### What it does

Monolith is implemented as a plugin to any coding agent that supports MCP tooling, which allows it to query and interact with the shared context via the RLM harness described in the original paper. One context, run everywhere.

### How we built it

We used a couple of key technologies: Modal serverless functions Modal sandboxes Modal volumes OpenAI API Cloudflare Workers & Containers For some quick background, the RLM paradigm exposes the context as an object in a REPL environment for the root LM to interact with and inspect with sub-LMs to avoid polluting the main context. We implement the root LM with a Modal serverless function, which can provision sandboxes for the sub-LMs to do analysis on chunks of the context. The context is exposed as a file system in a Modal volume, which is mounted to all sandboxes.

### Challenges we ran into

Existing RLM implementations are very barebones, so we had to do a lot of engineering to make things work in the cloud on Modal. Designing the system was also an interesting problem. Initially, we wanted to store the monocontext in object storage (S3), however, we found that this was not a good primitive for slice and append heavy workloads, which is what our use case demanded.

### Accomplishments we're proud of

Getting the whole thing to actually work by 4 am-ish.

### What we learned

A lot about designing systems, agentic harnesses (this is what the "RLM" is at the end of the day), and Modal.

### What's next

We don't know if this is THE way to implement a massive mutable shared context, maybe the best implementations just converge to some kind of database. However, we think it is an interesting idea that has potential. We envision Monolith eventually incorporating git history (commit messages, PR comments, etc.) into the context and having the option of automatic initialization of Monolith into GitHub repos.

## README (from the GitHub repository)

# Monolith

***One context, run everywhere.***

**RLM-as-a-service: persistent, recursive reasoning for AI coding agents.**

Built on top of [alexzhang13/rlm](https://github.com/alexzhang13/rlm) — the open-source [Recursive Language Model](https://arxiv.org/abs/2512.24601v1) framework where LLMs offload context into a REPL environment and recursively call sub-LLMs to decompose complex tasks. On benchmarks like OOLONG (132k tokens), RLM(GPT-5-mini) outperforms GPT-5 by over 34 points at similar cost.

Monolith takes the core RLM and turns it into **deployed infrastructure** that AI agents can call as a tool. We wrap the RLM in an [MCP](https://modelcontextprotocol.io) server, deploy the compute on [Modal](https://modal.com) serverless, and add a persistent memory layer (Modal Volume) so the RLM accumulates context across sessions. The result: plug it into Claude Code and the agent gains the ability to recursively reason over arbitrarily large contexts — and remember what it learned.

## What We Added on Top of RLM

| Layer | What | Why |
|-------|------|-----|
| **MCP server** | `server.py` (stdio) + Cloudflare Worker (HTTP) | Exposes RLM as tools any MCP-compatible agent can call |
| **Modal backend** | `modal_runtime.py` — serverless functions + HTTP endpoints | No infra to manage; scales to zero when idle |
| **Persistent memory** | Modal Volume stores `{thread_id}/context.txt` | RLM builds on past sessions instead of starting from scratch |
| **Session auto-upload** | Claude Code `Stop` hook captures full transcripts | Every conversation becomes searchable context for the RLM |
| **Modal Sandbox sub-LLMs** | `ModalSandboxSubRLM` runs sub-LLM calls in isolated sandboxes | Safe code execution for recursive calls in the cloud |
| **CLI tools** | `python -m monolith.query` / `store` | Use RLM outside of Claude Code |

## Architecture

```
Claude Code
  │
  └─ MCP (stdio or streamable-http)
      │
      ▼
MCP Server                              ← thin routing layer
  │  (Python stdio server OR Cloudflare Worker)
  │
  ├─ chat_rlm_query(query, thread_id)
  │     │
  │     ▼
  │   Modal: run_rlm_remote()
  │     ├─ reads context from Volume: /{thread_id}/context.txt
  │     ├─ runs RLM_REPL reasoning loop:
  │     │    root LLM (gpt-5) ──writes code──▶ sandboxed REPL
  │     │                                        │
  │     │    REPL calls llm_query() ────────▶ sub-LLM (gpt-5-nano)
  │     │                                        │
  │     │    results flow back to root LLM ◀─────┘
  │     │    ... repeat up to N iterations
  │     ├─ appends Q&A turn to Volume
  │     └─ returns answer
  │
  └─ upload_context(transcript, session_id, thread_id)
        │
        ▼
      Modal: store_context()
        └─ appends transcript to Volume: /{thread_id}/context.txt
```

## How RLM Reasoning Works

The RLM never sees the full context directly. Instead it interacts with it programmatically through a REPL:

1. **Recon** — the root LLM reads the context file, checks its size, identifies the format and natural chunk boundaries
2. **Filter + Analyze** — writes Python code to split the context along those boundaries, uses regex/keywords to find relevant sections, then calls `llm_query()` to delegate semantic analysis of each section to a sub-LLM
3. **Aggregate + Answer** — synthesizes sub-LLM results via a final `llm_query()` call and returns the answer

The root LLM uses a powerful model (gpt-5) for orchestration while sub-LLMs use cheaper models (gpt-5-nano) for focused analysis — keeping cost low while handling arbitrarily large contexts.

## Quick Start

### Prerequisites

- Python 3.12+
- [Modal](https://modal.com) account
- OpenAI API key
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code)

### 1. Set up Modal

```bash
git clone https://github.com/WingchunSiu/Monolith.git
cd Monolith
modal token set
```

### 2. Upload your OpenAI key to the Modal Volume

```bash
modal volume create rlm-shared-volume
echo "OPENAI_API_KEY=sk-..." > /tmp/.env
modal volume put rlm-shared-volume /tmp/.env .env
rm /tmp/.env
```

### 3. Deploy the backend

```bash
cd mcp-modal
pip install -r requirements.txt
modal deploy modal_runtime.py
```

### 4. Connect to Claude Code

**Local mode (stdio — recommended for dev):**

```bash
claude mcp add monolith --transport stdio -- python /path/to/Monolith/mcp-modal/server.py
```

**Cloud mode (Cloudflare Worker → Modal HTTP):**

```bash
cd mcp-modal/cloudflare/worker-gateway
# set MODAL_BACKEND_URL in wrangler.toml
npm install && npm run deploy

claude mcp add monolith --transport http \
  --url https://monolith-mcp-modal.<subdomain>.workers.dev/mcp
```

### 5. Use it

Open Claude Code — the `chat_rlm_query` and `upload_context` tools are available automatically. The RLM handles recursive reasoning; Claude Code handles everything else.

## MCP Tools

### `chat_rlm_query`

Query the RLM with persistent thread context.

| Param | Type | Description |
|-------|------|-------------|
| `query` | string | The question to ask |
| `thread_id` | string | Thread identifier — context accumulates per thread |

### `upload_context`

Upload a transcript to the RLM's persistent memory.

| Param | Type | Description |
|-------|------|-------------|
| `transcript` | string | Full transcript text |
| `session_id` | string | Session identifier |
| `thread_id` | string | Thread to store under (default: `transcripts`) |

## Auto Session Upload

Add to `.claude/settings.local.json` to automatically capture every Claude Code session:

```json
{
  "hooks": {
    "Stop": [{
      "type": "command",
      "command": "/path/to/Monolith/scripts/session_end_upload.sh"
    }]
  }
}
```

Each transcript is uploaded with metadata (developer, git branch, timestamps, message count) so the RLM can reason over your full development history.

## Project Structure

```
Monolith/
├── mcp-modal/                  # MCP + Modal deployment layer
│   ├── server.py               # MCP server (stdio)
│   ├── modal_runtime.py        # Modal functions + HTTP endpoints
│   ├── rlm/                    # RLM package (mounted into Modal image)
│   └── cloudflare/             # Cloudflare Worker gateway
├── rlm/                        # Core RLM (forked from alexzhang13/rlm)
│   ├── rlm/
│   │   ├── rlm_repl.py         # RLM_REPL — recursive reasoning loop
│   │   ├── repl.py             # Sandboxed REPL with llm_query()
│   │   ├── sub_rlm_worker.py   # Sub-LLM worker for Modal Sandboxes
│   │   └── utils/
│   │       ├── llm.py          # OpenAI client wrapper
│   │       └── prompts.py      # System prompts + 3-phase strategy
│   └── main.py                 # Needle-in-haystack example
├── monolith/                   # CLI entry points
│   ├── query.py                # python -m monolith.query
│   └── store.py                # python -m monolith.store
└── scripts/
    └── session_end_upload.sh   # Stop hook for auto-upload
```

## References

- [Recursive Language Models](https://arxiv.org/abs/2512.24601v1) — Zhang, Kraska & Khattab (2025)
- [RLM blog post](https://alexzhang13.github.io/blog/2025/rlm/) and [original codebase](https://github.com/alexzhang13/rlm)
- [Model Context Protocol](https://modelcontextprotocol.io)
- [Modal](https://modal.com)

## Built at TreeHacks 2026


## Detected evidence (automated analysis)

Indexed codebase: 48 recognized source files, 238 KB.
- OpenAI (technology) — detected in the code
- Python (language) — detected in the code
- TypeScript (language) — detected in the code
- AI coding agent: Claude Code — evidence: config files committed to the repository; commit authorship or trailers
- AI coding agent: Codex — evidence: config files committed to the repository

## Codebase structure (from repository index)

### Files (62 of 62)

```
.claude/plan.md
.gitignore
.python-version
AGENTS.md
claude_tool_mcp/server.py
deeprecurse/__init__.py
deeprecurse/modal_repl.py
deeprecurse/query.py
deeprecurse/store.py
LICENSE
main.py
mcp-modal/cloudflare/worker-gateway/package.json
mcp-modal/cloudflare/worker-gateway/src/index.ts
mcp-modal/cloudflare/worker-gateway/tsconfig.json
mcp-modal/cloudflare/worker-gateway/wrangler.toml
mcp-modal/modal_runtime.py
mcp-modal/README.md
mcp-modal/requirements.txt
mcp-modal/rlm/__init__.py
mcp-modal/rlm/logger/__init__.py
mcp-modal/rlm/logger/repl_logger.py
mcp-modal/rlm/logger/root_logger.py
mcp-modal/rlm/repl.py
mcp-modal/rlm/rlm_repl.py
mcp-modal/rlm/rlm.py
mcp-modal/rlm/sub_rlm_worker.py
mcp-modal/rlm/utils/__init__.py
mcp-modal/rlm/utils/llm.py
mcp-modal/rlm/utils/prompts.py
mcp-modal/rlm/utils/utils.py
mcp-modal/scripts/session_end_upload.sh
mcp-modal/server.py
pyproject.toml
README.md
requirements.txt
rlm/.env-example
rlm/.gitignore
rlm/LICENSE
rlm/main.py
rlm/modal_runtime.py
rlm/README.md
rlm/requirements.txt
rlm/rlm/__init__.py
rlm/rlm/logger/__init__.py
rlm/rlm/logger/repl_logger.py
rlm/rlm/logger/root_logger.py
rlm/rlm/modal_repl.py
rlm/rlm/repl.py
rlm/rlm/rlm_repl.py
rlm/rlm/rlm.py
rlm/rlm/sub_rlm_worker.py
rlm/rlm/utils/__init__.py
rlm/rlm/utils/llm.py
rlm/rlm/utils/original_prompts.py
rlm/rlm/utils/prompts.py
rlm/rlm/utils/utils.py
scripts/generate_modal_test_transcript.py
scripts/generate_synthetic_transcripts.py
scripts/README.md
scripts/session_end_upload.sh
scripts/upload_context.py
uv.lock
```

### Dependencies

- mcp-modal/cloudflare/worker-gateway/package.json: @cloudflare/workers-types@^4.20250224.0, typescript@^5.7.3, wrangler@^4.31.0
- mcp-modal/requirements.txt: mcp[cli], modal, openai, python-dotenv, rich
- pyproject.toml: dotenv@>=0.9.9, modal@>=1.3.3, openai@>=2.21.0, rich@>=14.3.2
- requirements.txt: modal, openai, python-dotenv, rich
- rlm/requirements.txt: dotenv, modal, openai, rich

### Recent commits (newest first)

- update readme
- Merge pull request #8 from WingchunSiu/mcp-modal-working
- Add README, remove unused HTML files
- Add scripts, modal REPL, update MCP-Modal pipeline
- Fix MCP-Modal pipeline, restore CLI entry points, clean up
- Add MCP-Modal pipeline: Cloudflare gateway + Modal backend
- Merge pull request #6 from WingchunSiu/modal
- Simplify deeprecurse to use pranav's modal runtime
- Merge remote-tracking branch 'origin/pranav/modal-volumne' into modal
- update agents.md
- niah example working
- initial impl
- Merge pull request #5 from WingchunSiu/modal
- modal function rlm
- lock
- add uv
- add rlm minimal
- rlm minimal
- remove submodule
- Add RLM session memory analyzer with gpt-5-mini/nano

## Key source files (fetched from GitHub, selected and truncated for size)

### AGENTS.md

```markdown
# Monocontext
This is the repo for monocontext, a project using RLMs as a tool for coding agents. RLMs are an inference scaffold for language models that allow them to scale to millions of tokens input size almost for free. So instead of all devs having separate agent chat histories, why not just have a monocontext that they all share like an unstructured growing dev log. Then whenever necessary the coding agent can use the RLM as a tool call to pull useful context from the monocontext about what other devs have worked on or even from your own previous sessions.

# Overall Rules and Background
The RLM is implemented with modal. The idea is the RLM runs as a modal function and the sub agents run as sandboxes.
This project uses `uv` so please use uv for dependency management and running scripts.
Please understand the philosphy behind RLM and how it works from this blogpost: https://alexzhang13.github.io/blog/2025/rlm/
The basic RLM implementation is implemented in rlm/


## Problem Solving
- Err on the side of minimal and simple solutions.
- Avoid writing a whole overly complex code with lots of error handling cases.
- Build like you are writing a well engineered weekend project.
- Be concise and minimally invasive and deliberate with your edits.

# Modal Rules and Guidelines for LLMs

This file provides rules and guidelines for LLMs when implementing Modal code.

## General

- Modal is a serverless cloud platform for running Python code with minimal configuration
- Designed for AI/ML workloads but supports general-purpose cloud compute
- Serverless billing model - you only pay for resources used

## Modal documentation

- Extensive documentation is available at: modal.com/docs (and in markdown format at modal.com/llms-full.txt)
- A large collection of examples is available at: modal.com/docs/examples (and github.com/modal-labs/modal-examples)
- Reference documentation is available at: modal.com/docs/reference

Always refer to documentation and examples for up-to-date functionality and exact syntax.

## Core Modal concepts

### App

- A group of functions, classes and sandboxes that are deployed together.

### Function

- The basic unit of serverless execution on Modal.
- Each Function executes in its own container, and you can configure different Images for different Functions within the same App:

  ```python
  image = (
    modal.Image.debian_slim(python_version="3.12")
    .pip_install("torch", "transformers")
    .apt_install("ffmpeg")
    .run_commands("mkdir -p /models")
  )

  @app.function(image=image)
  def square(x: int) -> int:
    return x * x
  ```

- You can configure individual hardware requirements (CPU, memory, GPUs, etc.) for each Function.

  ```python
  @app.function(
    gpu="H100",
    memory=4096,
    cpu=2,
  )
  def inference():
    ...
  ```

  Some examples specificly for GPUs:

  ```python
  @app.function(gpu="A10G")  # Single GPU, e.g. T4, A10G, A100, H100, or "any"
  @app.function(gpu="A100:2")  # Multiple GPUs, e.g. 
[truncated — 4476 more characters]
```

### .claude/plan.md

```markdown
# Recursive RLM Architecture Integration Plan

## Goal
Integrate the broker-based ModalREPL architecture to enable true recursive sub-LLM calls with depth limiting.

## Current State (Simplified)
```
Root LLM (RLM_REPL)
  ↓ calls llm_query()
  ↓ spawns ephemeral Modal sandbox
  ↓ runs sub_rlm_worker.py
  ↓ makes direct OpenAI API call
  ↓ returns response
```
- Each sub-LLM call creates/destroys a sandbox
- No recursion: sub-LLMs cannot spawn their own REPLs
- No depth tracking

## Target State (Recursive)
```
Root LLM (RLM_REPL) [depth=0]
  ↓ uses ModalREPL (persistent sandbox with broker)
  ↓ sandbox code calls llm_query()
  ↓ broker forwards to LM handler
  ↓ creates Sub-RLM_REPL [depth=1]
  ↓ which has its own ModalREPL
  ↓ can call llm_query() again [depth=2]
  ↓ ... limited by MAX_DEPTH
```
- One persistent sandbox per RLM instance
- Sub-LLMs can spawn their own REPLs and recurse
- Depth tracking prevents infinite loops
- Broker pattern for async LLM request handling

## Architecture Components

### 1. ModalREPL Class
**Location:** `rlm/rlm/modal_repl.py` (new file, ~500 lines)

**Key Features:**
- Persistent Modal Sandbox with Flask broker on port 8080
- Tunneled HTTP communication via `encrypted_ports`
- Background polling thread for LLM requests
- State persistence via dill in `/tmp/rlm_state.dill`
- Provides `llm_query`, `llm_query_batched`, `FINAL_VAR`, `SHOW_VARS` in sandbox

**Interface (compatible with REPLEnv):**
```python
class ModalREPL:
    def __init__(self,
                 lm_handler: Callable,  # Function to handle LLM requests
                 depth: int = 0,
                 max_depth: int = 3,
                 context_payload: dict | list | str | None = None,
                 context_path: str | None = None,
                 image: modal.Image | None = None,
                 timeout: int = 600):
        self.depth = depth
        self.max_depth = max_depth
        self.sandbox = None  # Persistent
        self.broker_url = None
        self.locals = {}  # Synced from sandbox

    def code_execution(self, code: str) -> REPLResult:
        # Execute in sandbox, return REPLResult

    def cleanup(self):
        # Terminate sandbox, stop poller
```

### 2. LM Handler Function
**Location:** Inside RLM_REPL

The lm_handler is a function that receives an LLM request and routes it appropriately:

```python
def handle_llm_request(self, prompt: str, model: str | None, depth: int) -> str:
    """Handle LLM request from sandbox."""
    if depth >= self.max_depth:
        return f"Error: Maximum recursion depth ({self.max_depth}) reached"

    # Create a new RLM_REPL for the sub-LLM call
    sub_rlm = RLM_REPL(
        model=model or self.recursive_model,
        recursive_model=self.recursive_model,
        max_iterations=self.max_iterations,
        depth=depth + 1,
        max_depth=self.max_depth,
        enable_logging=self.enable_logging,
        # ... same modal config
    )

    # Run completion (this will create its own Modal
[truncated — 5041 more characters]
```

### requirements.txt

```
openai
python-dotenv
rich
modal

```

### pyproject.toml

```
[project]
name = "deeprecurse"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
    "dotenv>=0.9.9",
    "modal>=1.3.3",
    "openai>=2.21.0",
    "rich>=14.3.2",
]

```

### rlm/requirements.txt

```
openai
dotenv
rich
modal

```

### mcp-modal/requirements.txt

```
modal
openai
python-dotenv
rich
mcp[cli]

```

### mcp-modal/cloudflare/worker-gateway/package.json

```
{
  "name": "deeprecurse-mcp-modal-gateway",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "wrangler dev",
    "deploy": "wrangler deploy"
  },
  "devDependencies": {
    "@cloudflare/workers-types": "^4.20250224.0",
    "typescript": "^5.7.3",
    "wrangler": "^4.31.0"
  }
}

```

### main.py

```python
"""Local multi-turn chat CLI that queries the MCP server tool."""

from __future__ import annotations

import argparse
from dataclasses import dataclass
from pathlib import Path


DEFAULT_MODEL = "gpt-5"
DEFAULT_RECURSIVE_MODEL = "gpt-5-nano"
DEFAULT_CHAT_FILE = "chat.txt"
EXIT_COMMANDS = {"exit", "quit", ":q"}


def project_root() -> Path:
    return Path(__file__).resolve().parent


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(description="Prototype chat CLI using MCP-hosted RLM")
    parser.add_argument("--chat-file", default=DEFAULT_CHAT_FILE, help="Shared chat log path")
    return parser.parse_args()


@dataclass
class ChatConfig:
    chat_path: Path
    server_module: str = "claude_skill_mcp.server"


class MCPChatClient:
    """Thin local client that invokes the MCP server's chat tool function."""

    def __init__(self, server_module: str, chat_path: Path):
        # Import is local to keep CLI startup lightweight.
        from importlib import import_module

        server = import_module(server_module)
        self._chat_tool = server.chat_rlm_query
        self._chat_path = chat_path

    def answer(self, query: str) -> str:
        # chat_rlm_query handles read context + generate + append in server.py
        return self._chat_tool(query=query, chat_file=str(self._chat_path))


class ChatSession:
    def __init__(self, client: MCPChatClient):
        self.client = client

    def run(self) -> None:
        print("Chat-RLM ready. Type your question, or 'exit' to quit.")
        while True:
            query = input("You: ").strip()
            if not query:
                continue
            if query.lower() in EXIT_COMMANDS:
                print("Goodbye!")
                break

            print("Generating answer via MCP server tool...")
            answer = self.client.answer(query=query)
            print(f"Assistant: {answer}")


def build_config(args: argparse.Namespace) -> ChatConfig:
    chat_path = Path(args.chat_file)
    if not chat_path.is_absolute():
        chat_path = project_root() / chat_path

    return ChatConfig(
        chat_path=chat_path,
    )


def main() -> None:
    args = parse_args()
    config = build_config(args)

    session = ChatSession(MCPChatClient(config.server_module, config.chat_path))
    session.run()


if __name__ == "__main__":
    main()

```

### mcp-modal/server.py

```python
"""Stdio MCP server for local dev (no Cloudflare needed).

Calls Modal functions directly via .remote().

Usage:
  claude mcp add deeprecurse --transport stdio -- python /path/to/mcp-modal/server.py
"""

from __future__ import annotations

import modal
from mcp.server.fastmcp import FastMCP

MODAL_APP_NAME = "rlm-repl"

mcp = FastMCP("deeprecurse-chat-rlm")


@mcp.tool()
def chat_rlm_query(query: str, thread_id: str) -> str:
    """Use this to query the Python RLM backend while reading/updating
    shared persistent thread context (thread_id)."""
    clean_query = query.strip()
    if not clean_query:
        return "Error: query cannot be empty."

    context_relpath = f"{thread_id}/context.txt"

    try:
        run_rlm_remote = modal.Function.from_name(MODAL_APP_NAME, "run_rlm_remote")
        answer = run_rlm_remote.remote(query=clean_query, context_relpath=context_relpath)
    except Exception as exc:
        return f"Error running RLM: {exc}"

    return answer


@mcp.tool()
def upload_context(
    transcript: str,
    session_id: str,
    thread_id: str = "transcripts",
) -> str:
    """Upload a session transcript to the shared context store on Modal Volume.
    The transcript is stored under a thread so the RLM can reason over past sessions."""
    if not transcript.strip():
        return "Error: transcript cannot be empty."
    if not session_id.strip():
        return "Error: session_id cannot be empty."

    try:
        store_context_fn = modal.Function.from_name(MODAL_APP_NAME, "store_context")
        store_context_fn.remote(
            thread_id=thread_id,
            session_id=session_id,
            transcript=transcript,
        )
        return f"Uploaded session {session_id} to thread '{thread_id}'."
    except Exception as exc:
        return f"Error uploading context: {exc}"


if __name__ == "__main__":
    mcp.run()

```

### rlm/main.py

```python
from __future__ import annotations

from pathlib import Path
import random
import tempfile
import uuid

import modal

try:
    from modal_runtime import ENV_RELATIVE_PATH, app, run_rlm_remote, shared_volume
except ImportError:
    from rlm.modal_runtime import ENV_RELATIVE_PATH, app, run_rlm_remote, shared_volume


def generate_massive_context_file(context_path: Path, num_lines: int = 1_000_000, answer: str = "1298418") -> int:
    print("Generating massive context with 1M lines...")

    # Set of random words to use
    random_words = ["blah", "random", "text", "data", "content", "information", "sample"]

    # Insert the magic number at a random position (somewhere in the middle)
    magic_position = random.randint(400000, 600000)

    with open(context_path, "w", encoding="utf-8") as file:
        for i in range(num_lines):
            if i == magic_position:
                line = f"The magic number is {answer}"
            else:
                num_words = random.randint(3, 8)
                line_words = [random.choice(random_words) for _ in range(num_words)]
                line = " ".join(line_words)
            file.write(line)
            if i < num_lines - 1:
                file.write("\n")

    print(f"Magic number inserted at position {magic_position}")
    return magic_position


def resolve_env_file() -> Path:
    project_root = Path(__file__).resolve().parents[1]
    candidates = [
        project_root / ".env",
        Path(__file__).resolve().parent / ".env",
    ]
    for candidate in candidates:
        if candidate.exists():
            return candidate
    raise FileNotFoundError(
        "Could not find .env file. Expected one at project root (.env) or rlm/.env."
    )


def upload_inputs_to_volume(context_file: Path, env_file: Path) -> str:
    run_id = uuid.uuid4().hex
    context_relpath = f"runs/{run_id}/context.txt"
    with shared_volume.batch_upload(force=True) as batch:
        batch.put_file(str(context_file), context_relpath)
        batch.put_file(str(env_file), ENV_RELATIVE_PATH)
    return context_relpath

def main():
    print("Example of using RLM (REPL) on Modal with a needle-in-haystack problem.")
    answer = str(random.randint(1000000, 9999999))
    env_file = resolve_env_file()
    query = "I'm looking for a magic number. What is it?"

    with tempfile.TemporaryDirectory(prefix="rlm_context_") as tmp_dir:
        context_file = Path(tmp_dir) / "context.txt"
        generate_massive_context_file(context_file, num_lines=1_000_000, answer=answer)
        context_relpath = upload_inputs_to_volume(context_file, env_file)
    with modal.enable_output():
        with app.run():
            result = run_rlm_remote.remote(
                query=query,
                context_relpath=context_relpath,
                model="gpt-5-mini",
                recursive_model="gpt-5-nano",
                max_iterations=10,
            )
    print(f"Result: {result}. Expected: {answer}")

if __name__ == "__main__":
    main()

```

[35 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]