Back to Index

How I Turned Pi into a Small Team of Specialized Coding Agents

Date:

A single coding agent with one growing context window is fine until the work stops being fine. The moment a task spans discovery, design judgment, multi-file implementation, visual polish, external docs, and a deploy checklist, one generalist starts thrashing. It rereads the same files, mixes planning with patching, and slowly loses the plot.

I use Pi as the host runtime. The interesting part is not the stock CLI. It is the personal configuration that turns Pi into a coordination layer over a small team of specialists.

This post is a draft of that system: what the roles are, how the task extension launches them, and which tradeoffs still hurt.

The bottleneck is context, not just model quality

When one agent owns everything, the context window becomes a junk drawer:

  • reconnaissance notes crowd out the current edit
  • a failed debugging branch pollutes the next implementation attempt
  • a review reads the implementer’s summary instead of the files
  • a deploy checklist gets interleaved with design debate

I did not want eight chat tabs. I wanted one lead agent that stays coordination-first, plus cheap fresh processes for work that benefits from isolation.

The lead agent still owns the user outcome. Specialists do not become a way to dodge responsibility. They become a way to protect judgment.

Coordination-first main agent

The main system prompt is explicit about the job:

  • understand the goal
  • split the work
  • write complete work orders
  • inspect evidence
  • integrate results
  • verify the combined outcome
  • answer the user

It also encodes triage:

  • Inline for one small edit or one direct answer
  • Delegate for multi-file work, broad investigation, UI direction, or review that needs fresh eyes
  • Parallelize only when ownership does not collide
  • Serialize when files or decisions depend on each other

That last part matters. Parallel agents with overlapping write rights are not speed. They are merge conflict generation with extra steps.

The lead agent is also told not to reimplement units the worktree already satisfies. Before dispatching another coder, check whether the job is already done. That sounds obvious. It saves real money once subagents become easy to spawn.

Nine roles, not one mega-prompt

Agent definitions live as Markdown files with YAML frontmatter. Each file is a specialist charter: description, model, fallback models, thinking level, tool allowlist, skill inheritance, and max turns. The body is the system prompt for that role.

The current roster:

  1. advisor: strategic planning only. Approach choices, course corrections, and high-leverage tradeoffs. Does not implement the product work.
  2. artisan: substantial UI and visual design. Tokens, hierarchy, interaction states, presentation polish. Not the default for a one-line CSS fix.
  3. librarian: remote source research. Library internals, release history, reference implementations, official docs. Read-only on the local project.
  4. machinist: the workhorse coder. Features, backend logic, refactors, migrations, bug fixes, tests. Smallest correct change, explicit file ownership.
  5. oracle: independent review and hard debugging. Second opinion on risky diffs, conflicting evidence, and high-stakes decisions.
  6. picasso: image generation specialist. Turns a visual brief into an inspected artifact, not a prose description of an image.
  7. scout: fast local reconnaissance. Broad scans, architecture maps, pattern hunting. Cheap model, low thinking, no file writes, skills off by default.
  8. scribe: editorial writing and revision. Blog posts, technical narratives, documentation, and long-form prose grounded in inspected sources.
  9. stevedore: ops and release mechanics. Lint, build, git ceremony, platform CLIs, deploy checklists. Not a place to redesign the system.

The names are a little theatrical. The separations are not. Scout exists so the lead does not burn a flagship context on rg. Oracle exists so the implementer is not also the final reviewer. Scribe exists so editorial work gets its own factual and stylistic pass. Stevedore exists so deploy muscle memory does not contaminate design judgment.

The task extension is the real product

The custom piece is a Pi extension that registers one tool: task.

On load it discovers agent definitions from the personal agents directory and, if present, a project-local .pi/agents directory. Each Markdown file is parsed into a structured agent definition. Unknown agent names fail immediately with the available roster.

When the lead calls task, the extension:

  1. resolves the agent definition
  2. validates the working directory
  3. acquires a concurrency slot
  4. spawns a fresh pi --mode json child process
  5. streams JSON events back into a compact custom TUI card
  6. returns only the child’s final report to the lead

