06. Skills

Skills Are the Manual: Where Concrete Best Practices Live

The last post gave the agent its foundation (System Prompt), and left one gap unfilled: knowledge that's really a methodology — "how to write this kind of article well" — doesn't belong in the system instructions. So where does it go? This post fills that gap. The main character: Skills.

👆 You are here
👆 You are here

🪧 A Knowledge Base You Summon On Demand

Last post's framing: the system prompt is "a constitution written into the DNA," holding only the persona and discipline that never change across the whole app. But something like "what makes an essay land" or "how to explain a technical topic clearly" — the methodology for writing a specific kind of piece well — is knowledge that keeps accumulating and keeps changing. Stuffing that into system instructions clearly doesn't fit. It needs somewhere to live that doesn't take up space most of the time, but can be summoned instantly the moment you're writing that kind of piece.

In Claude's world, that "somewhere" is a Skill.

When I first ran into this, I actually conflated Skill and Sub-agent for a while, and went back and forth on whether this methodology should be built as a Skill or handed off to a sub-agent. Turns out these are two entirely different dimensions. This post first pulls the two concepts apart, then walks through how Skills solve a specific problem: with 16 built-in writing-genre conventions baked into the product, how do you guarantee the agent always reaches for the right one?

🧭 The Core Idea: Get Skill's Role Straight First

A Skill is a reference manual you pick up and put down as needed. A Sub-agent is a clone you send out to do a job. They're orthogonal, not a choice between one or the other.

Here's a side-by-side of what actually separates them:

Agent Skill (the manual) Sub-agent (the clone)
What it is A SKILL.md file holding a methodology for "how to do this kind of thing" An independent agent instance
Context Shared with the main agent's current context — flipped open in place Fully isolated — runs in a brand-new conversation, only reports a conclusion back
Weight Light. Only a one-line description loads at startup; the full text expands only when used Heavy. Requires spinning up a whole new context and running its own pass
Good for Reusable methodology — "teach the agent how to write this kind of piece" Farming out an independent subtask — research, final review

Here's an analogy: a Skill is like a stack of cheat sheets I hand my writing copilot — flip to the essay page when writing an essay, the technical-writing page when writing technical prose. It's still the same copilot, just with a reference manual on hand now. A Sub-agent is more like hiring a separate specialist — send them off to a library to dig through a pile of material, and they hand back one page of summary when they're done; the digging never clutters my own desk.

If I'd mistakenly built the "essay methodology" as a sub-agent, every essay would need a fresh isolated context spun up, with the methodology itself round-tripping back as a "result" — heavy and awkward. Flip it around, and forcing "dig through dozens of reference documents for research" into a Skill would flood the main writing context with all that noise. Once you separate "shared vs. isolated" and "light vs. heavy," which one to use becomes obvious. This post is Skills only — Sub-agent gets its own dedicated post, post 12.

🔩 How Claude Code Packages This "Manual"

Concept settled — now look at how Claude Code already does this. The seventh post in the Learn Claude Code source-walkthrough series takes the Skills mechanism apart in detail. A Skill is one file: .claude/skills/<name>/SKILL.md. The file itself isn't complicated: a few lines of metadata at the top, the most important being a name and a description — that description is critical, since it's essentially the model's only basis for deciding "should I open this manual?", so it needs to be written so its purpose is obvious at a glance. The body of the file is the methodology itself. If needed, you can also attach a few reference files in the same subfolder. That's the whole of a Skill: one plain markdown file.

There's one more nice property to this file: it can be explicitly invoked by the user via a /name slash command, or the model can decide on its own whether to open it. At startup, Claude Code discovers and registers all these SKILL.md files from a few user-level and project-level locations, based on config — and they're all on standby, ready to go.

I originally assumed "commands" needed a separate, older .claude/commands/ file format. Turns out the official docs already mark that format as deprecated, and recommend unifying everything under SKILL.md, because one file now supports both "the user types a command" and "the model calls it on its own." So in SmartWriter, everything that reads as a "command" is really built as a Skill. More on this in post 7, on Slash Command.

🛠 The SDK's "Progressive Loading": A Manual That Doesn't Take Up Space Most of the Time

