Skip to content
AI/ML Engineering

Claude Code Subagents and Skills: Building Real Workflows

Layer subagents, skills, hooks, slash commands, and MCP servers into autonomous workflows. Real config patterns for 5-engineer backend teams.

A
Abhishek Patel11 min read

Infrastructure engineer with 10+ years building production systems on AWS, GCP,…

Claude Code Subagents and Skills: Building Real Workflows
Claude Code Subagents and Skills: Building Real Workflows

Claude Code Subagents and Skills: Build a Real Workflow

Claude Code is the most-adopted AI coding tool in 2026 — 46% "most loved" in the Pragmatic Engineer survey, 18% workplace adoption (1.5x growth from late 2025). Most articles cover what it is. This one shows how to build a real autonomous workflow by composing subagents (delegated context-isolated tasks), skills (reusable instructions triggered automatically), hooks (PreToolUse / PostToolUse / Stop event handlers), slash commands (custom prompts you can invoke with /), and MCP servers (external tool integrations). The goal: a setup where shipping a feature looks like "/implement <ticket>" and Claude Code drives the full loop — research, plan, code, test, review, commit — with human checkpoints at meaningful moments.

Building blockWhat it doesWhen to use
SubagentDelegated task in fresh context windowIndependent work that won't pollute main context
SkillAuto-loaded instructions matching topic / file / keywordRepeatable patterns (writing tests, releasing, debugging)
HookShell command run on tool eventsGuardrails (lint, test, format) and event automation
Slash commandSaved prompt with optional argumentsFrequently invoked workflows (commit, deploy, review)
MCP serverExternal tool integration via Model Context ProtocolProject-specific data sources (DB, internal docs, JIRA)

Last updated: April 2026 — verified against Claude Code current builds, agent/skill/hook spec versions current as of late April 2026. Anthropic ships breaking changes occasionally; check release notes monthly.

The Five-Layer Workflow Architecture

Most teams use only one or two of the building blocks. The compounding value comes from layering them. Concrete example for a typical team running:

  1. Skill auto-loads when working on tests (matches "test", "spec", or file pattern *.test.ts) — defines test-writing conventions for the codebase.
  2. PreToolUse hook blocks dangerous Bash commands (rm -rf, git push --force) before they run.
  3. Subagent handles "research how this third-party API works" tasks in isolated context, returning a summary without polluting the main thread.
  4. Slash command /commit formats commit messages per the team's conventional-commits rules.
  5. MCP server exposes the team's internal docs (Notion / Confluence) so Claude can ground answers in current architecture.

The layers compose: a request to "add tests for the new feature" auto-loads the test-writing skill, may delegate research to a subagent, hits the PreToolUse hook before running anything destructive, and ends with the slash command for the commit step. The Claude Agent SDK guide covers programmatic agent construction; this article focuses on the user-facing Claude Code tooling.

Subagents: Context Isolation for Independent Work

Subagents are the most underused feature. They run a sub-task in a fresh context window — the parent agent gets back a summary, not the raw tool calls. Key properties:

  • Independent context: a 200K-token research task doesn't pollute the main thread.
  • Configurable tool access: you can restrict the subagent to read-only tools to keep it safe.
  • Result-only return: the parent gets a single text response, summarizing what the subagent did.
  • Parallel execution: multiple subagents can run simultaneously when their work is independent.

Where subagents shine

- Research: "Find every place we use the deprecated logger and document them"
- Code review: independent reviewer with fresh eyes on a diff
- Test generation: write tests for module X without seeing main implementation work
- Doc summarization: read a 200-page API spec, summarize what's relevant
- Codebase exploration: trace the call graph for a function across the repo

Where subagents misfire

  • Tasks needing main-thread context: if the subagent needs to know what you and Claude have been discussing, the isolation works against you.
  • Sequential dependencies: subagents don't share state; if step 2 depends on step 1's intermediate output, both should run in main thread.
  • Trivial work: spinning up a subagent for "rename this variable" is more overhead than value.

Skills: Auto-Loaded Patterns

A skill is a markdown file that Claude Code auto-loads when its description matches the current task. Skills are how you encode "the way we do things here" without having to repeat it every conversation. Skills live in .claude/skills/<name>/SKILL.md per project (or globally in ~/.claude/skills/).

---
name: writing-tests
description: Use when writing or modifying tests, especially for our backend API
---

# Writing Tests for This Codebase

We use Vitest with the supertest helper for HTTP integration tests.

