Skip to content
Markdown

Recursive language models: training one policy to be both parent and child

Scope: an agent architecture where a model handles long or wide context by recursively calling itself on sub-problems, and the proposed training objective for one policy in both roles. This page distinguishes the alphaXiv blog's inherited-root-advantage equation from the reward behavior in the released SkyRL implementation, then validates branch normalization and finite-concurrency latency structurally. Non-recursive planning is in agent planning and reasoning; the underlying RL algorithm is in GRPO; alternative long-context handling is in ReContext.

Primary report: Daniel Kim and Rehaan Ahmad, "Reinforcing Recursive Language Models", published 2026-05-13 on the alphaXiv blog. It is a blog post reporting one experiment, not a peer-reviewed paper. Official SkyRL code is now available; repository commit b5fdfd0801014b04aa021a746a5c1c30101a1407 was inspected, along with merge commit 811f8ee9df8cae0bee16803bb4bd535f98a1cebf. Nothing was reproduced: no training run was performed here. The Python block is this page's executed structural model, not an execution of SkyRL.

What it is

A Recursive Language Model does not receive its context as a prompt. It receives a handle to it and a Python REPL, and it decides what to look at and what to delegate. The action space reported for this work:

  • rlm_query(prompt, context=None) spawns one child RLM; rlm_query_batched(prompts, context_list=None) dispatches several in parallel.
  • FINAL(answer) submits a literal string; FINAL_VAR(variable_name) submits the contents of a REPL variable, so a large answer never has to pass through the model's own output tokens.
  • list_papers(), search(), extract_section(), get_paper_abstract() inspect the context without loading all of it.

The child is the same policy as the parent. There is no separate sub-agent model, no separate reward model for sub-tasks, and no hand-written decomposition strategy. The parent learns what to delegate and the child learns to answer delegated questions, from the same weights and the same gradient.

The training problem this creates is credit assignment. The blog objective gives no independent child score. It assigns every child its root's group-relative advantage, A_{g,i} := A_g; the authors describe this estimator as unbiased and note that finer-grained credit could converge faster.

The released implementation does not directly implement that statement in the inspected reward path. RLMGymGenerator._post_process_agent_loop_output says each child retains rewards assigned by its independent agent_loop call and prepends those child step outputs when train_child_trajectories=true. The multi-paper environment returns reward 0.0 for depth greater than zero. No parent-advantage overwrite was found in these code paths. Even rlm_config.py describes parent reward propagation, so the release is internally inconsistent. Treat the blog equation and current code as different semantics until an upstream test demonstrates propagation.

The blog's second piece is normalization. Its combined objective for a root and k_g children is 1/G * sum_g [L_root + (1/k_g) * sum_i L_child_i] - beta * D_KL, and its arbitrary-depth recursion is L_subtree(y, A) = L_node(y, A) + (1/k_y) * sum_i L_subtree(y_i, A). The 1/k factor prevents a root from gaining total weight merely by spawning more children at one level.

Why use it

The executed model below makes both concrete, and the second one is more interesting than it first looks.

The proposed inheritance rule removes an entire scoring problem. In the modelled blog objective, 8 root rollouts spawn 27 children and require no additional child reward evaluations. That is a property of the equation, not a verified behavior of the current SkyRL training path.

Normalization removes a bias that correlates with nothing. Branchiness is a property of what the policy happened to do, not of how well it did. In the modelled group the branchiest root, with 12 children, has the worst advantage at -1.605. Unnormalized, it takes 37.1% of the gradient; normalized, 14.3%. Training without the 1/k factor would spend more than a third of the update amplifying the structure of the worst rollout in the group.

For a full tree whose leaves all have the same depth, the 1/k recurrence gives weight depth + 1: a depth-4 branching-6 tree has 1,555 nodes and weight 5.0. For an irregular tree, the recurrence is one plus the average child-subtree weight, so total weight depends on average path depth and is at most maximum_depth + 1. It is not universally linear in maximum depth.

When to use it (and when not)

Consider a recursive architecture when:

  • Context is wide rather than long. The reported task is evidence selection across groups of up to 10 papers, which decomposes naturally into per-document sub-queries. Independent sub-problems are what recursion exploits.
  • Latency matters more than aggregate work. Batched children can overlap, but finite inference concurrency turns wide levels into multiple service waves. Wall clock depends on depth, level width, queueing, and per-node service time.
  • You can run a small model locally. The reported result is a 4B model on one node beating an API model on latency by roughly an order of magnitude.

