# ypi is Pi plus one native tool that spawns a child Pi

> A recursive coding agent built as a Pi extension, named after the fixed-point combinator. Recursion is a child process rather than a role hierarchy, and five guardrails bound the tree. Two packages ship from one repository, and most of the tests make no model calls at all.

**rawwerks/ypi** — A recursive coding agent inpired by RLMs

- Repository: https://github.com/rawwerks/ypi
- Website: https://ypi.sh
- Stars: 391 · Forks: 36
- Language: Shell
- License: MIT
- Published: 2026-09-15 · Updated: 2026-09-15 · Language: en
- Canonical page: https://hysenlabs.com/projects/rawwerks-ypi

## The minimal path is one extension registering one tool

Pi already has an extension system and a shell, so ypi adds almost nothing to it structurally.

The whole mechanism is a single extension file that registers one native tool, rlm_query, and teaches the agent to use it. Calling that tool spawns a child process running Pi with the same extension and the same tools, and that child can call the tool in turn.

```bash
# Try for one run
pi -e npm:pi-recursive "Use rlm_query to ask a child what 2 + 2 is."

# Install globally for normal pi sessions
pi install npm:pi-recursive

# Install project-locally into .pi/settings.json
pi install -l npm:pi-recursive
```

Everything else is packaging. The launcher and a shell-compatible helper command exist so the recursion works from a pipeline rather than only from a tool call, and a second npm package carries the extension alone for people who do not want those defaults.

The design is credited to a body of work on recursive language models, where the finding was that a model given a code environment and a way to call itself can break a large problem into pieces and delegate them. The name comes from lambda calculus: a fixed-point combinator, and Pi that can call itself.

## Depth 2 keeps the shell and loses the recursive tool

The recursion is bounded by construction, and the description is explicit about what each level has.

At depth zero, the root process has the full toolset: the recursive query tool plus the shell. At depth one, the child has exactly the same thing, which is what makes it able to delegate further. At depth two, the process is a leaf: it keeps the shell but no longer has the recursive tool.

The default depth limit is three, configurable through an environment variable.

The important consequence is that there is no role hierarchy. Every level runs the same prompt with the same tools, so nothing in the design reserves searching, planning or reviewing for a particular level. What changes with depth is the instruction to be more conservative rather than spawn more children, which is a prompt-level pressure rather than a capability restriction.

That is the unusual bet in the design: the reasoning about how to decompose a problem is left to the model at every level, and the framework's job is only to make recursion available and make it stop.

## Five guardrails bound the tree, and one of them needs JSON mode

Termination is guaranteed by a set of limits, all set through environment variables, and they cover both time and money.

A budget caps total spend across the entire recursive tree, shown at fifty cents by default. A timeout caps wall-clock time for the same tree at sixty seconds. A call limit caps the total number of recursive invocations at twenty. A depth limit caps recursion at three. And a child model variable routes sub-calls to a cheaper model.

The budget row carries a caveat that is easy to miss: in native extension mode, measuring child cost requires the tool to return JSON. Turn JSON mode off and there is no cost tracking, which means the budget you set may not be enforceable in the way you expect.

The agent can report its own spend while running. A helper command prints a formatted total, and a JSON form of the same command returns cost, token count and call count together.

Separately from the budget, tracing writes every call with its timing and cost to a log file whose path is set through the host's own trace variable.

## Without a version control tool the children become read-only

File isolation is where the dependency on another tool shows up.

When a version control system for concurrent work is present and not disabled, each recursive child gets its own workspace, so several agents editing at once do not collide. That is the intended arrangement.

Without it, the extension still works, but children fall back to read-only tools in the current checkout. That is a deliberate restriction rather than a failure mode: if several children can write to one directory with no isolation between them, the result is not parallelism but interference.

There is an escape hatch, and its name is the point. The variable that makes children writable without isolation carries an unsafe marker in its name and is documented as something to set only when you deliberately want writable children in that situation.

The same variable-based approach is used everywhere else in the system: disabling workspace isolation, disabling JSON output, disabling extension loading at the root or only at child depths, and clearing shared session state. Each is a separate switch rather than a mode, which makes the combinations possible but also makes the surface larger than a single flag would be.

## The prompt teaches one pattern instead of a team of roles

The reasoning behind the design is laid out as properties, and the first one is the load-bearing choice.

Self-similarity means every depth runs the same prompt, the same tools and the same agent. There are no scout roles and no planner roles, and the text is explicit that the intelligence is supposed to come from decomposition rather than from specialisation. The system prompt teaches a single pattern, which runs size first, then search, then chunk, then delegate, then combine.