Once you have enough Skills, you can't stuff them all into context at once — that fills up fast. The SDK follows the same idea Claude Code does: progressive loading, split into two stages:

  1. At rest: a Skill normally only has its "name + one-line description" hanging in a lightweight index. That description is cheap — as stable and cacheable as the system prompt. The model normally only knows "there's a manual here, covering X," without knowing any of the detail.
  2. Triggered: once the model decides (or the user explicitly asks via /name) that this manual is needed, it calls a Skill tool that pulls back the full text of SKILL.md and reads it. The full text only enters context at that point.

The upside is obvious: 16 genre manuals can all sit registered, and at rest they only cost 16 one-line descriptions — nowhere near enough to blow out the context window. Only when one's actually needed does it expand and load — fast, and cheap.

📐 Going deeper · the "page you had open" can get quietly torn out by compaction (skippable)

Worth noting: a Skill's full text enters the current conversation in the form of a "tool result." And we covered this in post 2 — once context triggers compaction, early tool results are exactly the kind of thing that gets summarized away.

Which means: a long writing task that triggers compaction midway can lose the "genre manual" it had open, and the model quietly "forgets" it's supposed to keep writing by that genre's methodology. This is the exact same pitfall I ran into in post 4, when I abandoned "inject the profile via a tool result" in favor of routing through CLAUDE.md instead.

So for something like "genre methodology," which has to stay available the whole time, I didn't rely solely on "the model deciding on its own to call the Skill tool." That worry is the direct motivation behind the "deterministic injection" design later in this post.

One more constraint worth noting on its own: the SDK's skills list (which Skills are even in the candidate pool) is locked in at the moment a session is created — it can't be dynamically edited item-by-item mid-session. Which means "should this particular manual be in the candidate pool this time" has to be decided at the very start of a task, before the first character is even written.

📚 What SmartWriter Does: Splitting Skills into Three Categories, Not One Pot

Now, SmartWriter's own approach. I started out thinking about every kind of Skill as one big lump, and it felt chaotic — but once I sorted it out, three clean categories emerged:

Category What it is Examples Relationship to the profile
① Mode Skills (actions) Cross-genre, general-purpose writing actions Polish / Expand / Restructure / Reformat / Research / Translate + one catch-all, seven core actions + one standalone Xiaohongshu-style rewrite Unrelated — this is methodology for "how to edit," not what to write
② Genre Skills (knowledge) Structure, pacing, and common pitfalls for "writing this kind of piece well" 16 built-in (essay, technical writeup, industry report...) + user-defined Paired with a genre profile: the profile is your personal style, the Skill is the general-purpose methodology for writing this genre well
③ Flow Skills (orchestration) Chains actions and knowledge into one workflow A customized doc-coauthoring flow (research → outline → draft → final review) The orchestrator — carries no genre quality on its own

⚖️ The tradeoff · splitting by platform first was the wrong call

Early on, I split writing-knowledge Skills by "long-form for a public account / short-form for Xiaohongshu / technical docs." Looked reasonable at first glance? It was actually mistaking "platform" for "genre" — a category error.

The problem: the same product-tech article might get published to both a public account and Xiaohongshu. Would that mean writing two separate "how to write this well" methodologies, evolving independently and contradicting each other? Obviously not workable. What actually determines "how content is organized, what tone and logic it uses" is genre — the platform only determines "what it looks like at the very end."

I eventually switched to splitting by genre, and pushed "platform" entirely down to the last-mile export step (aside from tone adaptation, most of that work is done by deterministic formatting tools, not model creativity). Once that boundary — genre stays genre, platform stays export — was drawn cleanly, the whole Skill system finally made sense.

With the categories sorted, the next question is how each actually gets implemented, and how far you can push it. The difficulty across these three escalates: mode Skills are the least effort, flow needs some insurance, genre is the hardest. Let's walk through them in that order, easiest to hardest. There's a thread running underneath: the more error-prone a judgment call is, and the higher the cost of getting it wrong, the more I take that judgment away from the model.

🟢 Mode Skills: The Least Effort, Thanks to the SDK

Starting with the easiest. Mode Skills are a set of cross-genre, general-purpose actions: polish, expand, restructure, research, translate, plus a standalone "Xiaohongshu-style rewrite," which does content-level reformatting (clickbait titles, conversational tone) — that's a different job from pure format adaptation, so it's kept separate, explicitly user-triggered, and never folded into export.

