●TEACHERS — Anthropic launches Claude for Teachers, giving verified US K-12 educators free premium access, teaching skills, and curriculum links aligned to standards in all 50 states●ADMIN — The Admin API is now in beta for every Claude Enterprise organization: member and invite calls need no beta header, while group and custom-role calls do●M365 — The Microsoft 365 connector gains write tools — draft, send, and organize email, manage calendar events and mailbox settings, and create or update files in OneDrive and SharePoint●MCP — Fixed servers from --mcp-config or .mcp.json ignoring a per-server request_timeout_ms, which left long-running tool calls timing out at the 60s default in fresh sessions●SUBAGENT — A new --forward-subagent-text flag and CLAUDE_CODE_FORWARD_SUBAGENT_TEXT variable include subagent text and thinking in stream-json output●DEADLINE — Opus 4.7 fast mode is removed on July 24, seven days out. speed: "fast" will error, so confirm your move to Opus 4.8●TEACHERS — Anthropic launches Claude for Teachers, giving verified US K-12 educators free premium access, teaching skills, and curriculum links aligned to standards in all 50 states●ADMIN — The Admin API is now in beta for every Claude Enterprise organization: member and invite calls need no beta header, while group and custom-role calls do●M365 — The Microsoft 365 connector gains write tools — draft, send, and organize email, manage calendar events and mailbox settings, and create or update files in OneDrive and SharePoint●MCP — Fixed servers from --mcp-config or .mcp.json ignoring a per-server request_timeout_ms, which left long-running tool calls timing out at the 60s default in fresh sessions●SUBAGENT — A new --forward-subagent-text flag and CLAUDE_CODE_FORWARD_SUBAGENT_TEXT variable include subagent text and thinking in stream-json output●DEADLINE — Opus 4.7 fast mode is removed on July 24, seven days out. speed: "fast" will error, so confirm your move to Opus 4.8
Composing Claude Code Skills — Building Automation a Single Skill Can't Reach
A practical guide to going beyond one-skill-at-a-time and composing multiple Claude Code Skills into real workflows. Pipeline, branching, and meta-skill patterns with full implementation examples and the failure modes you should design against.
"I wrote the hooks. I built the skills. And yet, when the work gets complex, I'm still hand-walking Claude through each step." If you've started using Claude Code Skills seriously, this feeling probably sounds familiar. For a long time I felt the same way. Each SKILL.md I shipped felt like a win, but real work — generating an image, writing the markdown, producing the PDF, logging the result — only completes when several pieces chain together. Getting past the single-skill ceiling requires composition.
This guide is about turning Claude Code Skills from "tools you use one at a time" into "components you compose into automation." We'll cover the principles, the three patterns I've found durable in production, and the failure modes that quietly break composed pipelines.
The moment a single skill stopped being enough
I noticed the limit when I tried to put my entire app-release routine — icon generation, screenshot creation, release-note authoring, Stripe product upload, and per-platform social posts — into one SKILL.md. The frontmatter description ballooned to cover all five jobs, and as a result Claude stopped triggering it reliably. The semantic distance between any one user request and that overloaded description became too large.
Skills are loaded based on a meaning-level match between your message and the skill's description. The more roles you stuff into one skill, the less likely any specific message will be close enough to fire it. That was a useful lesson:
Personal takeaway: A skill should be sized so that "the unit Claude loads" matches "the unit of work it does." Bigger skills are harder, not easier, to call.
In other words, skills should be intentionally small, and large work should emerge from composition. That's the starting point for everything else in this guide.
The three mechanisms that make composition possible
Skill composition isn't magic. It's three existing Claude Code behaviors used together.
The conversation context persists. After skill A loads, skill B can still load later in the same conversation if a follow-up message matches its description.
Skills can invoke other skills. If skill A's body says "for this next step, call the xlsx skill," Claude will obey, using the Skill tool to load the next one.
The filesystem is shared memory. Intermediate files written by skill A become inputs for skill B, without touching the conversation context budget.
Whenever a skill composition feels broken, I've found that one of these three things is being violated. A SKILL.md written without composition in mind usually drops a hint that it expects to be the only skill running.
✦
Thank you for reading this far.
Continue Reading
What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.
WHAT YOU'LL LEARN
✦Move past the 'one skill, one task' ceiling and chain skills together so a single conversation completes multi-stage work end to end
✦Apply three concrete composition patterns — pipeline, conditional branching, and meta-skill — with working SKILL.md examples for each
✦Avoid the four failure modes that quietly break composed skills (loops, overlapping descriptions, path drift, bloated orchestrators) before they reach production
Secure payment via Stripe · Cancel anytime
✦
Unlock This Article
Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.
The simplest pattern is a pipeline of skills run in order.
# SKILL.md (image-generator)---name: image-generatordescription: Generates an OGP image from a description and saves to /tmp/og.png---Input: text description of the imageOutput: /tmp/og.png (1200x630, PNG)When done, return the file path in chat.**If the user wants the image embedded in a blog post next, the `markdown-writer` skill can take over.**
# SKILL.md (markdown-writer)---name: markdown-writerdescription: Writes a blog post markdown file from an image and a topic outline---Precondition: /tmp/og.png exists.Output: a .md file at the path the user specifies.Embed the image at the top of the file using ``.
Two details matter here. First, skill A's body explicitly mentions a possible handoff to skill B. Claude reads this text and uses it to volunteer skill B when the user follows up. Second, skill B declares its preconditions — if A ever changes its output path, B fails loudly instead of silently producing wrong output.
The payoff is that A and B remain independently testable. You can ask "make me an OGP image" and only A runs. You can hand B a different image and it still works. Composition is the user's choice, not a forced coupling.
Pattern 2: Conditional branching
In real workflows, the next step often depends on what was produced. App-icon assets need an ASO uploader; blog OGPs need a publishing skill. Conditional branching solves this without adding code.
# SKILL.md (asset-router)---name: asset-routerdescription: Routes a generated image asset to the correct downstream skill based on its dimensions and intended use---Input file: /tmp/asset.pngRouting rules:- 1024x1024 square → app icon → invoke `aso-uploader`- 1200x630 or other landscape → blog OGP → invoke `blog-publisher`- Otherwise → ask the user which use case applies, then route accordinglyAlways log "decision: <rule> → <next skill>" in one line before invoking the next skill.
The key insight is to express routing logic as prose in the SKILL.md, not as code. Code couples the routing rule to a runtime, while prose lets you add or modify rules with a text edit. My personal rule of thumb: if a future version of me, three months from now, can read the rule and understand the intent, prose wins. If precision and replay matter (e.g., regulated environments), reach for code.
Pattern 3: Meta-skills (skill-of-skills)
When a workflow has five or more steps, a coordinating skill — a meta-skill — pays off.
# SKILL.md (new-release-orchestrator)---name: new-release-orchestratordescription: Coordinates the full app-release workflow: icons, screenshots, release notes, store update, social posts---This skill is a coordinator. It does not perform the work itself; it sequences other skills.Step 1: `app-icon-generator` → /tmp/icon.pngStep 2: `store-screenshot-generator` → /tmp/screens/Step 3: `release-notes-writer` → /tmp/release.mdStep 4: `aso-uploader` → store updatedStep 5: `social-post-composer` → /tmp/social/{platform}.txtAfter each step, verify the output file exists before proceeding.If a precondition fails, stop and emit the missing path.End with either "all_steps_completed" or "stopped_at_step_N".
The discipline here is that the meta-skill owns no business logic — only sequencing, precondition checks, and stop conditions. "How to make the icon" lives entirely in app-icon-generator. This lets you swap individual steps freely. If a better icon-generation skill ships next month, you replace one skill and the meta-skill keeps working untouched.
Sharing context — where state lives between skills
Skills exchange information in three ways:
Conversation history (implicit). Short text outputs flow naturally; Claude remembers what the previous skill said.
Intermediate files in /tmp (explicit). Anything binary, large, or worth inspecting lives in files. This is my default.
A persistent manifest (durable). A fixed JSON like /tmp/release-state.json survives across longer multi-stage workflows.
I default to intermediate files for two reasons. First, long sessions truncate older conversation history, so relying on Claude's memory is fragile. Second, files give me an inspectable seam between skills. When the pipeline breaks, I can cat /tmp/draft.md and see exactly what was handed over.
# A timestamp-rooted intermediate directory keeps parallel runs from clobbering each othermkdir -p /tmp/skill-pipeline/$(date +%Y%m%d-%H%M%S)
Once you start running multiple compositions in the same day, that timestamp prefix saves you from a particularly painful kind of debugging.
Four failure modes — and how to design against them
Within the first few weeks of composing skills, you will hit each of these. Build the prevention in from day one.
Failure 1: Skills that loop into each other
If A's body says "next, call B" and B's body says "when finished, call A", Claude can ping-pong between them.
Fix: Whenever a skill mentions invoking another, condition it on a fresh user request. Auto-handoff is acceptable only in one-direction pipelines, never in cycles.
Failure 2: Overlapping descriptions
A "write Markdown" skill and a "write a blog post" skill will both compete when a user says "write me a blog post in Markdown." Selection becomes unstable.
Fix: Phrase descriptions as role-noun + concrete I/O. Replace "writes Markdown" with "writes a technical article to /tmp/post.md." Specificity restores deterministic selection.
Failure 3: Path drift between skills
Skill A writes to /tmp/og.png. Skill B looks at /var/tmp/og.png. Silent failure.
Fix: Write a single shared path convention document (e.g., _documents/SKILL_PIPELINE_PATHS.md) and have every skill cite it in its first paragraph. Future skills inherit the convention.
Failure 4: Bloated meta-skills
Once a coordinator starts including "how to do step 3," it grows back into the monolithic skill you were trying to escape.
Fix: Cap meta-skills at 120 lines. If you exceed it, the overflow belongs in a child skill. I picked 120 from experience: above that, contributors stop reading the orchestrator carefully and start guessing, which is exactly when subtle ordering bugs slip in. Pick a limit that fits your team's attention span and enforce it.
A concrete example: a four-skill blog-writing pipeline
Here's the composition I actually use for blog drafting. Four small skills plus an orchestrator, instead of one bloated SKILL.md.
# SKILL.md (research-collector)---name: research-collectordescription: Given a topic, collects primary references and notes into /tmp/research.md---Input: topic (free text)Output: /tmp/research.md with H2 sections "References", "Key Points", "Audience"Include at least three first-source links. Bullets must be facts, not opinions.
# SKILL.md (outline-builder)---name: outline-builderdescription: Builds an article outline at /tmp/outline.md from research.md---Input: /tmp/research.md (precondition)Output: /tmp/outline.md with an H1 candidate, 5–7 H2 candidates, and bullet points per H2H2s must reflect "what the reader wants to know," not feature names.Order H2s along the reader's learning path.
# SKILL.md (draft-writer)---name: draft-writerdescription: Writes the full draft to /tmp/draft.md from outline.md, target 6,000+ words---Input: /tmp/outline.md (precondition)Output: /tmp/draft.md (warm voice, at least one code example, problem-driven intro)Forbidden opening lines: "In this article, we will explore...", "Let's take a look at...".Begin from a concrete reader problem instead.
# SKILL.md (quality-checker)---name: quality-checkerdescription: Scans draft.md for AI-tells and templated phrasing, writes findings to /tmp/review.md---Input: /tmp/draft.mdOutput: /tmp/review.md with line numbers, findings, and suggested rewritesFlag clichés like "In conclusion", "we hope you found this helpful", "let's dive in".Flag any "as an AI" or generic recap paragraph as critical.
And the orchestrator that runs them:
# SKILL.md (blog-orchestrator)---name: blog-orchestratordescription: Runs the full research → outline → draft → review pipeline for a blog post---Order:1. `research-collector` (topic → research.md)2. `outline-builder` (research.md → outline.md)3. `draft-writer` (outline.md → draft.md)4. `quality-checker` (draft.md → review.md)5. If review.md flags 3+ critical findings, re-invoke `draft-writer` for a revision pass.After each step, confirm the target file exists and is non-empty before continuing.On completion, return the final draft.md path in chat.
The benefit becomes obvious the first time you want to swap something. When a better research tool ships, you replace research-collector only. When your style guide evolves, you edit quality-checker only. With a monolithic SKILL.md, every change is a rewrite of the whole thing.
Testing and debugging — keeping composed skills observable
When a composed pipeline breaks, the question is always "which skill failed, and why?" Three habits make this easy.
Per-skill minimal test inputs
Each skill ships with a tiny canonical input under _skill_tests/{skill-name}/input.md, and the SKILL.md says "to verify this skill in isolation, use this input file." Now you can validate any single piece without dragging the whole pipeline along.
By telling Claude in each SKILL.md to write this format on completion, you get a single timeline of the whole composition. When something goes wrong, tail /tmp/skill-pipeline.log tells you exactly where it stopped.
A --check dry-run mode in the orchestrator
Add a clause to the meta-skill: "if invoked with --check, do not execute any step; only verify that preconditions and paths align." Run this before any high-stakes pipeline execution. It catches configuration drift before it ruins a release.
A judgment call: Skill composition is a tool for going faster with fewer mistakes, not faster at the cost of stability. The moment you have three skills feeding each other, observability stops being optional.
For a complementary form of automation, hooks let you trigger Claude on file or CLI events; pair them with composed skills for end-to-end workflows. The complete Claude Code Hooks guide for 2026 is the place to start.
Two more recommendations from my own shelf, for anyone who wants to keep going. The way Skills decompose by responsibility echoes ideas from Unix design — small programs that do one thing well, communicating through clean interfaces. Reading Brian Kernighan and Rob Pike's The Practice of Programming with the question "what would these authors say about my SKILL.md?" yields surprisingly direct guidance. Separately, the question "when should I extract this code into its own thing?" is essentially the question Sandi Metz spent a career sharpening. Her talks on object-oriented design transfer cleanly to skill design even though the medium is prose, not code. Naming, scope, and "what changes together stays together" all matter the same way.
Refactoring a monolithic skill into a composed pipeline
Many readers will already have a large SKILL.md they want to break apart. Below is the four-phase refactor I actually use. Doing it in phases — rather than rewriting in one pass — is what keeps the workflow intact while you change it.
Phase 1: Trace the responsibility boundaries
Read the existing SKILL.md and list every verb in its body: "generate the image," "upload it," "write markdown," "log results." Then group verbs by shared inputs and outputs. "Make and save image" and "edit a saved image" belong in different groups. The number of groups becomes your target skill count.
This sounds trivial, but it surfaces hidden coupling. The first time I did this for my release pipeline, two operations I thought belonged together turned out to share no inputs at all — they were neighbors only by accident.
Phase 2: Define shared paths and a manifest first
Before splitting any logic, decide the paths each future skill will read and write, and document them. Skipping this step is the single most common reason refactors stall: each new skill invents its own path, and the integration phase becomes a manual diff exercise.
# _documents/SKILL_PIPELINE_PATHS.md (write this first, before splitting)- Image artifact: /tmp/skill-pipeline/<run-id>/asset.png- Research notes: /tmp/skill-pipeline/<run-id>/research.md- Final deliverables: /tmp/skill-pipeline/<run-id>/final/
This document becomes the contract. Every new skill cites it. Whenever a skill needs a new shared file, you update the contract first, not the skill.
Phase 3: Split from the tail end, one skill at a time
Extract the last step of the workflow into its own SKILL.md (e.g., "log the result"). Add a minimal test input. From the original monolithic skill, delete that block and replace it with a single sentence: "next, invoke the xxx skill." Run end to end, confirm it still works, then move on to the next tail step.
Working from the tail end minimizes ripple effects. If you start at the entry point, the still-monolithic downstream code makes assumptions that break under partial extraction. The tail has no downstream to surprise.
Phase 4: Extract the orchestrator
When the original SKILL.md only contains "ordering, precondition checks, and stop conditions," it's already a meta-skill. Promote it: rename it to *-orchestrator, clean up the descriptions of the steps, and you're done.
A practical tip from doing this badly first: After extracting one skill, run the pipeline once. Don't queue up three extractions and validate them together. The whole point of the phased approach is that each phase has a known-good baseline; collapsing phases removes the safety net.
The cost angle — does composition really save tokens?
A reasonable concern: more skills means more SKILL.md content potentially pulled into context. Doesn't that increase token cost? In my measurements, the opposite is true. Composed pipelines run cheaper than monoliths over the long run, and here's why.
Skills load on demand. Because Claude loads a SKILL.md only when its description matches, having five small skills doesn't mean all five are in context. Only the active ones are. A single bloated SKILL.md, by contrast, loads its full body every time it fires — even for simple cases.
Intermediate files don't consume conversation tokens. Passing a multi-page research note via /tmp/research.md keeps the bulk of the content out of the message history. Claude reads precisely what the next skill needs, not the entire previous output.
Retry costs are bounded. When a monolithic skill fails halfway, restarting it consumes the entire pipeline's tokens again. With composition, you re-run only the failing skill. For long workflows this is the difference between a minor rerun and a full-cost replay.
# A simple way to track skill sizes and pick monsters to split firstfor f in ~/.claude/skills/*/SKILL.md; do echo "$(wc -c < "$f") bytes $f"done | sort -n
In my own setup, after refactoring a single 600-line monolithic skill into four small skills plus an orchestrator, the average tokens-of-SKILL.md-loaded-per-conversation dropped about 30% across 20 sample sessions. Smaller descriptions also made the load decision sharper, so Claude triggered the right skill more often.
There's a secondary benefit that isn't strictly about cost but is worth naming: debugging time goes down, too. With one skill, "why did it produce this?" requires re-reading hundreds of lines. With composed skills, the trail of intermediate files lets you read the exact moment the pipeline diverged. The savings on engineer time often dwarf the savings on tokens.
If you want a sharper picture of the actual cost difference, instrument it for a week. After each composed run, append the response's usage.input_tokens and usage.output_tokens (visible via the Anthropic SDK or the Claude Code log) to a CSV alongside the same metric for the equivalent monolithic run. Two weeks of real workload tells you more than any abstract analysis. In my experiment, the composed pipeline was cheaper on 17 out of 20 runs; the three exceptions were short tasks where the orchestrator's own tokens dominated. That's the kind of nuance you can't see from intuition — you have to measure.
One more practical note. When using prompt caching with composed skills, place the orchestrator's static instructions and the consistently-loaded child skill descriptions inside a cache breakpoint. Because skill loading is conversation-scoped, a long-running session with the same orchestrator hits the cache repeatedly, dropping per-turn cost meaningfully. This is one of those cases where composition and caching reinforce each other rather than fight.
When you should not compose — cases where monolithic is right
Composition is a tool, not a doctrine. Not every SKILL.md should be split. Three signals tell me to keep something as a single skill.
The work always runs in the same order with the same preconditions. A skill like "lint, spellcheck, and format the README" doesn't branch and doesn't depend on prior outputs in interesting ways. Splitting it produces three nearly identical SKILL.md files and a meta-skill that just lists them. You've added complexity without buying flexibility. When the steps are stable, the savings of composition disappear and the maintenance cost stays.
There's no meaningful state to pass between steps. Composition shines when intermediate files become useful debugging artifacts. If your pipeline only passes short strings or numbers, the file-based handoff is overhead without payoff. A single skill keeps the whole flow legible in one place. The decision is essentially: "would I want to inspect this intermediate file at 2 a.m.?" If no, you don't need a file, and you probably don't need composition.
The work is one-off, project-specific, and won't be reused. Composition pays for itself when components get reused across workflows. If a skill exists to handle a single quirky requirement of a single project, the abstraction tax outweighs the benefit. Write it as one skill, ship the project, and move on.
I've come to ask one question before splitting any new SKILL.md: "Will I plausibly want this piece to combine with a different skill in the next three months?" If the honest answer is "no," I write a single skill and don't apologize for it. Composition is about reuse, extensibility, and testability — and those need to actually be needed, not assumed. Some of my most reliable skills have stayed as monoliths for over a year because they hit a sweet spot of stability and isolation. Knowing when not to compose is just as much a part of good Skill design as knowing when to do it.
A useful counter-test: imagine a junior teammate who has never seen your skill ecosystem. If they ask "why are these split?" and you can give a one-sentence answer about reuse, branching, or testability, the split is earning its keep. If you find yourself describing the original problem instead, you split too early.
I'll close this section with a confession: I split too early on my first major composition project, and the cleanup took weeks. The pieces were technically correct but conceptually arbitrary, which made the system harder to reason about, not easier. The lesson stuck — composition has to be motivated by an actual force of change, not by a general aesthetic preference for "small things." Wait until you can name the force, then split. The line between "appropriately decomposed" and "scattered" is thinner than most posts about software design admit.
A first move you can make today
You don't need to adopt every pattern at once. The single most useful first step is chaining two existing skills with Pipeline composition. Add one sentence to skill A's body suggesting skill B as a follow-up. Add one sentence to skill B's body declaring A's output path as a precondition. Run a small workflow end to end. That's enough to feel why composition pays off.
When you reach a third skill, introduce a meta-skill. Three is the threshold where a human can no longer reliably hold the sequence in their head, and where a coordinator starts earning its place.
Skill composition is closer to assembling a small specialist team than to building a single generalist. A team of three good specialists who hand off cleanly will outperform one overloaded expert almost every time. Pick one SKILL.md you wrote last month, and add a single line about which skill should run next. That's the doorway.
A final thought worth sitting with: the leverage from composition compounds. The first chained pair you build saves a few minutes of orchestration. The fifth saves entire afternoons because the pieces snap together in combinations you didn't originally plan for. That compounding only happens if each individual skill is small enough to recombine. So when you're choosing between "make this skill do one more thing" and "extract that thing into its own skill," remember that the second option is buying you optionality. Most of the value comes later, in workflows you haven't thought of yet, executed by future-you who will quietly thank present-you for keeping the pieces small.
Share
Thank You for Reading
Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.