Do not use it when:

  • The task does not decompose. A genuinely sequential reasoning chain gains nothing and pays the tree's token multiple.
  • Aggregate inference work is the binding cost. A recursive tree can issue far more model calls than a direct pass even when batching reduces elapsed time.
  • You need the strongest possible answer. In the reported evaluation the fine-tuned 4B model scores about 0.58 average rubric against Claude Sonnet's 0.607. It trades a little quality for a lot of latency.

Architecture

flowchart TB
  ROOT["Root RLM<br/>query plus context handle"] --> REPL["Persistent Python REPL"]
  REPL --> BATCH["rlm_query_batched<br/>submit child prompts"]
  BATCH --> QUEUE["Finite-concurrency inference queue"]
  QUEUE --> C1["Child RLM"]
  QUEUE --> C2["Child RLM"]
  QUEUE --> C3["Additional children in later waves"]
  C1 --> RET["Ordered child answer strings"]
  C2 --> RET
  C3 --> RET
  RET --> REPL
  REPL --> FIN["FINAL(answer) or FINAL_VAR(name)"]
  ROOT -.-> BLOG["Blog objective:<br/>inherit root advantage and average children"]
  ROOT -.-> CODE["Released code:<br/>independent child rewards retained"]

How to use it: validate the proposed objective and serving bounds

Run: python3 rlm.py.

import numpy as np

rng = np.random.default_rng(3)

# --- 1. Blog objective: GRPO root advantage inherited by children ---------
# This validates the published equation. The inspected SkyRL reward path does
# not contain the corresponding parent-advantage overwrite.
G = 8                                   # rollouts per prompt
rewards = np.array([0.9, 0.2, 0.6, 0.6, 0.1, 0.8, 0.4, 0.5])
assert len(rewards) == G


def grpo_advantage(r: np.ndarray) -> np.ndarray:
    return (r - r.mean()) / (r.std() + 1e-8)


A = grpo_advantage(rewards)
print(f"[1] rewards    {np.array2string(rewards, precision=2)}")
print(f"[1] advantages {np.array2string(A, precision=3)}")
assert np.isclose(A.mean(), 0.0, atol=1e-6), "group-normalized advantages are centered"
# Children of rollout g all take A_g. No separate reward is computed for them,
# which is what removes the need to score sub-agent trajectories.
children_per_root = np.array([1, 5, 0, 3, 12, 2, 0, 4])
inherited = [np.full(k, A[g]) for g, k in enumerate(children_per_root)]
print(f"[1] blog-objective children per root {children_per_root.tolist()} "
      f"-> {int(children_per_root.sum())} child rollouts, 0 child reward evaluations")
assert all(np.allclose(c, A[g]) for g, c in enumerate(inherited)), "uniform inheritance"

# --- 2. Why the 1/k normalization is load-bearing ------------------------
# Without it, a root that happens to spawn many children contributes
# proportionally more gradient, independent of whether it was a good rollout.
print()


def root_weight(k: np.ndarray, normalize: bool) -> np.ndarray:
    """Total gradient weight each root contributes: its own node plus children.

    With 1/k normalization the children sum to weight 1 regardless of how many
    there are. A root with no children contributes only its own node.
    """
    has_children = (k > 0).astype(float)
    return 1.0 + (has_children if normalize else k.astype(float))


w_norm = root_weight(children_per_root, True)
w_raw = root_weight(children_per_root, False)
print(f"[2] normalized 1/k : weights {np.array2string(w_norm, precision=2)} "
      f"(max/min = {w_norm.max() / w_norm.min():.2f})")
print(f"[2] no normalization: weights {np.array2string(w_raw, precision=2)} "
      f"(max/min = {w_raw.max() / w_raw.min():.2f})")
assert w_norm.max() / w_norm.min() == 2.0, "childless roots weigh 1, branching roots weigh 2"
assert w_raw.max() / w_raw.min() > 6.0, "without it, branchy roots dominate"

# The bias this removes is real: branchiness correlates with nothing useful.
# Here the branchiest root (12 children) has a BELOW-average advantage.
worst = int(np.argmax(children_per_root))
print(f"[2] root {worst} spawned the most children ({children_per_root[worst]}) "
      f"and has advantage {A[worst]:+.3f}")
share_raw = w_raw[worst] / w_raw.sum()
share_norm = w_norm[worst] / w_norm.sum()
print(f"[2] its gradient share: {100 * share_raw:.1f}% unnormalized vs "
      f"{100 * share_norm:.1f}% normalized ({share_raw / share_norm:.2f}x over-weighted)")
assert A[worst] < 0, "the branchiest rollout here is a below-average one"
assert share_raw / share_norm > 2.0, "unnormalized training over-weights it several fold"

# --- 3. Recursive subtree loss at arbitrary depth ------------------------
# L_subtree(y, A) = L_node(y, A) + (1/k_y) * sum_i L_subtree(y_i, A)
print()


def subtree_weight(tree) -> float:
    """One plus the mean child-subtree weight; leaves are empty tuples."""
    if not tree:
        return 1.0
    return 1.0 + sum(subtree_weight(child) for child in tree) / len(tree)


def full_tree(depth: int, branching: int):
    assert depth >= 0 and branching >= 1
    return () if depth == 0 else tuple(full_tree(depth - 1, branching) for _ in range(branching))


def max_depth(tree) -> int:
    return 0 if not tree else 1 + max(max_depth(child) for child in tree)


for d in range(5):
    tree = full_tree(d, branching=6)
    w = subtree_weight(tree)
    nodes = sum(6 ** i for i in range(d + 1))
    print(f"[3] depth {d}: {nodes:>6,} nodes in the tree, total gradient weight {w:.1f}")
assert subtree_weight(full_tree(4, 6)) == 5.0
# Full equal-depth trees attain depth+1. Irregular trees equal one plus an
# average over child paths, so they can be strictly below max_depth+1.
leaf = ()
irregular = (leaf, (leaf, (leaf,)))
irregular_weight = subtree_weight(irregular)
print(f"[3] irregular depth {max_depth(irregular)} tree has weight {irregular_weight:.2f} "
      f"(< depth+1 = {max_depth(irregular) + 1})")
assert 1.0 <= irregular_weight < max_depth(irregular) + 1
# Duplicating equivalent children changes node count but not their mean weight.
assert subtree_weight((full_tree(2, 2),)) == subtree_weight((full_tree(2, 2),) * 9)
naive_nodes = sum(6 ** i for i in range(5))
print(f"[3] a depth-4 branching-6 tree has {naive_nodes:,} nodes but contributes "
      f"weight {subtree_weight(full_tree(4, 6)):.1f}, not {naive_nodes:,}")
assert naive_nodes > 300 * subtree_weight(full_tree(4, 6))

