Model or dataset
rawwerks/ypi avatar
rawwerks/ypi

ypi: a recursive coding agent that lets Pi call itself through rlm_query

A recursive coding agent inpired by RLMs

389 stars35 forksShellMIT

At a glance

What is it?
ypi is a Pi extension that registers one native tool, rlm_query, and spawns child Pi processes that can spawn children of their own. The repository documents the guardrails and the jj isolation path in more detail than it documents failure recovery.
Who is it for?
Adopt ypi if you already run Pi and want self-delegation with measurable cost control, and if you can work inside the depth, call and budget limits the README lists. Do not adopt it if you need a documented rollback path or you cannot install jj, because without jj the minimal extension defaults children to read-only tools and the writable path requires RLM_UNSAFE_NO_JJ_WRITE=1.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 85 days ago.
What is it written in?
Mainly Shell, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem ypi solves: one agent that can decompose its own work

A single coding agent working on a large repository hits two walls. The first is context: the agent can read a file, but reasoning about a whole tree means holding too much in one prompt. The second is specialization: the usual answer is to build separate planner, scout and editor roles, each with its own prompt and its own interface. ypi takes the other route. It is Pi with one extra native tool, rlm_query, and a system prompt that teaches the agent to call that tool on a smaller piece of the problem. The README states the design goal plainly: the intelligence is in decomposition, not specialization, and every depth runs the same prompt, the same tools and the same agent.

The intended user is someone already running Pi who wants recursive delegation without writing a multi-agent framework. The README is explicit that ypi is a thin layer on top of Pi and that the project tries not to break or duplicate what Pi already does. If you have never used Pi, the recursive part is not the hard part; the host runtime is.

How rlm_query spawns a child Pi process, and what stops the recursion

The mechanism is a Pi extension, extensions/recursive.ts, which registers a native tool named rlm_query. Calling that tool spawns a child Pi process configured with the same extension and the same tools. That child can call rlm_query as well, so the tree grows until the depth limit is reached. The README describes the shape as depth 0 running full Pi with the native tool and bash, depth 1 running the same, and the leaf depth running Pi with bash but no rlm_query.

The package layout backs this up. The npm package declares a pi manifest exposing only ./extensions/recursive.ts, so the extension is the whole recursion machinery. The ypi launcher, the shell-compatible rlm_query command, rlm_cost, rlm_parse_json, rlm_sessions and rlm_cleanup are convenience layers around it. The README maps the three pieces against the Python RLM it was inspired by: SYSTEM_PROMPT.md plays the role of RLM_SYSTEM_PROMPT, a $CONTEXT file plus bash plays the role of the Python context variable, and the native rlm_query tool plays the role of llm_query().

Termination is handled by what the README calls five concentric guardrails. Depth is capped by RLM_MAX_DEPTH, total calls by RLM_MAX_CALLS, wall-clock time by RLM_TIMEOUT, dollar spend by RLM_BUDGET, and PATH scrubbing prevents a child from finding the launcher in a way that escapes the tree. The system prompt adds a second, softer brake: deeper agents are told to prefer direct action over spawning more children. That is a prompt-level constraint, not an enforced one, and the README presents it as cognitive pressure rather than a hard limit.

Installing ypi and running a first recursive call

The README gives four install paths. The global installs use bun or npm, there is a curl installer, and there is a manual clone that initializes the pi-mono submodule and puts the checkout on PATH. The package requires Node 22.19.0 or newer and lists linux and darwin as its supported platforms, so Windows is not covered by the published package metadata.

bash
npm install -g ypi

After that, a one-shot run takes a prompt as an argument. The README's own example asks the agent to refactor error handling in the current repository.

bash
ypi "Refactor the error handling in this repo"

The more interesting first use is the minimal path, which skips the launcher entirely. The pi-recursive package is described as a pure Pi extension that gives Pi the native recursive tool without the ypi wrapper, the shell helper or the jj requirement.

bash
pi -e npm:pi-recursive "Use rlm_query to ask a child what 2 + 2 is."

The README says this runs Pi with the extension loaded for a single run. To make it permanent, pi install npm:pi-recursive installs it globally, and pi install -l npm:pi-recursive installs it into .pi/settings.json for the current project. Once a recursive call has run, rlm_cost reports what the tree spent.

bash
rlm_cost --json

The README shows the JSON output as an object with cost, tokens and calls fields. If that output is empty, the most likely cause is that RLM_JSON=0 is set, because the README states that JSON mode is what makes child cost measurable.

jj workspace isolation, and what happens when jj is missing

This is the part of ypi worth reading carefully before adopting it. When jj is available and RLM_JJ is not set to 0, recursive children run in jj workspaces. The parent can then absorb a child's fix with jj squash, which the README's diagram shows as the last step of the loop. That gives the recursion a real isolation boundary: a child edits its own working copy and returns a patch on stdout rather than mutating the parent's checkout.

Without jj, the README states that the minimal extension still works, but children default to read-only tools in the current checkout. Writing from a no-jj child requires setting RLM_UNSAFE_NO_JJ_WRITE=1, and the variable name is the documentation's own warning. There is no middle setting described. You either have jj, or you accept read-only children, or you turn off the safety flag deliberately.

The README does not document rollback. There is no described procedure for undoing a child's edits in a no-jj writable session, and no described way to recover a jj workspace that a child left in a bad state. rlm_cleanup exists as a binary in the package, but the README excerpt does not explain what it cleans up. Treat the isolation model as the thing to evaluate first, not the recursion itself.