The child does not inherit the parent conversation. That is the point. If the work order is vague, the specialist cannot “just know” what you meant five turns ago. The prompt has to carry goal, scope, context, evidence, validation, and return format.

I treat that constraint as a feature. Incomplete delegation fails loudly instead of half-working on hidden assumptions.

Self-contained work orders beat clever shared memory

A strong work order is boring and complete:

  • the user-visible outcome
  • owned files and non-goals
  • decisions already made
  • exact implementation or investigation ask
  • first files or docs to inspect
  • the narrowest useful validation command
  • the report shape the lead expects back

Writers get explicit ownership boundaries. Reviewers get explicit “do not edit” instructions when the job is pure review. If a specialist needs broader research it cannot do efficiently, it says so and asks the lead to dispatch the librarian with concrete questions.

There is no magical shared blackboard. The lead is the blackboard.

Prompt, model, thinking, tools, and turn limits are metadata

Because each agent is a file, role policy is data:

  • model sets the primary route
  • fallbackModels define the retry chain
  • thinking sets the effort profile
  • tools restrict the surface area
  • maxTurns caps wander
  • inheritSkills decides whether the child gets the skill catalog
  • the Markdown body becomes --system-prompt

The task tool also accepts per-call overrides for model, timeout, max turns, and working directory. That lets the lead keep the role defaults while still saying “use a different family for this review” or “run this scout in that package root.”

Scout stays cheap and read-only. Machinist gets the edit tools and a higher turn budget. Advisor can write plan documents but is instructed not to implement the feature. Picasso is pinned to an image workflow instead of drifting into frontend code. Those differences are enforced by metadata and prompt text, not by hoping the same general agent remembers its costume.

Fresh subprocesses, model overrides, and fallback routing

Every task is a new process. The extension launches the same Pi CLI the human uses, but in JSON mode, with no session restore, and with a system prompt taken from the specialist file.

Model handling is deliberate:

  • a fully qualified provider/model override sets both provider and model
  • a bare model id inherits the agent’s provider when possible
  • declared fallback models remain available even when the primary is overridden
  • if the primary fails, the extension walks the remaining attempts and reports which model finally worked

That fallback path is not theoretical. Provider blips and model-specific refusals happen. I would rather the task card say “succeeded on fallback after one failed attempt” than force the lead to rediscover the failure manually.

Environment markers tag the child as a subagent, including agent name and model label. Crash diagnostics use those markers later.

Concurrency cap, queueing, and no recursive worker graphs

The runner executes at most three child processes at once. Additional tasks queue. That cap is intentional. Larger fan-outs mostly add latency, cost, and contention. The lead prompt also recommends two or three parallel subagents as the practical default, with writers kept single-threaded unless file ownership is clearly disjoint.

Recursive delegation is blocked at the process boundary. Child invocations exclude the task and related wait tools, so a machinist cannot quietly become a second orchestrator. Most specialist prompts reinforce the same rule. Escalation happens by returning a blocker to the lead, not by growing a process tree.

This keeps the topology star-shaped: one coordinator, many workers, no worker-owned worker farm.

Streamed JSON events and a custom TUI

Because children run in JSON mode, the extension can render progress without dumping transcripts into the lead context.

The task card tracks:

  • agent identity and mission summary
  • queued vs running vs completed vs failed
  • current model and whether a fallback was used
  • recent tool activity
  • turn count
  • final report excerpt

The custom mono UI extension keeps the surrounding chrome compact so the terminal remains readable when several missions are in flight. I care more about knowing which specialist is stuck in a long test than about watching every token land.

Only the final report returns to the lead agent. That is the main context-preservation trick. The lead sees outcomes, evidence summaries, and blockers. It does not inherit every dead-end file read the scout needed to get there.

Crash diagnostics without turning the terminal into a black box

