Home About Blog Get in Touch

Claude Code Subagents vs Agent Teams: A Better Default for Sequential Workflows

Michał Król
  • claude-code
  • ai-automation
  • flutter
  • subagents
  • anthropic
Cover image for Claude Code Subagents vs Agent Teams: A Better Default for Sequential Workflows

TL;DR

  • Subagents (.claude/agents/*.md) define a role: tools, model, system prompt, skills.
  • Agent teams are a communication group of named, still-running agents that can SendMessage each other while both are alive.
  • They’re orthogonal primitives, not alternatives. A team uses subagents as the role each member plays; subagents work fine without a team.
  • For a sequential plan → approve → implement workflow, main Claude already orchestrates and shuttles output between agents — there’s no live back-and-forth, so a team is overhead.
  • This post shows the two custom subagents (planner.md, implementer.md) and a /task slash command I use instead — and how I run them automatically inside a GitHub Action for a client project.

What is a custom subagent in Claude Code?

A custom subagent in Claude Code is a Markdown file under .claude/agents/ that defines a role: which tools the agent can call, which model it runs on, its system prompt, and which skills it has access to. Main Claude can spawn it as a child task, hand it work, and read its final output back into the parent context.

Subagents are personas. Each invocation gets a fresh context, scoped by the role you defined. They don’t share state with each other and they don’t talk to each other.

The misconception: teams are not an upgrade of subagents

This is the bit I got wrong for months.

I’d been treating “agent teams” and “custom subagents” as two ways to do the same thing. They aren’t. They’re orthogonal primitives.

  • Subagent = a role definition (tools, model, prompt, skills). A persona.
  • Team = a communication group of named, still-running agents that can SendMessage each other directly while both are alive. The team is the runtime that lets multiple personas talk in real time.

A team uses subagents as the role each member plays. Subagents work fine without ever being in a team.

The decision rule that finally clicked for me: reach for a team only when agents need to converse while both are alive. If your workflow is sequential — agent A produces output, you (or main Claude) approve it, then agent B starts — you don’t need a team. Main Claude is already the orchestrator. It can spawn one subagent, read the output, then spawn the next.

My old approach: spawning a team for every multi-agent task

Whenever a task felt like it needed more than one agent, I’d send Claude something like this:

Create an agent team for the following task:

Before creating an agent team ask me questions if anything is unclear.

Spawn two teammates:

1. Planner (name: "planner")
   - Model: Opus
   - Mode: Default
   - Role: Analyze the codebase and produce a detailed implementation plan with file-level changes. Flag ambiguities or risks. Output the plan as a structured message.

2. Implementer (name: "implementer")
   - Model: Sonnet
   - Mode: Default
   - Role: Implement the approved plan step by step. After 2 failed fix attempts on the same issue, report the blocker to the lead.

Coordination:
- Create tasks with dependencies: implementer is blocked until planner's
  plan is approved.
- The planner's plan requires approval from both you (the lead) and me
  before the implementer starts.

Figma:
...

This worked. It also did three things I didn’t actually need:

  1. Held two agents alive in parallel when only one was active at a time.
  2. Re-defined the planner and implementer roles from scratch in every prompt, so the role definitions drifted between sessions.
  3. Burned coordination overhead on a workflow that was already strictly sequential.

The role definitions weren’t version-controlled. The skill list wasn’t tied to the agent. The whole thing lived in my prompt history.

My new approach: two custom subagents + a /task command

Same workflow, expressed as two .claude/agents/*.md files and a /task slash command that orchestrates them. The role definitions live in the repo, get version-controlled, and carry their tool and skill lists with them.

planner.md

---
name: planner
description: Analyzes the codebase and produces a detailed file-level implementation plan for a given task. Flags ambiguities and risks.
model: opus
color: pink
tools: Read, Glob, Grep, Bash, WebFetch, WebSearch, Skill, TaskCreate, TaskGet, mcp__figma__*
skills: flutter-apply-architecture-best-practices, flutter-build-responsive-layout, flutter-fix-layout-issues, flutter-implement-json-serialization, flutter-use-http-package, flutter-add-widget-test, flutter-accessibility-audit
---

You are the Planner. Your job is to produce a detailed, file-level implementation plan for given task — nothing more.

## What you do

1. **If the task contains Figma links, fetch the design first — before anything else.** Extract every relevant design detail: layout, spacing, colors, typography, component structure, text content (labels, button text, headings, body copy), icons, images, and interactive states. Do not draft the plan or list open questions until the design has been fully read — many "questions" answer themselves once you see the file.
2. Read the relevant existing code so the plan is grounded in the real codebase, not assumptions.
3. Produce a structured plan covering:
   - **Goal**: one-paragraph restatement of the task.
   - **Files to change**: every file you expect to touch, listed at the function/class/method level with the specific change and the reason.
   - **Files to add**: new files with their purpose and approximate shape (key classes, public API).
   - **Test plan**: which tests to add or update.
   - **Risks & ambiguities**: anything that could go wrong.
   - **Open questions for the lead**: things that must be resolved before the implementer starts.
4. Be honest about uncertainty. If you are unsure, list it as an ambiguity with options — do not guess.

## What you do NOT do

- Do not modify files. You have no Edit/Write tools by design.
- Do not implement the work. Your output is the plan only.
- Do not pad the plan with restatements of project conventions the lead already knows. Focus on what is specific to this task.

## Output format

Return one structured message in this shape:

# Plan: <task title>

## Goal

## Files to change
- `path/to/file.dart`
  - `ClassName.methodName`: <what changes and why>

## Files to add
- `path/to/new_file.dart`: <purpose, key classes/functions>

## Test plan
- ...

## Risks & ambiguities
- ...

## Open questions for the lead
- ...

End your message with the literal line **`Plan ready for approval.`** so the lead knows to gate the implementer on it.

A few things worth calling out about this file:

  • The planner has no Edit or Write tool. That’s intentional — you cannot accidentally let the planner start coding. The role boundary is enforced by the tool list, not just by the prompt.
  • Skills are declared explicitly in skills:. Subagents don’t automatically inherit the project’s skills — you have to list them in the agent’s frontmatter. (Built-in agents like Explorer / Plan / Verify can’t access skills at all.)
  • color: pink. Pink is one of my favorite colors and the planner header pops in the terminal output. Genuine question for anyone reading: what color is your planner?

implementer.md

---
name: implementer
description: Implements a plan step by step.
model: sonnet
tools: Read, Write, Edit, Glob, Grep, Bash, WebFetch, WebSearch, Skill, TaskCreate, TaskGet, TaskUpdate, TaskList, mcp__figma__*
skills: flutter-apply-architecture-best-practices, flutter-build-responsive-layout, flutter-fix-layout-issues, flutter-implement-json-serialization, flutter-use-http-package, flutter-add-widget-test, flutter-accessibility-audit
---

Your key responsibility is to implement the given plan.

## Inputs you expect

- Implementation plan
- Any modifications the lead and user agreed on during plan approval

## What you do

Work through the plan step by step. Treat each "Files to change" / "Files to add" entry as a discrete unit of work.

## Blocker rule

If the same issue fails twice after you tried to fix it, **stop and report**. Send a single message to the lead with:

- What you were trying to do.
- The two attempts you made and why each failed.
- Your best hypothesis for the root cause.
- What you would try next, or what input you need from the lead.

Do not loop on a third attempt. The lead decides whether to redirect, re-plan, or escalate to the user.

## Reporting back

When the plan is fully implemented:

- Summarize what changed (files + one-line per change).
- List the verification checks you ran and their outcomes.
- Note anything you intentionally deferred and why.

Two details that matter here:

  • The blocker rule lives in the implementer’s prompt, not the orchestrator’s. Two failed fix attempts on the same issue → stop and report. No third try without input from the lead. This used to live in my team-spawning prompt and would silently drop out whenever I rewrote the prompt. Now it’s pinned to the role.
  • The implementer runs on Sonnet. Most of what an implementer does — applying a plan that’s already been thought through — does not need Opus. Opus is reserved for the planner where actual reasoning happens.

/task command

For interactive use, you could just run main Claude and ask it to use the planner subagent first, then the implementer. That works, but it’s repetitive. So I wrapped the orchestration in a slash command:

---
description: Run a workflow with planner and implementer subagents for a task
argument-hint: [--auto] <task description>
---

Run the workflow described below — using the `planner` and `implementer` subagents — for the following task:

$ARGUMENTS

## Mode

- **Interactive (default)**: analyze code related to the task ask clarifying questions if anything is unclear, and require my approval of the plan before implementation.
- **Automated**: if the message above contains `--auto`, skip clarifying questions and skip my approval gate. Strip the `--auto` token from the task before passing it to the planner.

## Workflow

1. **Clarify** — interactive mode only. If the task is unambiguous, skip to step 2. Otherwise ask me clarifying questions before spawning anything.

2. **Plan** — spawn the `planner` subagent with the task. Wait for the plan.

3. **Approve**
   - Interactive mode: present the plan to me. Both you and I must approve before implementation. If either of us has changes, send them back to the planner.
   - Automated mode: review the plan yourself. If it has critical issues (architectural conflicts, missing prerequisites, contradictions with `CLAUDE.md`), send it back to the planner with feedback. Otherwise approve and proceed.

4. **Implement** — spawn the `implementer` subagent with the approved plan. The implementer is blocked until approval.

5. **Blockers** — if the implementer reports a blocker after 2 failed fix attempts on the same issue:
   - Interactive mode: surface it to me with the implementer's hypothesis and options. Do not loop on a third attempt without my input.
   - Automated mode: halt the workflow and report the blocker with full context. Do not retry.

Two modes:

  • Interactive (default) — clarify if needed, plan, present plan, wait for human approval, implement, surface blockers to me.
  • Automated (--auto) — skip the interview and the human approval gate. Use this only when the input task is well-refined. (You can — and should — write a separate skill that enforces the refinement standard before --auto ever runs.)

The --auto mode is what makes the command usable inside CI.

Real-world example: a GitHub Action for Aparkado

For Aparkado (the team behind LKW.APP), I run this as part of an end-to-end automation:

  1. A team member adds an @automation-claude comment on a Linear issue labeled App + Automation.
  2. A Make.com scenario calls GPT to validate the issue against the project’s Definition of Ready and posts the JSON result (confidence score + comments) back to Linear. If the confidence score clears the threshold, Make.com creates a branch from develop, commits a task.md containing the refined task, and opens a PR.
  3. A GitHub Action triggers on PR creation. It runs Claude Code, which executes /task --auto against the contents of task.md. The two subagents do the work — plan, then implement — commit, push, and remove task.md in a final cleanup commit.
  4. A human reviews the PR. We deliberately keep this step for knowledge sharing, not because the code needs it.

The whole point of this pipeline is that the expensive part — refining the task to a state Claude can implement well — happens before the agents run. The DoR check enforces it. By the time /task --auto fires, the input is good enough that no clarifying questions are needed.

If I’d built this same pipeline with agent teams, every PR would have been spawning a runtime communication group, paying the coordination tax, and re-defining the planner and implementer roles from scratch in every CI run. With custom subagents, the roles are committed to the repo and the pipeline is just claude --slash-command "/task --auto $TASK".

FAQ

Are subagents and agent teams interchangeable? No. Subagents define a role; teams define a runtime communication group. A team uses subagents as the role of each member, but subagents work without a team.

When should I actually use an agent team? When you need agents to converse while both are alive — a debate, a back-and-forth code review, a long-running pair-programming session. If your workflow is sequential, main Claude is already the orchestrator and you don’t need a team.

Why does the planner have no Edit or Write tools? Role separation is enforced by the tool list, not just by the prompt. Removing those tools makes it physically impossible for the planner to start implementing the task.

Do subagents inherit the project’s skills automatically? No. You have to list each skill explicitly in the agent’s skills: frontmatter. Built-in agents (Explorer, Plan, Verify) can’t access skills at all — only custom subagents in .claude/agents/ can.

Can I run /task in CI without a human in the loop? Yes — /task --auto skips the clarifying interview and the approval gate. Only do this when the input task is well-refined; otherwise the planner has nothing solid to ground its plan on. A well-defined Definition of Ready, enforced before the action runs, is what makes this safe.

What’s next

This post focused on subagents. The same Anthropic Skills course also reshaped how I think about skill descriptions, the SKILL.md structure, the priority order between enterprise / personal / project / plugin skills, and when to reach for a hook or slash command instead of a skill. I’ll write those up next.

If this kind of orchestration is something you’re building into a client project and you want a second pair of eyes on it, get in touch — it’s the work I do.

Share this article