Implementing these is basically "follow the SDK's default playbook": write one SKILL.md per action, spelling out that action's methodology clearly (the "polish" one, for instance, spells out exactly how to tighten word choice, adjust pacing, cut redundancy). Then it can be explicitly invoked by the user with a slash command like /polish, or the model can decide on its own, from what you said, whether it's needed. The output contract is clear too: writing actions (polish, expand, restructure) update your piece directly.

This category is basically usable out of the box — I barely fought the SDK on it, and spent most of my effort making each SKILL.md's content genuinely solid. Because with actions like "polish" or "expand," user intent is unambiguous, and the model rarely misreads it — even when it occasionally judges wrong on its own whether to trigger, the cost is low (worst case, you just say it again). The one hiccup: slash commands like /polish can get silently swallowed if handled wrong — I'll dig into that gotcha in the next post.

🔗 Flow Skills: Stringing Actions into a "Script"

One step up from mode: flow Skills. What makes these more complex is that mode is a single action, while flow orchestrates a chain of actions and knowledge into one workflow. The one I pre-installed and customized strings together "research → outline → draft → final review" — a customized doc-coauthoring flow.

A flow Skill isn't a pipeline hard-coded in software — it's more like a script the model performs on its own. At the "draft" step, it loads the matching genre Skill; at the step that needs source material, it sends a sub-agent off to research. The whole thing is orchestrated by the model reading this script and driving itself forward, not a DAG I hard-coded.

Customizing doc-coauthoring mainly meant three things: generalizing its original tone (built for "documents" — docs, proposals, specs) toward "articles / columns"; wiring in our own profile-injection rules and the final-review step; and having certain steps call our own deterministic tools (format validation, profile assembly, and so on).

Since the model is "performing the script itself," there's a real risk of dropping a line — skipping a step, or running them out of order. That's not a big deal for most steps, but for a mandatory critical step (the clearest example: final review — required before a piece is marked done), you can't rely entirely on the model's own discipline. So for these critical checkpoints, I use a hook to weld a backstop in (what a hook is and how that welding works gets its own post, post 10) — if it's skipped, the hook catches it and forces it back in. Compared to mode Skills' "hand it confidently to the model," flow Skills are where things start getting more serious — critical steps need a deterministic safety net.

Worth a quick aside: users can also build their own custom workflows. They can drag and drop a few mode Skills into an order and assemble their own flow. This sounds like it needs a runtime orchestration engine, but it doesn't: the core implementation is stitching the selected steps' instructions, in order, into a template, and generating a new flow SKILL.md. Think of it as "writing a new script," not "building an orchestration machine."

At this point, for mode and flow, the SDK's default playbook ("model decides autonomously + /name") plus a hook backstop for critical steps is basically enough. But the third category, genre Skills, is where that default playbook stops being flexible enough. Let's dig into why it's "a bit different."

🎯 The Real Problem: 16 Genres — How Do You Guarantee It Uses the Right One?

Genre Skills run into an unavoidable problem: writing is about as personal as it gets, and even with 16 genres already built in, users will almost certainly define more of their own. So, for any given piece, which manual should actually get opened?

Following the mode/flow logic, the intuitive move is to keep "trusting the model": throw every genre Skill the user has enabled into the candidate pool, and let the model pick based on that one-line description. I actually tried this, and the results weren't great:

  1. Adjacent genres confuse the model. "Opinion commentary" and "career reflection," "personal essay" and "life logging" — these genres have naturally similar descriptions, and having the model tell them apart from a single line, out of a candidate pool, has a real error rate. And once it picks wrong, that takes effect silently — the output drifts off, and the user has no idea why.
  2. It can end up fighting the profile. Remember post 4? I already inject a "genre profile" into CLAUDE.md, keyed to the genre. If the model then independently picks a different genre's Skill, you get a kind of split personality — the profile says this is genre A, but the Skill is operating as if it's genre B.

So for this category, I pushed "deterministic takeover" all the way: genre Skills don't let the model pick blindly — instead, it's a deterministic "single-choice injection." The logic in one sentence: first, a deterministic decision chain settles what the current genre actually is; only then does it check whether the user has that genre's Skill enabled.