Cost control is the strongest documented feature, and it has a catch

Recursion multiplies spend, so ypi's guardrails are mostly about money and time. RLM_BUDGET caps dollar spend for the entire recursive tree, RLM_TIMEOUT caps wall-clock time for the same tree, and RLM_CHILD_MODEL routes sub-calls to a cheaper model, with haiku given as the README's example value. RLM_MAX_CALLS caps the total number of rlm_query invocations. Tracing goes to the file named by PI_TRACE_FILE, which the README shows as $HOME/scratch/trace.log, and the README says the trace logs calls with timing and cost.

The catch is stated in the guardrail table. Budget enforcement in native extension mode requires JSON output so that child cost can be measured, and RLM_JSON=0 disables JSON mode, which the table describes as disabling cost tracking. So the budget guardrail and the cost-tracking guardrail share a switch. If you turn off JSON mode for readability, you lose the measurement that the budget depends on. That is a design trade-off, not a bug, but it means the cheapest-looking configuration is the one where you can least tell what you spent.

A second limit is that the guardrails bound the tree, not the individual child. A single child that reads a very large file can still consume a large share of the budget before any call limit triggers.

ypi compared with the Python RLM it was inspired by

The README names its inspiration directly: Recursive Language Models, which showed that an LLM with a code REPL and an llm_query() function can decompose problems and analyze large contexts through self-delegation. ypi is the same three-part architecture moved into Pi. The system prompt becomes SYSTEM_PROMPT.md, the Python context variable becomes a $CONTEXT file plus bash, and llm_query() becomes the native rlm_query tool with an optional shell-compatible command of the same name.

The practical difference is the host. Python RLM is a research artifact built around a Python REPL; ypi is a Pi extension, so it inherits Pi's session manager, its extension system and its provider configuration. The README states that child sessions go in the same directory as the parent's session when a parent session exists. That is the adoption argument for ypi: if your work already happens in Pi, recursion arrives as one installed extension rather than a second runtime. If your work happens in Python, the original RLM is closer to the code you already have, and ypi's bash REPL is a step sideways rather than forward.

A second difference is symbolic access. The README argues that anything the agent needs to manipulate precisely should be a file rather than tokens in context: $CONTEXT holds the data, $RLM_PROMPT_FILE holds the original prompt, and hashline provides line-addressed edits, so agents grep, sed and cat instead of copying tokens from memory.

Maintenance, release mechanics and the MIT licence

The repository is not archived, and the last push was on 2026-06-22. The most recent release listed is v0.5.1 from 2026-03-23, while package.json declares version 0.6.1, so the published package is ahead of the last tagged release. The Makefile includes targets named check-release-consistency and test-release-consistency, described as enforcing two-package lockstep and changelog invariants, which suggests the ypi package and pi-recursive are expected to move together. A contributor changing one should run those targets before publishing.

The upgrade surface is small but pinned. The runtime dependency on @earendil-works/pi-coding-agent is pinned to 0.79.4, and the repository carries a .pi-version file plus a Makefile target named check-upstream. Because ypi is a thin layer over Pi, a Pi upgrade is the main source of breakage, and the Makefile's doctor target exists to catch a wrong or stale pi before it merely seems broken. The README notes that extension tests require a real pi installed, so a full test run is not free of setup.

The licence is MIT, declared in both the LICENSE file and package.json. That permits commercial use and modification, and it also means the project ships without warranty. Nothing in the repository indicates a separate commercial licence or a contributor agreement, but this is a description of the licence field, not legal advice; if you redistribute ypi inside a product, read the LICENSE file yourself.

Editorial conclusion

Adopt ypi if you already run Pi and want self-delegation with measurable cost control, and if you can work inside the depth, call and budget limits the README lists. Do not adopt it if you need a documented rollback path or you cannot install jj, because without jj the minimal extension defaults children to read-only tools and the writable path requires RLM_UNSAFE_NO_JJ_WRITE=1. Before trusting it on a real repository, run scripts/doctor to confirm the host Pi runtime matches the pinned @earendil-works/pi-coding-agent version, then run one child call with RLM_JSON=0 and rlm_cost to see what the tree actually spends.

Frequently asked questions

Does ypi require jj to work?

No. The README states that jj workspace isolation is used when available but is not required for the minimal path, and that the minimal extension still works without jj. Without jj, recursive children default to read-only tools in the current checkout unless RLM_UNSAFE_NO_JJ_WRITE=1 is set.

How do I limit how much a ypi recursive run costs?

Set RLM_BUDGET to cap dollar spend for the entire recursive tree, RLM_MAX_CALLS to cap total rlm_query invocations, and RLM_MAX_DEPTH to cap recursion depth. The README notes that budget enforcement in native extension mode requires JSON output so child cost can be measured, and RLM_JSON=0 disables cost tracking.

What is the difference between ypi and the pi-recursive package?

pi-recursive is the pure Pi extension that provides the native recursive rlm_query tool without the ypi launcher, the shell helper or the jj requirement. The ypi binary remains available for users who want the wrapper defaults and the shell-compatible helper commands such as rlm_cost and rlm_query.

Official sources

  1. License: MIT
  2. Project website
  3. rawwerks/ypi on GitHub
  4. README
  5. Releases
Community notes

Community notes