A separate crash-logger extension appends process diagnostics to a local log file. It records uncaught errors, rejected promises, stream failures, session shutdowns, and even clean exits because a graceful terminal disappearance can still be the clue. Each entry identifies whether the process was the main Pi session or a subagent, plus agent name, model label, pid, cwd, and stack text when available.

That sounds unglamorous. It is the difference between “the terminal just vanished” and “the stevedore child died during a deploy command with a concrete stack.” The logger is intentionally best-effort and must never create a second fatal error while handling the first.

Prompt templates for the jobs I keep repeating

Not everything needs a subagent. Some workflows are repeated operator moves, so they live as prompt templates:

  • browser attaches to a dedicated authenticated debug Chrome instead of fighting daily-profile permission prompts
  • brainstorm forces divergent option generation and forbids implementation until I converge
  • deploy gathers worktree facts, then forces the lead to hand release mechanics to stevedore instead of freelancing a deploy mid-conversation

Templates are for mode shifts. Agents are for role shifts. The distinction keeps the system smaller than it looks.

Review loop and model diversity

The system treats review as part of the work, not optional polish.

  • tiny inline edits can be self-reviewed by the lead
  • delegated multi-file or risky work should get a fresh reviewer or oracle pass
  • reviewers inspect files and diffs, not the implementer’s summary alone
  • after fixes, validation runs again before the lead claims done

Model diversity is part of that loop. Advisor and oracle are most valuable when they are not a clone of the lead’s blind spots. The lead is instructed to override to a strong model from a different family when the specialist default would otherwise correlate too hard with the parent. Same-family second opinions are comfort, not review.

I still reconcile those opinions myself. A reviewer can be wrong, speculative, or out of scope. Fresh eyes are an input, not an autopilot.

Secrets stay out of the story and out of git

The configuration repository is meant to be restorable on a new machine, but secret-bearing provider, MCP, and auth files are intentionally excluded from source control. Restore means reinstalling dependencies, recreating ignored local credential files, and signing back into OAuth-backed providers. I am not going to name those values or paste example secrets here.

That split is part of the workflow design. The agent roster and prompts are portable knowledge. The credentials are local state.

Tradeoffs that are still real

This setup is powerful. It is also easy to romanticize.

Latency. Fresh processes and queueing add wall-clock time. For a one-line fix, the multi-agent path is pure overhead. The lead has to keep using inline work.

Cost. Specialists multiply spend, especially when advisor, machinist, and oracle all touch the same feature. The concurrency cap and cheap scout defaults help, but they do not make fan-out free.

Prompt quality. Bad work orders produce confident garbage in a clean context window. Isolation removes hidden conversation state. It does not invent missing requirements.

Context isolation cuts both ways. Workers cannot see the parent thread, so the lead must spend tokens writing better briefs. That is good discipline and also more work up front.

Limited automated tests. The extensions are real TypeScript with real process control, TUI rendering, and fallback logic. Automated coverage is still thinner than I want for something this close to my daily driver. A lot of confidence still comes from use, crash logs, and typechecking rather than a rich end-to-end suite.

Operational sharpness. Stevedore can move fast with platform CLIs. That is useful only if the lead keeps shared-state actions under explicit control. Shipping remains a human-visible decision.

What I would keep if I rewrote it tomorrow

If I threw away the names and the chrome, I would keep these rules:

  1. One coordinator owns integration and the final answer.
  2. Specialists get fresh context and explicit metadata, not vibes.
  3. Writers never share file ownership in parallel.
  4. Children cannot spawn children.
  5. Review is a different process from implementation.
  6. Secrets stay local, prompts stay portable.

Pi is the host. The custom configuration is the team shape. Once those rules are in place, the rest is tuning: which model is cheap enough for scout, how hard oracle should think, when artisan is worth the handoff, and when the lead should just edit the file itself.

I still do the last one more often than the architecture diagram would suggest. That is healthy. A team of agents is a tool for expensive work, not a costume for every keystroke.

Related Posts