Broken down, the flow is:

  1. First, a layered, graceful-degradation genre-inference chain (genre_inferrer) determines the current genre — or determines that it can't.
  2. If it successfully determines a specific genre: check whether the user has that genre's Skill enabled in settings. If yes, that one Skill gets added to the candidate pool and deterministically injected; if not, it isn't added, but the genre profile still gets injected as usual (the two are decoupled and don't block each other).
  3. If it can't determine one (inference failed, low confidence, degraded): no genre Skill gets loaded at all. Better to load nothing than force-fit one that might be wrong.

For a judgment this high-value and this error-prone, the goal is to cover it with deterministic logic wherever possible, and only fall back to letting the model "pick" as a last resort. As for "how do you determine the genre both quickly and accurately," I added two earlier steps to the product: users can directly pre-select a genre from a dropdown when creating a new task (the fastest, cheapest shortcut — skips model classification entirely), and a manually maintained alias list ("interview," "Q&A transcript" appearing in the first sentence gets classified straight to interview-record, no model call needed). Both exist for the same purpose: trigger the model classification call as rarely as possible.

So where does the methodology manual come from when a user creates a genre outside the built-in 16 (say, "product retrospective")? I didn't let the writing agent improvise that manual on the spot — instead, I built a dedicated background "generator" Skill (a meta-skill) that follows a fixed procedure: research the characteristics of the new genre, reference the format of the 16 built-in manuals, draft a methodology, and produce a properly-formatted SKILL.md on disk. There's no way to know a custom genre in advance, but generating its manual is itself a "standard action, fixed format" job — exactly the kind of thing well-suited to a deterministic generator.

🔧 Gotcha · tested with a real probe: leaving it to the model to proactively open the manual only worked about half the time

Once I'd settled "which genre Skill to use," I originally kept a backup plan in mind: "even without deterministic injection, surely the model would go call the Skill tool and open the manual on its own?" To check, I wrote a small dedicated test for exactly this.

The result wasn't good: even with the genre already pre-selected for the task, the model's rate of proactively calling the Skill tool and actually opening the matching manual was only around 50%. Which means half the time, that carefully written genre methodology never got opened at all. Part of the root cause: the genre manual's one-line description was too short — not enough of a signal to reliably trigger the model into acting on it.

The fix was to stop betting on the model's own discipline entirely: I take the selected genre manual and splice its full text directly into the very front of the first message of the conversation (wrapped in a "genre methodology" marker), feeding it in deterministically. At the same time, I keep the "model calls it on its own" path alive too — both run together, and whichever one lands, lands (in engineering terms, belt and suspenders — belt plus suspenders, your pants aren't falling regardless). And tying back to the deep-dive box above: this prefix can get lost after compaction, so I also added a hook that re-injects it automatically after compaction, as a backstop. For anything that "absolutely must happen," don't bet on the model's own discipline — weld it in with a deterministic mechanism.

⚖️ Wrapping Up: A Slope Where "More Critical" Always Means "More Ownership"

Looking back at how these three categories of Skills got implemented, they're really three points on the same slope, worth lining up side by side:

⚖️ The tradeoff · three categories of Skill, escalating by how much certainty each demands

How much goes to the model How much I take over Why split it this way
Mode Skills Almost entirely (autonomous + /name) Almost none Intent is clear, mistakes are cheap — trust the model
Flow Skills Orchestration handed to the model, "performing the script" Hook backstop on mandatory critical steps Fine to let go on the big steps, but something like final review can't afford to be skipped
Genre Skills None — the model doesn't pick Both determination and injection fully taken over Adjacent genres are easy to confuse, and a wrong pick fights the profile and derails the whole piece

The Skills mechanism itself is genuinely flexible and "smart," and it nudges you toward handing judgment calls to the model. But when it comes to actually building a product, I care about something else more: grade every judgment call by the cost of getting it wrong, and the higher that cost, the more deterministic machinery it deserves to have backing it up. This is the same logic as the last post's "drop Bash, weld safety into the tool layer": subtract at the critical points, add certainty there, and save the model's actual latitude for the creative work that genuinely needs it.

That's this post. You may have noticed I kept bringing up "the user can summon a Skill with /name," and planted a landmine about a slash command getting swallowed. So what actually happens between the moment a user types that / and the moment it actually fires?

Next post, we take apart Slash Command — and the core idea behind it: the output contract. Let's keep going.