# pi-loops

A reusable [Pi](https://pi.dev) extension that adds a **supervised loop harness** around the Pi coding agent.

The agent still works as normal — it thinks, investigates, edits files, runs tools, and writes code. The loop extension owns the **workflow around the agent**: state, node order, tool scope, steering, evidence, validation, approvals, and completion.

**This extension ships with no pre-built loops.** It gives you the runtime and tooling to build your own workflows. Add your loops in `src/loops/` and the agent will help you design them.

## Features

- **Generic loop runtime** — sequence typed nodes (code, LLM, gate, approval, finalizer)
- **Bounded LLM nodes** — each node has scoped tools, timeout, model assignment, and steering rules
- **Deterministic gates** — validate artifacts and evidence without LLM cost
- **Evidence collection** — every tool call, command, and file change tracked automatically
- **Steering** — the loop detects stalls, over-research, repeated failures and nudges the agent
- **Context cleaning** — sanitize tool-call noise between nodes via code handlers
- **Session persistence** — loop state survives Pi session restarts
- **Per‑node model routing** — assign different models and thinking levels to different nodes
- **`loop_report` tool** — structured agent-to-loop handoff

## Installation

```bash
# Install for all projects
pi install npm:@asm3r96/pi-loops

# Or install from git
pi install git:github.com/Asm3r96/pi-loops

# Or load directly
pi -e ./src/index.ts
```

After install, the extension auto-loads on Pi startup. The agent will also discover the bundled `pi-loops` skill from `skills/pi-loops/`, so it can guide users through designing and creating their own loops.

## Quick start — build your first loop

After installing, ask the agent:

```text
Help me build a loop that does X.
```

The agent will read the bundled skill and walk you through creating:

1. A loop definition in `src/loops/my-loop/definition.ts`
2. Optional code handlers in `src/loops/my-loop/handlers.ts`
3. Registration in `src/loops/index.ts`
4. Reload and run

The skill also includes a plain-text design reference at `skills/pi-loops/references/github-issue.md`. This is not runnable loop code; it is a walkthrough the agent can read to understand how a real multi-node loop can be structured.


## Available commands

| Command | Description |
|---------|-------------|
| `/loop start <definition> [input...]` | Start a new loop |
| `/loop status` | Show current run state |
| `/loop list` | List available loop definitions |
| `/loop cancel` | Cancel active run |
| `/loop pause` | Pause active run |
| `/loop resume` | Resume paused/idle loop |

## Architecture

```text
src/
├── index.ts              Extension entry: commands, events, tool registration
├── types.ts              Loop/workflow type definitions
├── runtime.ts            Generic loop runtime engine
├── nodes.ts              Code handler registry + gate/LLM execution
├── state.ts              Session persistence (save/restore via Pi session entries)
├── evidence.ts           Tool observation + steering triggers
├── tools.ts              loop_report custom tool
└── loops/
    └── index.ts          Add your loops here
```

## Key node types

| Type | Description |
|------|-------------|
| `code` | Deterministic logic (fetch, transform, validate, side-effect) |
| `llm` | Agent works inside bounded scope, reports via `loop_report` |
| `gate` | Validates artifacts and evidence deterministically |
| `approval` | Pauses for user decision |
| `finalizer` | Writes final result |

## The `loop_report` tool

LLM nodes signal completion by calling `loop_report`. The report includes a summary, artifacts, changed files, and confidence. It is a **proposal** — the next gate decides whether to pass, request a retry, or fail.

## Adding a new loop

1. `src/loops/my-loop/definition.ts` — export a `LoopDefinition`
2. `src/loops/my-loop/handlers.ts` — write code handlers and register them
3. `src/loops/index.ts` — import and register

```typescript
// loops/index.ts
import { createMyLoopDefinition } from "./my-loop/definition.ts";
import { registerMyLoopHandlers } from "./my-loop/handlers.ts";

export function registerLoopPackages(registerDefinition) {
  registerDefinition(createMyLoopDefinition());
  registerMyLoopHandlers();
}
```

Reload Pi and run:

```text
/reload
/loop start my-loop input=value
```


## License

MIT

Built with [Pi](https://pi.dev).
