Skills vs. Subagents

You're right that it's "just swap one prompt for another." So what actually changes when people say multi-agent? One thing — and it isn't the prompt. Grounded in your real loop.

May 31, 2026 · grounded in orchestrator.mjs, skills.mjs, router.mjs, tools/registry.mjs
What actually differs The picture Pros & cons The #1 cost What you should do
A skill swaps the instructions inside one shared context. A separate agent spins up a second context — its own message history and its own tool set — and hands back only a result. Same model calls either way. The real axis is context isolation + tool scoping, not prompt text. Everything else follows from that one difference.

What actually differs

Both approaches are "call OpenAI with a prompt." Your instinct is correct. Here's the one knob that moves:

AxisSkill (what you run now)Separate agent
Prompt / instructionsSwapped — SKILL.md prose injected into the system messageSwapped — sub-agent gets its own system prompt
Context / historyShared. One message thread. The model sees the whole conversation + every tool resultIsolated. Its own thread. Caller never sees the sub-agent's internal turns
Tools visibleAll of them. Every turn loads ALL_TOOLS regardless of skillScoped. Sub-agent sees only its 4–6 relevant tools
Output to callern/a — it's all one turnA summary. The messy middle is discarded
New intelligence?None, either way. Multi-agent is just more loops, scoped differently. No magic appears.

So the prompt is a red herring. The thing that changes is what's in the context window and which tools are on the table. A skill keeps one big shared context; a separate agent fences off a private one.

Where your code sits today

One orchestrator.mjs loop — the only place OpenAI is called. router.mjs picks a SKILL.md to splice into the system prompt (or none, and the model self-selects via use_skill). Crucially: tools are global — the orchestrator loads ALL_TOOLS every turn and the skill prose only suggests which fit. You have skills. You do not have separate agents. That's a fine place to be.

The picture

SKILL — ONE SHARED CONTEXT orchestrator loop system = identity + SKILL.md message history (all turns) + every tool result, inline ALL_TOOLS visible (~10, growing) swap skill = swap the prose only. context + tools stay the same. SEPARATE AGENT — ISOLATED CONTEXT main loop calls a tool: dispatch_vendor(ctx) sees only the returned summary ↓ sub-agent (own loop) own system prompt own message history (private) scoped tools: scrape, pick, send returns: "vendor = Joe's, sent ✓"
Left: today. Right: the messy middle (scraping, 6 tool calls, big JSON) stays out of the main thread.

Pros & cons

Skills you, now

one loop, one context, global tools
Pros
  • Dead simple. One loop to reason about and debug. Your turn-trace captures it cleanly.
  • No context loss. The model sees the whole conversation — it can't "forget" what another agent knew.
  • Cheap to add. New workflow = drop a SKILL.md + one registry line.
  • Model self-routes via use_skill — no routing layer to maintain.
Cons
  • Context bloat. Every tool result + all history piles into one window. Long jobs balloon it.
  • Tool overload. All ~10 tools shown every turn; at 20–30 the model mis-picks more.
  • Generalist prompt. One system message trying to be triage + dispatch + follow-up.

Separate agents later, selectively

isolated context, scoped tools
Pros
  • Clean main thread. A verbose job's 10 tool calls collapse to one summary line.
  • Sharper tool selection. 5 tools beat 30 for accuracy.
  • Independent tuning. Own model (cheaper for narrow jobs), own iteration cap, own evals.
Cons
  • Handoff context loss — the big one, see below.
  • More moving parts — routing, state, tracing across loops.
  • Latency stacks — sequential model calls add up.
  • Overkill at your scale — solving a problem you don't have yet.

The #1 cost of going multi-agent

Handoff context loss. A sub-agent only knows what you pass it. Forget to forward one fact — the tenant already said the leak is under the sink, the owner caps repairs at $500 — and it makes a worse decision than your single agent would have, because your single agent saw everything. This is the most common way real multi-agent systems get dumber, not smarter. Skills are strictly safer for correctness; multi-agent trades that safety for a cleaner context and tighter tools. Only make that trade when the bloat is actually hurting you.

What you should do

Stay on skills. Peel out one sub-agent only when the context tells you to.

Now: skills are the right call — 2 skills, ~10 tools, one conversation per handle. Nothing is bloated. Keep adding workflows as SKILL.md files.

The tripwire: the line that loads ALL_TOOLS every turn. When tool count crosses ~15–20, or one workflow generates verbose intermediate output that crowds the thread, that's the signal — not a calendar date.

First thing to peel out: the PMS / AppFolio dispatch flow. It's self-contained, tool-heavy (scrape, match, send), and spits out messy intermediate JSON you don't want in the main context. Textbook sub-agent.

How — no framework: a sub-agent is just a tool. Write dispatch_vendor whose run() fires its own scoped model loop (its own prompt + 4–6 tools) and returns a one-line summary. Your orchestrator already runs arbitrary tools — it won't even know the tool happened to call a model inside. That's multi-agent, built from the loop you already have.

Rule: skills until the context hurts; then fence off the worst offender as a tool. You'll never need a framework to do it.