Quickstart

Install

npm install @ai-for-dev/combo       # the library
pi install npm:@ai-for-dev/combo    # the same package, loaded into pi

Node 23.6 or later is required: it runs TypeScript natively, and there is no build step. The package ships the TypeScript it was written in, and tsc is used only to typecheck.

From a clone, the same three commands the CI runs:

npm install
npm test          # offline, no network calls
npm run typecheck

A model is needed for anything that actually talks to a provider. pi resolves it the usual way, and the examples take --model on the command line:

node examples/01-run.ts --model local/qwen/qwen3-coder-next

Not every provider reports tokens. When one does not, the usage lines read 0, and that is deliberate: nothing here is estimated by counting characters. See Measurements.

One subagent, one task

The high level form is disposable: it spawns, asks, and closes.

import { findAgent, loadAgents, run } from "@ai-for-dev/combo";

const agents = loadAgents();
const scout = findAgent(agents, "scout");

const result = await run(scout, "Find the authentication code");
console.log(result.output);
console.log(result.usage.turns, result.usage.input, result.usage.cost);

run never throws on a model failure. It returns a Result with ok: false and an error, and the usage it managed to spend is still filled in.

A subagent that remembers

The low level form gives you the object, and you decide how long it lives.

import { spawn } from "@ai-for-dev/combo";

const coder = await spawn(coderAgent, { lifetime: "workflow" });
try {
	await coder.ask("Implement the parser");
	await coder.ask("Apply these remarks: …");   // it remembers the previous turn
	console.log(coder.usage);                     // cumulative since spawn
} finally {
	await coder.close();
}

Whoever opens, closes. The finally is not decoration: an undisposed session leaks, and closing is also what triggers an export when one was asked for.

Read Lifetime before choosing anything other than the default.

A workflow

Combinators take agents and give back results. They compose because they all speak the same Result.

import { chain, fanOut, loop, saysWord } from "@ai-for-dev/combo";

await chain({ steps: [scout, reviewer], input: "Explain how usage is measured" });

await fanOut({ agent: scout, tasks: ["find A", "find B", "find C"], concurrency: 2 });

await loop({
	steps: [coder, reviewer],
	input: "Implement the parser",
	until: (step) => saysWord(step.output, "LGTM"),
	lifetime: "workflow",
});

Set a deadline on anything unattended. There is no default one, and pi’s agent loop has no step cap:

await fanOut({ agent: scout, tasks, timeoutMs: 60_000 });   // per branch, not total

Workflows covers every combinator.

From pi

pi -e extension          # this session only
pi install ./extension   # permanently, via settings

Then, in the TUI:

> /run build add a slugify helper with tests
> use subagent with scope "project" and agent "scout" to find the auth code

The demo agents of this repository live in .pi/agents/, which is repository-controlled content and therefore never loaded by default - hence the explicit scope. See Agents and Extension.

Next