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

> Discover the core RLM APIs: RLM class for recursive execution, get_client factory for backend abstraction, and structured exceptions. Understand the Recursive Language Model interface.

- Repository: [az/rlm](https://github.com/alexzhang13/rlm)
- Tags: api-reference
- Published: 2026-06-18

---

**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`](https://github.com/alexzhang13/rlm/blob/main/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.

```python
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`](https://github.com/alexzhang13/rlm/blob/main/rlm/core/rlm.py), this method returns an `RLMChatCompletion` data class containing the final answer, usage statistics, timing metadata, and optional trajectory information.

```python
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.

```python
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.

```python
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`](https://github.com/alexzhang13/rlm/blob/main/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.

```python
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`](https://github.com/alexzhang13/rlm/blob/main/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

```python
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`](https://github.com/alexzhang13/rlm/blob/main/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.

```python
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`](https://github.com/alexzhang13/rlm/blob/main/rlm/logger/verbose.py) handles lightweight console pretty-printing of execution steps without requiring manual logger configuration.

## Package-Level Exports

The [`rlm/__init__.py`](https://github.com/alexzhang13/rlm/blob/main/rlm/__init__.py) file re-exports the core symbols, enabling clean imports:

```python
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`](https://github.com/alexzhang13/rlm/blob/main/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.

```python
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`](https://github.com/alexzhang13/rlm/blob/main/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`](https://github.com/alexzhang13/rlm/blob/main/rlm/clients/__init__.py) instantiates provider-specific clients based on string identifiers.
- **Error Handling**: A structured exception hierarchy in [`rlm/utils/exceptions.py`](https://github.com/alexzhang13/rlm/blob/main/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`](https://github.com/alexzhang13/rlm/blob/main/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`](https://github.com/alexzhang13/rlm/blob/main/rlm/environments/local_repl.py).