## Conventions
- Place tests next to the code: `src/routes/users.ts` → `src/routes/users.test.ts`
- Test the integration, not the unit — call the route handler with a real-ish request
- Use the test helper `createApp()` to spin up an in-memory app instance
- Database tests run against the dockerized postgres in `docker-compose.test.yml`
- Always assert HTTP status, response shape, and database state — at minimum two of the three

## Example skeleton
\`\`\`ts
import { describe, expect, it } from 'vitest';
import request from 'supertest';
import { createApp } from '../../testing/app';

describe('GET /users/:id', () => {
  it('returns 200 with user shape', async () => {
    const app = await createApp();
    const res = await request(app).get('/users/test-id');
    expect(res.status).toBe(200);
    expect(res.body).toMatchObject({ id: 'test-id', email: expect.any(String) });
  });
});
\`\`\`

The skill's description field is what Claude Code matches against. Make it specific — vague descriptions ("Use for code") never trigger or trigger too often. The MCP server build guide covers a different but related extensibility surface.

Hooks: PreToolUse, PostToolUse, Stop Events

Hooks are shell commands the harness runs at specified events. Configure in .claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "scripts/check-bash-safety.sh"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "npx prettier --write \"$CLAUDE_TOOL_FILE_PATH\""
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Session ended at $(date)' >> .claude/audit.log"
          }
        ]
      }
    ]
  }
}

Common useful hooks

  • Auto-format on Write: prettier --write or black --quiet after every file modification
  • Block dangerous Bash commands: PreToolUse with a script that exits 1 on rm -rf, git push --force, etc.
  • Run tests after Edit: PostToolUse on Edit triggers vitest run --related <changed-file>
  • Audit log on Stop: write session summary to a log for compliance
  • Notification on long-running task: Notification hook sends a desktop alert when Claude finishes

Slash Commands: Saved Prompts with Arguments

Slash commands live in .claude/commands/<name>.md. They're saved prompts you can invoke with /<name> [args]. The argument string substitutes into $ARGUMENTS in the file:

---
description: Implement a Linear ticket
allowed-tools: [Read, Write, Edit, Bash, Grep, Glob]
---

Implement Linear ticket $ARGUMENTS.

Process:
1. Read the ticket details (use the Linear MCP server if available)
2. Identify which files need to change
3. Make minimum-scope changes
4. Run tests
5. Commit with conventional-commits format: feat(scope): description (LIN-XXX)
6. Open a PR draft

Now /implement LIN-1234 drives the full feature implementation cycle. Pair with skills (auto-loaded test conventions), hooks (auto-format on Edit), and an MCP server (Linear API access) and the workflow becomes genuinely autonomous within bounded scope.

MCP Servers: External Tool Integration

The Model Context Protocol standardizes how Claude Code (and other MCP clients) talk to external tools. Each MCP server exposes resources (read-only data), tools (function calls), and prompts (parameterized instructions). The best MCP servers roundup covers production-ready options; the build-your-own MCP server tutorial covers authoring.

Configure MCP servers in .claude/settings.json:

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/docs"]
    },
    "internal-docs": {
      "command": "node",
      "args": ["./mcp-servers/internal-docs.js"]
    }
  }
}

Common useful MCP servers for engineering teams:

  • Linear / Jira: ticket lookup, status updates, comment posting
  • GitHub: issue search, PR review, status checks
  • Postgres / DB schemas: schema introspection without connection strings in conversation
  • Internal docs (Notion / Confluence): ground answers in current architecture
  • Sentry / Datadog: pull error context for debugging sessions
  • Filesystem (read-only): expose specific directories outside the working tree

The Real Setup: Putting It All Together

For a 5-engineer backend team, the layered Claude Code setup that delivers daily value:

.claude/
  settings.json          # hooks: format-on-edit, block-dangerous-bash; MCP: linear, github, internal-docs
  skills/
    writing-tests/
      SKILL.md           # team test conventions
    debugging/
      SKILL.md           # debugging workflow + tools
    releasing/
      SKILL.md           # release process, version bumping
  commands/
    implement.md         # /implement  — full feature cycle
    review.md            # /review  — code review with our standards
    debug.md             # /debug  — investigation workflow
    deploy.md            # /deploy  — staged deployment
    fix-types.md         # /fix-types — TypeScript error fixing pattern
  agents/
    researcher.md        # subagent for codebase exploration
    test-writer.md       # subagent for test generation
    reviewer.md          # subagent for fresh-eyes code review

Each engineer can compose these — running /implement LIN-1234 kicks off auto-load of writing-tests skill, may spawn a researcher subagent to map the affected code, runs prettier on every Edit (PostToolUse), blocks risky Bash via PreToolUse, and pulls Linear ticket details via the MCP server. The whole thing feels like a real engineering teammate. The AI coding assistants comparison covers Claude Code in the broader landscape.

Pro tip: Skills with vague descriptions never trigger correctly. Make the description field specific to when the skill should auto-load — include the kind of file pattern, task type, or topic. "Use when writing tests" beats "Testing skill" by a wide margin. The advanced multi-agent orchestration patterns I deploy in production I send to the newsletter.

Common Pitfalls

  1. Hooks that block legitimate work: too-aggressive PreToolUse rules force friction. Whitelist what's safe rather than blacklisting what's not — the latter always misses cases.
  2. Subagents called for trivial tasks: spawning a subagent for "rename a variable" is overhead. Use them only for genuinely independent work.
  3. Skills with vague descriptions: never trigger correctly. Be specific about the matching pattern.
  4. MCP servers that pull live data on every conversation: chatty MCPs slow Claude down meaningfully. Cache where appropriate.
  5. Slash commands without descriptions: nobody discovers them. Document each command in the team README.
  6. Mixing project-level and user-level settings randomly: project-level .claude/ is committed to the repo and shared across the team; ~/.claude/ is per-developer. Pick deliberately.

Frequently Asked Questions

What are Claude Code subagents?

Subagents are delegated tasks that run in fresh context windows separate from the main conversation. The parent agent gets back a summary, not the raw tool calls — so a 200K-token research task doesn't pollute the main thread. Useful for codebase exploration, independent code review, doc summarization, and parallel research. Configure tool access per subagent to keep them safe (read-only for research tasks).

What is a Claude Code skill?

A skill is a markdown file that Claude Code auto-loads when its description matches the current task. Skills encode "how we do things here" — testing conventions, debugging workflows, release processes — without repeating instructions every conversation. Skills live in .claude/skills/<name>/SKILL.md. The description field is what Claude matches against, so make it specific.

How do Claude Code hooks work?

Hooks are shell commands the Claude Code harness runs on specified events: PreToolUse (before any tool call), PostToolUse (after), Stop (session end), Notification (on user-attention events). Useful for guardrails (block dangerous Bash), automation (format on Edit, run tests on Write), and audit logging. Configure in .claude/settings.json; matchers can target specific tools (Bash, Edit, Write).

What is an MCP server in Claude Code?

An MCP server is an external tool integration following the Model Context Protocol. Claude Code talks to MCP servers to access data and capabilities outside its built-in tools — Linear tickets, GitHub repos, Postgres schemas, internal docs, Sentry errors. Common production MCP servers cover the major dev tools; you can also build custom ones for project-specific needs.

Can I use Claude Code in a team?

Yes — project-level .claude/ directory committed to the repo shares skills, slash commands, hooks, and MCP server configs across the team. Per-developer settings live in ~/.claude/. Best practice: project-level for team conventions, user-level for personal preferences. Document the project-level setup in the README so new team members know what's available.

How do slash commands work in Claude Code?

Slash commands are saved prompts in .claude/commands/<name>.md files. Invoke with /<name> [arguments]. The argument string substitutes into $ARGUMENTS in the file, so /implement LIN-1234 passes "LIN-1234" to the prompt. Useful for repeatable workflows: /commit, /review, /deploy, /debug, etc.

What's the difference between skills and slash commands?

Skills auto-load when their description matches the current task — Claude decides when to use them based on conversation context. Slash commands are explicitly invoked by the user (typed as /name). Skills are for "how we work in this area"; slash commands are for "I want to run this specific workflow now." They complement each other.

Compose, Don't Just Configure

The teams getting real productivity from Claude Code aren't just turning it on — they've layered subagents, skills, hooks, slash commands, and MCP servers into workflows that match how their team actually ships. The setup investment pays back within days for any team shipping daily. Start with one skill (your testing conventions), one slash command (your commit workflow), one hook (auto-format on Edit), one MCP server (your ticket system), and one subagent (codebase research). Build from there as patterns emerge.

A

Written by

Abhishek Patel

Infrastructure engineer with 10+ years building production systems on AWS, GCP, and bare metal. Writes practical guides on cloud architecture, containers, networking, and Linux for developers who want to understand how things actually work under the hood.

Related Articles

Enjoyed this article?

Get more like this in your inbox. No spam, unsubscribe anytime.

Comments

Loading comments...

Leave a comment

Stay in the loop

New articles delivered to your inbox. No spam.