What Are the Main APIs Exposed by RLM? A Complete Guide to the Recursive Language Model Interface

RLM exposes a compact public API centered on the RLM class for recursive execution, a get_client factory for backend abstraction, a structured exception hierarchy for limit enforcement, and optional logging utilities, all re-exported from the top-level rlm package.

The alexzhang13/rlm repository implements a Recursive Language Model that runs language models with built-in REPL support, sub-calls, and budget tracking. Understanding what are the main APIs exposed by RLM allows developers to configure backends, manage persistent environments, and handle execution limits without interacting with internal runtime plumbing.

The RLM Class: Core Entry Point

The primary public interface resides in rlm/core/rlm.py. Instantiating the RLM class configures the backend, environment, execution limits, and callbacks.

Instantiation and Configuration

The constructor accepts parameters for backend selection, environment type (e.g., "local"), iteration limits, budget constraints, and optional loggers.

from rlm import RLM
from rlm.logger import RLMLogger

rlm = RLM(
    backend="openai",
    backend_kwargs={"model_name": "gpt-4o-mini", "api_key": "<YOUR_KEY>"},
    environment="local",
    max_iterations=15,
    max_budget=0.05,
    verbose=True,
    logger=RLMLogger(log_dir="./logs"),
)

The completion Method

The RLM.completion(prompt, root_prompt=None) method runs a full RLM cycle, processing the system prompt through iterations until completion or limit violation. According to the source code in rlm/core/rlm.py, this method returns an RLMChatCompletion data class containing the final answer, usage statistics, timing metadata, and optional trajectory information.

result = rlm.completion(
    "Summarize the following text in three bullet points:\n\n"
    "Lorem ipsum dolor sit amet..."
)

print("Answer:", result.response)
print("Tokens used:", result.usage_summary.total_input_tokens,
      "+", result.usage_summary.total_output_tokens)

Context Manager Support

The RLM class implements __enter__ and __exit__ methods, enabling context-manager support for automatic resource cleanup. This pattern is essential when using persistent REPLs that maintain state across multiple calls.

with RLM(
    backend="openai",
    backend_kwargs={"model_name": "gpt-4o-mini"},
    environment="local",
    persistent=True,
) as rlm:
    r1 = rlm.completion("List the planets in the solar system.")
    r2 = rlm.completion("Now give me the average distance from the Sun for each.")

Explicit Resource Cleanup

For persistent environments outside of a context manager, the RLM.close() method explicitly releases resources and terminates the REPL subprocess.

rlm = RLM(backend="openai", backend_kwargs={"model_name": "gpt-4o-mini"}, persistent=True)

# ... use rlm ...

rlm.close()

Backend Client Factory

The get_client(backend, backend_kwargs) function in rlm/clients/__init__.py serves as a factory that instantiates concrete LM clients based on the requested backend identifier. This abstraction supports OpenAIClient, AnthropicClient, GeminiClient, and other implementations without exposing provider-specific details in the main API.

from rlm.clients import get_client

client = get_client("anthropic", {"model_name": "claude-3-opus", "api_key": "<KEY>"})

Exception Hierarchy for Limit Enforcement

As implemented in rlm/utils/exceptions.py, RLM exposes a structured exception hierarchy to signal specific limit violations. These exceptions are part of the public contract and should be caught when implementing robust error handling.

  • BudgetExceededError – Raised when execution costs exceed max_budget
  • TimeoutExceededError – Raised when execution exceeds max_timeout seconds
  • TokenLimitExceededError – Raised when token consumption exceeds configured limits
  • ErrorThresholdExceededError – Raised when consecutive error iterations exceed tolerance
  • CancellationError – Raised when execution is manually cancelled
from rlm import RLM, BudgetExceededError, TimeoutExceededError

rlm = RLM(
    backend="openai",
    backend_kwargs={"model_name": "gpt-4o-mini"},
    max_budget=0.001,
    max_timeout=5,
)

try:
    rlm.completion("Write a 10-page essay about quantum computing.")
except BudgetExceededError as be:
    print("Budget depleted:", be)
except TimeoutExceededError as te:
    print("Execution timed out:", te)

Logging and Observability Utilities

RLMLogger

The RLMLogger class in rlm/logger/rlm_logger.py provides optional structured logging that records each iteration, metadata, and can persist detailed trajectories to disk for debugging or audit purposes.

from rlm.logger import RLMLogger

logger = RLMLogger(log_dir="./logs")
rlm = RLM(..., logger=logger)

VerbosePrinter

When verbose=True is passed to the RLM constructor, the VerbosePrinter class from rlm/logger/verbose.py handles lightweight console pretty-printing of execution steps without requiring manual logger configuration.

Package-Level Exports

The rlm/__init__.py file re-exports the core symbols, enabling clean imports:

from rlm import RLM, BudgetExceededError, TimeoutExceededError, TokenLimitExceededError

Internal environment-specific functions (such as llm_query, rlm_query, SHOW_VARS) are injected into the REPL runtime and are not part of the public Python API; they are accessible only from code executed inside the REPL environment defined in rlm/environments/local_repl.py.

Advanced Usage Examples

Injecting Custom Tools

Developers can inject Python functions and constants into the REPL environment via the custom_tools parameter, making them available to the model during execution.

def fetch_number():
    return 42

custom_tools = {
    "fetch_number": {"tool": fetch_number, "description": "Returns a secret integer"},
    "PI": 3.14159,
}

rlm = RLM(
    backend="openai",
    backend_kwargs={"model_name": "gpt-4o-mini"},
    environment="local",
    custom_tools=custom_tools,
)

answer = rlm.completion(
    "Use the provided tool `fetch_number` to get the secret integer and add PI to it."
)
print(answer.response)  # Output: 45.14159

Summary

  • Core API: The RLM class in rlm/core/rlm.py provides completion(), context-manager support, and resource cleanup for recursive language model execution.
  • Backend Abstraction: get_client() in rlm/clients/__init__.py instantiates provider-specific clients based on string identifiers.
  • Error Handling: A structured exception hierarchy in rlm/utils/exceptions.py signals budget, timeout, token, and threshold violations.
  • Observability: RLMLogger and VerbosePrinter provide optional logging and console output for debugging recursive workflows.
  • Public Surface: Only RLM, exception classes, and logging utilities are exported from the top-level rlm package; internal REPL functions remain encapsulated.

Frequently Asked Questions

What is the return type of the RLM.completion method?

The RLM.completion() method returns an RLMChatCompletion data class instance. This object contains the final response string, usage_summary with token counts, execution_time in seconds, and optional trajectory metadata for debugging.

How do I handle persistent state across multiple calls to RLM?

Set persistent=True when instantiating the RLM class and use it as a context manager with with RLM(...) as rlm:. This maintains the same REPL subprocess across calls, preserving variables and state between invocations of completion(). Always ensure proper cleanup via the context manager or by calling rlm.close() explicitly.

Can I use different LLM providers with the same RLM API?

Yes. The backend parameter accepts identifiers like "openai", "anthropic", or "gemini", and the get_client() factory in rlm/clients/__init__.py instantiates the appropriate client. The RLM class interacts with these backends through a unified interface, making provider swaps transparent to your application logic.

What functions are available inside the RLM REPL environment?

The REPL environment injects utility functions such as llm_query(), rlm_query(), SHOW_VARS, and answer() for recursive calls and introspection. However, these are not part of the public Python API; they are runtime globals available only to code executing inside the REPL subprocess, as defined in rlm/environments/local_repl.py.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →