TreeFlex: Policy-Directed Navigation of Resumable Search Trees
Long agent runs can trap work in one growing context; TreeFlex saves resumable paths as a tree and lets a model choose where to continue, branch, backtrack, or seek approval.
Read the paper ↗What it is
- Resumable search tree Each completed stretch of work becomes a saved point with a summary and enough task state to continue from it. Returning to an earlier point can start a separate line of work.
- Two views of the same model One role compares summaries across the whole tree and chooses what to do next. The other resumes one chosen path, does the task work, and can submit a proposed solution for review.
- Policy-directed navigation The model—not a fixed search rule—decides whether to continue from the latest work, revisit an earlier point, start another branch, or accept a proposal.
Why it matters
Long-running agents need a way to preserve useful work without forcing every future step to carry every past detail. TreeFlex makes alternatives resumable and gives the model control over where effort goes, while keeping state restoration and proposal approval explicit.
Before getting into the machinery, here’s the short version: TreeFlex lets an agent save completed stretches of work and return to any saved point later. A model chooses where to resume and what to do there; a harness restores the relevant context and task state. That matters when a single line of reasoning gets stuck: you can try another branch without pretending the earlier work never happened.
-
Long tasks outgrow one history: In a flat ReAct-style run, the whole interaction keeps accumulating in one context. That is simple, but every new step inherits the same history, including dead ends. TreeFlex saves segments as tree nodes so that a later decision can start from an earlier point instead.
-
A summary is useful for choosing, not for doing: Imagine researching a question and saving a notebook card after each stretch: what you checked, what you found, and what remains uncertain. You can scan those cards to pick the next lead, but you may need the full notes to defend a conclusion. That’s the split here: Reflection sees a global record of cards and links; Execution gets the detailed context and environment for one selected path. The notebook analogy breaks if the card leaves out a crucial caveat—that can send the next choice in the wrong direction.
So what does it mean to save a node? It is a checkpoint for a whole segment, not every individual turn. Each saved point remembers where the segment started, a short card, its resumable context, and the task environment—for code work, that includes the repository state. In plain terms, the card is the index; context and environment are the working materials you need to continue. A checkpoint records progress, while a commit records a proposed answer or code change for review.
- Different views create different jobs: Reflection sees the tree-wide cards and chooses a node plus an instruction. Execution resumes the chosen node’s path and uses the ordinary task tools. For a concrete example, suppose a code agent has one branch investigating a failing test and another trying a fix. Reflection can compare their reports, but Execution resumes just one branch with its code and error details. This keeps branch choice global and task work path-specific; it also means Reflection cannot repair a proposal from raw evidence it never saw.
What can the model do with that choice? It can keep going from the newest saved point, revisit an older point and explore a sibling, or return to the root for a fresh line. Those are familiar depth-first, breadth-first, and best-first patterns, but no fixed traversal rule decides among them. If Execution proposes a solution, Reflection can accept it unchanged or keep navigating while the proposal remains available. I like that the harness does not secretly choose the search strategy; the tradeoff is that the model has to make that decision well. So when should it stop exploring and approve a proposal? That depends on its evidence across the cards and the paths it can resume.
Read the deep dive
Why People Wanted It
An agent working on a long task accumulates context, and one unproductive line of work can consume that context without leaving a useful way back. A flat history makes every next step inherit the same past; folding history can compress it, but compression risks losing details needed to resume. So the real question was not simply how to fit more turns into a prompt. It was how to preserve alternative lines of work and let the agent decide which one deserves attention next.
The Core Move
TreeFlex saves each completed segment as a resumable node, then lets the model choose a node and instruction for the next segment. A node is a parent-linked record : its parent, a summary card, model context, and environment state. The model navigates; the harness saves and restores.
Why the Tree Stores Segments, Not Turns
Now the version for readers who want more of the machinery: a node represents an entire Execution segment, not an individual model turn. The root stores the task and initial environment; each later node is created when a segment checkpoints or proposes a solution. The node’s parent records where that segment began, so selecting an older node can create a sibling branch rather than overwrite later work.
The saved state has distinct jobs. The card is the compact account Reflection can use to compare branches. The context state supplies the resumable conversation, and restores the task environment—for example, a repository snapshot. These are not interchangeable: a card helps choose a path, while the context and environment let Execution actually continue it.
Why Reflection and Execution See Different Things
Here is the part that gets technical: the two roles are the same model operating over different views and tool permissions. Reflection sees the task and a global record of node identifiers, parents, and cards, but not the raw context of each segment. Execution sees only the restored path to its selected node, that node’s environment, and its instruction. It uses domain tools and ends by checkpointing or committing a proposal.
This separation makes the choice of role consequential. Reflection can compare branch summaries and decide what to do next, but it cannot edit a proposal using evidence it cannot see. Execution has path-specific evidence and can do the work, but it cannot directly inspect competing branches. In deep research the path context uses cards; in SWE it uses raw context because diffs and error traces are harder to summarize faithfully.
Why Navigation Is the Search Policy
Now the deeper control-flow detail: Reflection’s action is either —resume node with instruction —or, when a proposal is available, approve it. Navigation creates no node by itself. The next Execution segment creates a child of the chosen node when it checkpoints or commits; thus resuming the latest node deepens a line, while resuming an earlier one opens a sibling branch.
This lets one policy enact depth-first, breadth-first, or best-first behavior without the harness imposing a traversal rule. A proposal is saved as a node and remains available if Reflection chooses to keep searching; approval accepts that proposal unchanged and ends the search. The harness validates actions and restores state, but does not choose the next branch.
Minimal Causal Code
This plain loop makes the state transition visible: Reflection chooses a saved node; Execution works from that node’s path and environment; a checkpoint or proposal becomes a child. It omits prompts, tool validation, and context limits.
# nodes store parent, card, context, and environment
nodes = {"root": root_state}
pending_proposals = {}
while not limit_reached():
record = global_cards_and_parents(nodes)
action = reflect(task, record, pending_proposals)
if action.kind == "approve":
return pending_proposals[action.node]
parent = action.node
context, environment = restore_path(nodes, parent)
result = execute(context, environment, action.instruction)
if result.kind in ("checkpoint", "commit"):
child = save_child(
parent=parent,
card=result.card,
context=result.context,
environment=result.environment,
)
nodes[child.id] = child
if result.kind == "commit":
pending_proposals[child.id] = result.solution
What You Gain, and What You Lose
The tree gives an agent somewhere to return to when a line of work stalls, and lets it compare compact records before spending more work on a branch. Path-specific restoration also avoids handing every segment the raw history of every alternative. But the design depends on useful cards and accurate saved context and environment; a misleading summary can steer Reflection badly, while a restored path does not magically provide evidence from sibling branches. Search is sequential, and a model must spend decisions on navigation and review as well as task work.
For deep research, TreeFlex’s reported comparisons include higher accuracy than flat ReAct and FoldAgent under the stated setup; on SWE, the reported system comparison also favors TreeFlex over FoldAgent. Those outcomes do not make the tree a free speedup: it trades a single growing history for state management, branch selection, and proposal review. The separate training treatment for complete searches is covered in the companion module.
TreeFlex turns saved paths into choices: the model decides where to resume, while the harness only restores and records state.