That pattern is claimed to work at every scale, which is the part to test rather than accept. A five-file repository and a five-thousand-file repository are given the same instructions, so nothing in the design tells the agent that chunking is unnecessary at the small end.

The second property is self-hosting. When the shell helper is loaded, the prompt includes the helper's own source, so the agent can read and modify the machinery it is running on. A bare extension install does not include that file and does not need it.

The result is a system where the prompt is the product and the code is small. That has a practical consequence: changing behaviour means editing prose, not code.

## Context lives in files, and edits are line-addressed

The fourth design property is the one that shapes day-to-day use.

Anything the agent needs to handle precisely is a file rather than tokens sitting in context. The working context is held in a file, the original prompt is held in another, and a line-addressing mechanism provides edits by line rather than by rewriting a block of text.

The stated consequence is behavioural: the agent greps, reads ranges and prints lines instead of copying text out of memory into a new file. That is both cheaper and less lossy, and it is the same instinct as the guardrails, since everything that could be re-derived from the working tree instead of the context window is.

The project map follows the same logic. The system prompt is a file at the repository root rather than a string in the extension, which is what makes the edit-prose claim practical. A file describes what a child process receives, and there is a sibling file describing the child context.

It also means the recursion is inspectable after the fact. Whatever a child did leaves a trace in files rather than only in a transcript.

## Two packages ship from one repository, and the tests avoid models

The build file is the clearest evidence of how the project is run.

There are separate suites for the unit tests, the guardrail behaviour, the native tool, and a provider allowlist that exists to enforce parity between the native and shell paths. Every one of those is labelled as making no model calls, and the fast target is simply the six of them chained together.

Only the extension compatibility suite is marked as requiring a real host installation, and the end-to-end targets sit apart from the fast set.

Two release-related scripts are also in the fast set: one checks that the two published packages stay in lockstep and that the changelog matches, and one tests the checker. A doctor script reports whether the host runtime is healthy, described as catching a wrong or stale installation before it looks like a bug elsewhere.

The manifest explains the two packages. One exposes the extension entry point and installs six commands; the other is the same extension without the wrapper. It pins the host agent package to an exact version rather than a range, declares Linux and macOS only, and requires a recent Node.

The last commit on the default branch, named master, is dated 2026-06-22.

## Conclusion

This fits someone who wants a second pass over a large codebase without designing an agent hierarchy, since the same prompt and toolset run at every depth and the hard part, decomposition, is delegated to the model. It does not fit Windows, which the published package does not declare, or anyone who wants children editing files without a version control tool present, since they default to read-only in that case. Two things to set before the first run. The depth limit is the control that decides whether you get a second opinion or a fan-out, and the budget needs JSON mode enabled or child cost cannot be measured, so a run without it can exceed the figure you thought you set.

## FAQ

### What does ypi add to Pi?

One native tool called rlm_query, registered by an extension, which spawns a child Pi process carrying the same prompt and tools. The launcher binary and the shell helper command are convenience layers over that single tool.

### How deep does ypi recurse?

To a configurable maximum, three by default. The root and the first child both keep the recursive tool, and the leaf depth keeps the shell but loses the recursive tool, which is what stops the tree.

### How do I cap what a ypi run costs?

A budget variable caps total spend across the whole recursive tree, shown at fifty cents by default, with a wall-clock timeout and a maximum call count bounding the same tree. Child calls can be routed to a cheaper model. Cost measurement requires JSON mode to stay enabled.

### Do I need a version control tool installed to use ypi?

No. With one available and not disabled, each child gets its own isolated workspace. Without it, children fall back to read-only tools in the current checkout, and a separately named override variable makes them writable.

### How is ypi installed?

Globally with bun or npm, without installing through bunx, by piping a shell script, or from a clone with submodules initialised. A second package installs as a pure extension for one run, globally, or into a project's settings file.

### Which platforms and runtimes does ypi support?

The published package declares Linux and macOS, with no Windows entry, and requires Node 22.19 or newer. It pins the host coding agent package to an exact version.

## Sources

- [License: MIT](https://github.com/rawwerks/ypi/blob/master/LICENSE)
- [Project website](https://ypi.sh)
- [rawwerks/ypi on GitHub](https://github.com/rawwerks/ypi)
- [README](https://github.com/rawwerks/ypi/blob/master/README.md)
- [Releases](https://github.com/rawwerks/ypi/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/rawwerks-ypi