# --- 4. Finite-concurrency latency waves plus reported source facts --------
print()
def service_waves(level_widths, concurrency: int) -> int:
    assert concurrency >= 1 and all(width >= 1 for width in level_widths)
    return sum((width + concurrency - 1) // concurrency for width in level_widths)


levels = [1, 6, 36]  # full depth-2, branching-6 call tree: 43 model calls
for capacity in (4, 8, 16):
    waves = service_waves(levels, capacity)
    print(f"[4] level widths {levels}, concurrency {capacity:>2}: {waves:>2} service waves")
assert service_waves(levels, 4) == 12
assert service_waves(levels, 8) == 7
assert service_waves(levels, 16) == 5
assert service_waves(levels, 10_000) == len(levels)      # unlimited-concurrency lower bound
assert sum(levels) == 43

# These are reported end-to-end measurements, not outputs of the wave model.
REPORTED_LOCAL_S = 7.0
REPORTED_SONNET_LOWER_S = 60.0
print(f"[4] source-reported query latency: local 4B {REPORTED_LOCAL_S:.0f} s, "
      f"Sonnet RLM >{REPORTED_SONNET_LOWER_S:.0f} s (>"
      f"{REPORTED_SONNET_LOWER_S / REPORTED_LOCAL_S:.1f}x)")
assert REPORTED_SONNET_LOWER_S / REPORTED_LOCAL_S > 8.5

print("\nAll assertions passed.")

Executed output:

[1] rewards    [0.9 0.2 0.6 0.6 0.1 0.8 0.4 0.5]
[1] advantages [ 1.507 -1.216  0.34   0.34  -1.605  1.118 -0.438 -0.049]
[1] blog-objective children per root [1, 5, 0, 3, 12, 2, 0, 4] -> 27 child rollouts, 0 child reward evaluations

[2] normalized 1/k : weights [2. 2. 1. 2. 2. 2. 1. 2.] (max/min = 2.00)
[2] no normalization: weights [ 2.  6.  1.  4. 13.  3.  1.  5.] (max/min = 13.00)
[2] root 4 spawned the most children (12) and has advantage -1.605
[2] its gradient share: 37.1% unnormalized vs 14.3% normalized (2.60x over-weighted)

[3] depth 0:      1 nodes in the tree, total gradient weight 1.0
[3] depth 1:      7 nodes in the tree, total gradient weight 2.0
[3] depth 2:     43 nodes in the tree, total gradient weight 3.0
[3] depth 3:    259 nodes in the tree, total gradient weight 4.0
[3] depth 4:  1,555 nodes in the tree, total gradient weight 5.0
[3] irregular depth 3 tree has weight 2.75 (< depth+1 = 4)
[3] a depth-4 branching-6 tree has 1,555 nodes but contributes weight 5.0, not 1,555

[4] level widths [1, 6, 36], concurrency  4: 12 service waves
[4] level widths [1, 6, 36], concurrency  8:  7 service waves
[4] level widths [1, 6, 36], concurrency 16:  5 service waves
[4] source-reported query latency: local 4B 7 s, Sonnet RLM >60 s (>8.6x)

All assertions passed.

Two cautions follow from that output.

The blog's inheritance rule has coarse credit. Every child of a good root receives its positive advantage, including children that returned nothing useful, and every child of a bad root receives its negative advantage, including children that were right. The authors call the estimator unbiased and suggest finer-grained credit could improve convergence; neither statement is independently established here. The released multi-paper environment instead returns zero reward for children, so its effective training signal must be inspected rather than inferred from the blog equation.

Parallelism reduces elapsed time, not aggregate work. The modelled depth-2 tree issues 43 calls. With equal per-call service time it needs at least three sequential level waves even with unlimited width, and 12 waves at concurrency four. The reported 7-second local result and greater-than-60-second API result are measurements from one setup, not consequences of the structural model.

What the depth ablation shows: more recursion is not monotonically better

The blog this page is built on trains one policy at max depth 1 and notes only that the objective "can be expanded to any RLM depth". It reports no experiments beyond depth 1. The originating RLM paper does run that ablation, across max recursion depths 0 to 3, and its results complicate the obvious assumption that deeper is stronger.1

Depth 0 is the REPL with no sub-calling at all: the model still offloads the long prompt into an environment variable and manipulates it programmatically, but never calls a model on a snippet. Depth 1 sub-calls plain LMs. Depth greater than 1 sub-calls RLMs.

Three results are worth carrying:

  • The REPL, not the recursion, does most of the long-context work. The paper's own framing is that "the REPL is necessary for handling long inputs, while the recursive sub-calling of RLMs provides strong benefits on information-dense inputs". Depth 0 already scales beyond the model's context limit and beats most task-agnostic baselines on long-context settings.
  • Deeper can be worse. On CodeQA with Qwen3-Coder-480B-A35B, "the no-sub-calling RLM(depth=0) is able to outperform all sub-calling variants of the RLM." If your task is long but not information-dense, recursion is adding cost and variance for nothing.
  • Deeper pays where the input is information-dense. On OOLONG-Pairs the higher-depth GPT-5 variants beat every other method including Claude Code and OpenCode by a large margin. That is the regime where a sub-call has to actually transform content rather than locate it.

So depth is a task-shape decision, not a quality dial. Start at depth 0, and only add a level when you can point at the transformation a sub-call is doing that the REPL cannot.

Recursion is not free at short context, and its cost is a distribution

Two more findings from the same source bound the enthusiasm.

There is a context-length crossover. Comparing RLM(GPT-5, depth=1) against base GPT-5, the paper reports that "for context lengths beyond 2^14, the RLM consistently outperforms GPT-5." That word "beyond" is the caveat: below roughly 16k tokens the advantage is not consistent, which is what you would expect when the base model can simply read everything and the scaffold is pure overhead. Recursion earns its keep past the point where the base model starts degrading, and the paper is explicit that base-LM performance "degrades as a function of input length and problem complexity", so the crossover moves with task difficulty rather than sitting at one token count.

The nuance is that within-window does not automatically mean skip it. On tasks whose processing cost scales with input length, the paper reports RLM(depth=1) beating the base model "even on tasks within the model's context window", by 28.4% with GPT-5 and 33.3% with Qwen3-Coder on OOLONG. The distinction is whether the task requires work proportional to the context, not whether the context fits.

Cost is bimodal, so report the median and the mean. The paper finds "the median RLM run is cheaper than the median base model run, but more expensive on average due to outlier trajectories where the RLM struggles to find an answer." That is the shape to plan for: most requests cheap, a tail where the model flails through sub-calls and spends heavily. A capacity model built on the median will under-provision; one built on the mean will over-provision for the common case. Track both, and cap sub-call count as a tail control.

Treat published runtimes with care. The authors flag that their runtime numbers are "heavily dependent on implementation details such as the machine used, API request latency, and the asynchrony of LM calls", and that in their implementation "all LM calls are blocking / sequential". A production implementation that batches sibling sub-calls has a different latency profile entirely, which is the point the finite-concurrency model above is making.

How to develop with it

  • Choose the child-credit semantics explicitly. If implementing the blog objective, overwrite every child's advantage with its root advantage, divide each sibling set by its actual child count, and add a tensor-level regression test for both operations. Do not infer inheritance from a configuration comment.
  • Test the released path before training. Record root and child reward and advantage tensors after post-processing. At the inspected commit, the generator retains rewards from independent child loops while the multi-paper environment returns 0.0 for children. That combination does not demonstrate inherited credit.
  • Keep orchestration tests adversarial. Cover zero children, a single child, unequal branch counts, the depth cap, child exceptions, and output ordering from a batched call. Verify that failed children do not leave active rollout state behind.
  • Pin the implementation. The blog objective, the release commit, and the current repository can disagree. Record the exact SkyRL commit beside every training result.

How to run it in production

  • Batch the children within finite capacity. rlm_query_batched can overlap independent children, but a level wider than the serving limit requires multiple waves. Measure queueing and service time at each depth.
  • Return by reference, not by value. FINAL_VAR exists so a large answer does not have to be regenerated token by token through the parent. Use it for anything bigger than a sentence.
  • Cap depth, child count, and total calls. Node count grows exponentially in a full tree. The normalized blog objective bounds loss weight, not serving work.
  • Keep the KL term when reproducing the blog objective. The reported equation retains beta * D_KL against a reference. This does not replace hard recursion and request budgets.
  • Watch tree shape and queue pressure. Mean children per root, mean depth, service waves, rejected calls, and the fraction of roots that never recurse distinguish useful decomposition from avoidance or runaway delegation.

How to maintain it

  • Re-check reward propagation and branch normalization after every SkyRL update. The current implementation and its own configuration comment disagree. A passing root reward test does not establish the child advantage tensor.
  • Re-measure the latency claim on your own serving stack. The source reports the 7-second figure for its 4B deployment on one 8xH200 node. It does not establish a general latency ratio.
  • Re-validate against a non-recursive baseline of the same model. The interesting comparison is not against a large API model; it is against the same 4B model given the whole context directly.

Failure modes

  • Adding recursion depth as if it were a quality dial. Depth 0 (REPL, no sub-calls) beat every sub-calling variant on CodeQA with Qwen3-Coder in the originating paper. Depth helps on information-dense inputs and costs money everywhere else.
  • Applying an RLM below the crossover. The reported advantage over base GPT-5 is consistent only beyond roughly 2^14 tokens, and the crossover moves with task complexity.
  • Sizing capacity from the mean or the median alone. RLM cost is bimodal: median cheaper than the base model, mean higher because of outlier trajectories that flail through sub-calls. Cap sub-call count to bound the tail.
  • Degenerate non-recursion. The policy learns to answer directly and never spawn children, because recursion is harder and the reward does not require it. Detectable only by tracking tree shape, not by watching the loss.
  • Runaway delegation. The opposite failure: the policy spawns children that spawn children, exhausting the depth cap on every query.
  • Gradient capture by branchy rollouts. This is the specific failure the blog's 1/k factor prevents, quantified above at 2.60x over-weighting for one modelled rollout in an eight-rollout group.
  • Coarse credit under the blog objective. Good children of bad roots receive negative advantage and bad children of good roots receive positive advantage. Whether this produces high variance in the reported setup is not established.
  • Silent zero child signal in the released example. The multi-paper child reward is 0.0, while the generator says independent child rewards are retained. Without an explicit parent-advantage overwrite, included child trajectories can carry no task score.
  • Token and queue blowout at depth. Exponential node count increases aggregate calls, and finite concurrency converts wide levels into service waves.
  • Reading the headline comparison as a quality win. The reported 0.58 versus 0.607 is a small quality deficit bought back with a large latency gain, and should be quoted that way.

Open questions and validation

  • The source is a blog post reporting a single experiment: Qwen3.5-4B with SFT pretraining, 1,000 synthetically generated queries over groups of up to 10 papers, a single 8xH200 node, batch size 16, 8 samples per prompt. There are no seeds, error bars, or ablations reported, and no independent replication was located here.
  • The training rubric score is reported to improve from 0.3 to 0.6 on the training set, which is the same scale as the 0.58 evaluation figure; whether the evaluation set is disjoint in distribution is not established by the source.
  • The claim that uniform advantage inheritance is an unbiased estimator is stated by the authors and not verified here.
  • Whether the approach transfers beyond evidence selection over document groups, which is unusually decomposable, is untested.
  • SkyRL now contains an official RLM example. Its generator says children retain rewards from their independent loops, its multi-paper environment assigns child reward 0.0, and its configuration docstring says parent reward is propagated. The inspected release and current snapshots contain this inconsistency; an upstream test that proves the intended child advantage remains an open requirement.

References

  • Kim and Ahmad, "Reinforcing Recursive Language Models", alphaXiv blog, 2026-05-13: https://www.alphaxiv.org/blog/reinforcement-learning-for-rlms
  • Zhang, Kraska and Khattab, "Recursive Language Models" (the originating work, with the depth 0-3 ablation): https://arxiv.org/abs/2512.24601
  • NovaSky-AI, SkyRL RLM release commit 811f8ee9df8cae0bee16803bb4bd535f98a1cebf: https://github.com/NovaSky-AI/SkyRL/tree/811f8ee9df8cae0bee16803bb4bd535f98a1cebf
  • NovaSky-AI, SkyRL inspected snapshot b5fdfd0801014b04aa021a746a5c1c30101a1407: https://github.com/NovaSky-AI/SkyRL/tree/b5fdfd0801014b04aa021a746a5c1c30101a1407
  • NovaSky-AI, RLMGymGenerator child-output assembly at the inspected snapshot: https://github.com/NovaSky-AI/SkyRL/blob/b5fdfd0801014b04aa021a746a5c1c30101a1407/examples/train/rlm/rlm_generator.py#L144-L199
  • NovaSky-AI, multi-paper child reward at the inspected snapshot: https://github.com/NovaSky-AI/SkyRL/blob/b5fdfd0801014b04aa021a746a5c1c30101a1407/examples/train/rlm/multi_paper_env/evidence_rlm_env.py#L275-L302
  • NovaSky-AI, RLM configuration comment at the inspected snapshot: https://github.com/NovaSky-AI/SkyRL/blob/b5fdfd0801014b04aa021a746a5c1c30101a1407/examples/train/rlm/rlm_config.py#L14-L23
  • NovaSky-AI, multi-paper RLM launch template and environment tests at the inspected snapshot: https://github.com/NovaSky-AI/SkyRL/blob/b5fdfd0801014b04aa021a746a5c1c30101a1407/examples/train/rlm/run_multi_paper_rlm.sh and https://github.com/NovaSky-AI/SkyRL/blob/b5fdfd0801014b04aa021a746a5c1c30101a1407/skyrl-gym/tests/test_rlm.py
  • Shao et al., "DeepSeekMath" (the GRPO objective this extends), arXiv 2402.03300: https://arxiv.org/abs/2402.03300

Related: GRPO · GRPO variants · Agent planning and reasoning · Multi-agent collaboration · ReContext long-context reasoning · Agentic RL


  1. Zhang, Kraska and Khattab, "Recursive Language Models" (arXiv 2512.24601). Ablates max recursion depth 0 to 3, where depth 0 is the REPL with no sub-calling. Reports that the no-sub-calling depth-0 variant outperforms all sub-calling variants on CodeQA with Qwen3-Coder-480B-A35B, that higher-depth GPT-5 variants win by a large margin on the information-dense OOLONG-Pairs, that RLM(GPT-5, depth=1) consistently outperforms base GPT-5 only for context lengths beyond 2^14, that RLM(depth=1) still beats the base model within the context window on length-proportional tasks (28.4% with GPT-5 and 33.3% with Qwen3-Coder on OOLONG), and that the median RLM run is cheaper than the median base-model run while the mean is higher because of outlier trajectories. The authors caution that their runtime figures use blocking sequential LM calls. Not reproduced here.