guides/python/recursive-language-models/README.md
This guide demonstrates how to implement a recursive language model (RLM) agent system built on Daytona sandboxes, based on the approach pioneered in Recursive Language Models (Zhang, Kraska, Khattab). Unlike traditional single-agent approaches, agents can spawn sub-agents recursively, each in its own isolated sandbox with a fresh clone of the target repository.
The system enables tree-structured problem decomposition: a root agent can delegate subtasks to child agents, which can spawn their own children, creating a hierarchy of specialized workers collaborating on complex software engineering tasks.
rlm_query(), each with their own sandboxrlm_query_batched() spawns multiple sub-agents concurrently using thread poolsDAYTONA_API_KEY: Required for access to Daytona sandboxes. Get it from Daytona DashboardLLM_API_KEY: Required for your LLM provider via LiteLLM (OpenRouter, OpenAI, Anthropic, etc.)python3.10 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -e .
.env (copy from .env.example):cp .env.example .env
# Edit .env with your DAYTONA_API_KEY and LLM_API_KEY
python run.py https://github.com/user/repo --prompt "Fix the bug in auth.py"
repo - GitHub repository URL (required, positional)-p, --prompt - Task prompt for the agent (required)-b, --branch - Branch name (optional)--commit - Specific commit SHA (optional)-c, --config - Path to YAML configuration file (default: config.yaml)-o, --output - Output file for the patch (default: stdout)--verbose / --quiet - Enable verbose output (default: verbose)The script has several configurable parameters in config.yaml:
max_sandboxes: Maximum total sandboxes that can be created over the entire run (default: 50)global_timeout: Total timeout in seconds for the entire run (default: 1800 = 30 minutes)model.name: The LLM model to use in LiteLLM format (default: openrouter/google/gemini-3-flash-preview)max_iterations: Maximum iterations per agent before timeout (default: 50)result_truncation_limit: Maximum characters for sub-agent results (default: 20000)The system runs a recursive agent architecture where each agent operates in its own sandbox.
rlm_query(task), a new sub-agent is created with its own sandboxFINAL() or times out, producing a git patch of all changesRoot Agent (depth=0)
├── Sub-Agent A (depth=1)
│ ├── Sub-Agent A1 (depth=2)
│ └── Sub-Agent A2 (depth=2)
└── Sub-Agent B (depth=1)
├── Sub-Agent B1 (depth=2)
└── Sub-Agent B2 (depth=2)
| Function | Description |
|---|---|
rlm_query(task) | Spawn a single sub-agent with the given task, returns result string |
rlm_query_batched(tasks) | Spawn multiple sub-agents in parallel, returns list of result strings |
FINAL(answer) | Submit final result (root agent: triggers git patch extraction) |
FINAL_VAR(var_name) | Submit the value of a variable as the result |
edit_file(path, old, new) | Edit a file with syntax validation |
Variables and imports persist between iterations within the same agent.
Start a local server and open the viewer to visualize agent execution:
python -m http.server 8000
# Open http://localhost:8000/viewer/
The viewer provides:
After running, results are saved in the results/ directory:
{run_id}.detail.json: Full agent tree with all iterations, code blocks, and outputsindex.json: Index of all runs for the viewer-o file)See the main project LICENSE file for details.