Skip to content
Back to skills

Subagent Orchestration

ASecurity

Subagent personas + orchestration patterns (port of pi-subagents by @nicopreme). Delegate with the right persona, fan out/sequence with the agent tool, isolate writers with fractal worktrees. Includes code mode: scripted orchestration in plain JS that loops, fans out, awaits, branches on real child output, mixes parallel/sequential phases, and isolates each child in its own git worktree - for native agents (nur run) and OMP.

  • 3 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 2, 2026
ai-agentsjavascriptjavashellnodeexpressgitbackend

Works with

  • cli

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned September 2, 2026

npx -y skills add nuroctane/nur-cli --skill subagent-orchestration --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Subagent Orchestration?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Subagent Orchestration
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/nuroctane-subagent-orchestration/badge)](https://www.skillsdirectory.com/skills/nuroctane-subagent-orchestration)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: subagent-orchestration
description: Subagent personas + orchestration patterns (port of pi-subagents by @nicopreme). Delegate with the right persona, fan out/sequence with the agent tool, isolate writers with fractal worktrees. Includes code mode: scripted orchestration in plain JS that loops, fans out, awaits, branches on real child output, mixes parallel/sequential phases, and isolates each child in its own git worktree - for native agents (nur run) and OMP.
disable-model-invocation: false
---

# Subagent delivery & orchestration (pi-subagents port)

Use the right persona, compose work with the `agent` tool, and isolate writers so
children can't clobber each other. This is the nur port of `pi-subagents`
(orchestration vocabulary + worktree isolation), keeping nur's native `agent`
tool and async admissions instead of a JS runtime.

## Personas (route by need, not by habit)

| Persona | Use it when you want... | Knowing on the child |
|---------|-------------------------|----------------------|
| `scout` | Fast recon: relevant files, entry points, data flow, risks | read-only explore before you understand the code |
| `researcher` | Web/docs research, sources, a concise brief | web_fetch/search, leave it to facts |
| `worker` | Implementation that edits files, validates, escalates instead of guessing | the file-authoring tools; verify before claiming |
| `reviewer` | Code review + small fixes against plan/tests/edge cases/simplicity | a fresh read-only pass |
| `oracle` | A second opinion before acting; challenge assumptions without editing | read-only, no edits |
| `delegate` | A lightweight general child close to the parent session | same surface as parent |

## Recommended loops

- Implementation: **clarify -> scout -> worker -> fresh reviewers -> worker**
- Second opinion: **ask oracle to challenge assumptions before we edit**
- Hard bug: **oracle to investigate before we change anything**
- Review a diff: **reviewer**
- Parallel review: **fan out reviewer for correctness, tests, cleanup**

## Fan out in one batch (parallel)

Issue several `agent` calls in one response — they run concurrently (nur fans
them out). Each is an independent child:

```
agent(description="review correctness", subagent_type="explore", prompt="...")
agent(description="review tests", subagent_type="explore", prompt="...")
```

## Sequence phases (await before branching)

When one child's output feeds the next, run them sequentially — wait for the
result, then act on it:

1. `agent scout` -> read results
2. `agent worker` with the scout findings
3. `agent reviewer` fresh, with the diff

Branch on real child output — pass `scan.output` into the next task string.

## Background / async (nur admissions)

For work that should keep running while you continue, use `agent async=true`
(returns a handle immediately; collect later via `admission get`). Prefer this for
long reviewers or implementations you can proceed in parallel with.

## Worktree isolation for parallel writers (fractal)

When two children both **write**, give each its own worktree so they don't
clobber each other. Nur uses fractal worktrees. Pass cwd/fractal on the child, or
run writers in separate fractal nodes, then merge. Keep ONE writer per location
unless writers are deliberately isolated.

## Child safety (boundaries)

- Children don't re-spawn agents (depth limit). If a child must delegate, it can
  only do so when explicitly allowed; otherwise it completes directly.
- Children get a focused tool surface — they don't inherit the parent's full
  orchestrator role.
- Never let a child guess an unapproved decision; it escalates instead.

## Code mode: scripted orchestration (plain JS)

pi-subagents' "code mode" lets you orchestrate subagents from a plain
JavaScript script: loop, fan out, await, branch on real child output, mix
parallel and sequential phases, and isolate each child in its own git worktree
- all in one file. In nur this runs *outside* the model loop (a bun/node
script), but it drives the SAME two delegation backends the model would use:

- **NATIVE** - every delegation is a headless `nur run` (one agent turn,
  prints the final answer). Parallel = `Promise.all` over child processes.
- **OMP** - every delegation is an `omp` tool run (Oh My Pi, LSP-wired).
  Call the `omp` CLI directly the way `src/tools/omp.rs` does, or shell out to
  the nur `omp` tool via `nur` itself. Results come back as JSON events you can
  branch on.

Why script instead of a batched tool block? The script gives real control flow:
`for`/`while` loops over children, `if` on their actual text output, mixing
`await` (sequential phases) with `Promise.all` (parallel fan-out), and a
`worktree` per child so concurrent writers never clobber each other - none of
which is expressible as a single static tool call.

### The reusable template

A working, copy-and-fill-in template ships with this skill at:

```
skills/subagent-orchestration/code-mode/orchestrate.mjs
```

Copy it next to your task, edit the `tasks` array and the `dispatch` function,
then `bun orchestrate.mjs` (or `node orchestrate.mjs`). It already implements:
parallel fan-out, sequential phases, branching on real child text output,
per-child git worktrees, and a combined report. See its header comment and the
README in the same folder.

### Core pattern (native - nur run)

```js
import { execFile } from "node:child_process";
import { promisify } from "node:util";
const run = promisify(execFile);

// dispatch ONE child -> one headless native agent turn
async function dispatch({ name, prompt, cwd }) {
  const { stdout } = await run(
    "nur", ["run", "-y", prompt],
    { cwd, maxBuffer: 10 * 1024 * 1024 },        // big enough for long reports
  );
  return { name, ok: true, text: stdout };
}

// PHASE 1: parallel fan-out (independent writers, each in its own worktree)
const tasks = [ /* fill in: {name, prompt, cwd} */ ];
const parallel = await Promise.all(tasks.map(dispatch));

// PHASE 2: branch on REAL child output, then a sequential dependent phase
const winner = parallel.find((r) => /SUCCESS|DONE/i.test(r.text));
const dependent = winner
  ? await dispatch({ name: "integrate", prompt: `Use ${winner.name}'s result: ${winner.text.slice(0, 2000)}`, cwd: "./" })
  : await dispatch({ name: "fallback", prompt: "Nothing succeeded; reassess and produce a plan." });
```

### Same pattern for OMP (parallel + collect + branch)

OMP returns JSON events (see `src/tools/omp.rs`). The `omp` CLI flags mirror
what the tool builds:

```js
// dispatch ONE child -> one OMP one-shot run (JSON events on stdout)
async function dispatchOmp({ name, prompt }) {
  const args = [
    "--mode", "json", "--no-session", "--no-title",
    "--no-extensions", "--no-skills", "--no-rules",
    "--max-time", "300", "--approval-mode", "yolo",
    "--thinking", "low", "-p", prompt,
  ];
  const { stdout } = await run("omp", args, { maxBuffer: 10 * 1024 * 1024 });
  // pick the final assistant text out of the newline-delimited JSON events
  let output = "";
  for (const line of stdout.split("\n")) {
    try {
      const ev = JSON.parse(line);
      if (ev?.type === "message_end") {
        output = ev.message?.content?.map?.((c) => c.text ?? "").join("") ?? output;
      }
    } catch { /* not JSON - skip */ }
  }
  return { name, ok: !!output, text: output };
}

const results = await Promise.all(tasks.map(dispatchOmp));  // parallel fan-out
const failed = results.filter((r) => !r.ok);
// ... branch on failed.length, re-route, sequence dependent phases
```

> Prefer the nur `omp` **tool** (approval-gated, budget-tracked, cancellation
> aware) when you are already inside a nur session. Call the `omp` CLI directly
> only when the script is fully standalone. OMP writes to the workspace, so use
> a worktree per writer and `--approval-mode yolo` only in a disposable
> environment.

### Worktree isolation per child

Give each *writing* child its own git worktree so parallel writers never
clobber one branch:

```js
import { execFileSync } from "node:child_process";
function worktree(name) {
  const slug = name.toLowerCase().replace(/[^a-z0-9._-]+/g, "-");
  if (!slug) throw new Error("safe worktree name required");
  const dir = `.wt-${slug}`;
  const branch = `wip/${slug}`;
  execFileSync("git", ["worktree", "add", "-b", branch, dir], { stdio: "inherit" });
  return { dir, branch }; // pass dir as cwd; hand branch to the integrator
}
// Preserve writer worktrees until their commits/changes are verified integrated.
// Never auto-remove --force: that can discard uncommitted child work.
```

This mirrors nur/fractal's worktree isolation (`.worktrees`) without needing a
fractal coordinator: keep ONE writer per worktree, then merge or cherry-pick
the branches you accept. The template wires this in with an `isolate: true`
per task.

### Checklist when a model writes code-mode

1. Choose backend per task: native `nur run` (fast, inherits your provider) vs
   `omp` (LSP-wired edits, explicit model) vs mixed.
2. Fan out independent tasks with `Promise.all`; keep dependent phases in
   `await` sequence.
3. Branch on the *actual child text* (`r.text`), never on a guess.
4. Give every concurrent writer its own worktree, pass its branch/path to the
   integration phase, and preserve it until integration is verified.
5. Cap `maxBuffer` and `--max-time`; collect all results, don't fail fast on
   the first error unless you mean to.
6. Report per child: name, ok, files changed, checks run - then a combined
   summary.

## Source

Ported from `pi-subagents` (nicobailon) — the persona table, recommended loops,
parallel/sequence pattern, worktree isolation, and the child-boundary rules.
Keep nur's native `agent`/`admission`/`fractal` as the runtime.

Files in this skill

  • SKILL.md9.5 KB
  • code-mode/README.md2.3 KB
  • code-mode/orchestrate.mjs7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…