Skills vs. Rules in Claude Code — What Auto-Loads, What Loads on Demand, and the Context Cost

Inside a Claude Code project’s .claude/ folder, rules and skills sit side by side: Markdown files that look almost identical — and behave in exactly opposite ways. That contrast is what Claude Code skills vs rules comes down to: rules are fully in context at every session start; a skill costs next to nothing until someone invokes it. Get the two mixed up and you either stuff everything into rules and pay for it every session — or expect a skill to “just apply” without ever being invoked.

This article draws the line sharply — using the .claude/ folder of a real project, the open DI² starter kit.

The essentials up front:

  • Rules (CLAUDE.md + .claude/rules/) load automatically at session start — full content, every session.
  • Skills (.claude/skills/) are on demand: only the description line sits in context; the body loads on invocation — via slash command or because Claude itself finds the description matches the task.
  • The context-cost table: what costs how much, and when — including the two dials paths: (rules) and disable-model-invocation (skills).
  • The decision rule: what must always apply becomes a rule; what runs on command becomes a skill.
  • Why a skill still names the rules — and why rules are a living document.

Prerequisites: A Claude Code project with a .claude/ folder; the examples come from the open DI² starter kit on GitHub. Mechanics as of July 2026, verified against the official Claude Code docs — the details are version-dependent, the principle behind them is not.

Contents

Rules: the Constitution That Is Always in Context

Rules are everything Claude Code loads into context without being asked, before the first prompt is processed: the project’s CLAUDE.md (plus a personal ~/.claude/CLAUDE.md and an optional, gitignored CLAUDE.local.md) and every file under .claude/rules/. This is what it looks like in the starter kit:

.claude/
├── CLAUDE.md                  project frame (+ @imports)
├── rules/
   ├── language.md            always loaded
   ├── security.md            always loaded
   └── sql/postgres/…         always loaded
└── skills/
    ├── requirements/SKILL.md  only the description in context
    ├── backend/SKILL.md       only the description in context
    └── deploy/SKILL.md        only the description in context

The consequence of the first half of this tree: rules apply to every action — including the ad-hoc request (“change table X”) that uses no skill at all. That is exactly why conventions belong there: a language policy, a security floor, a SQL style. If the same convention lived only inside a skill text, it would silently not apply outside that skill.

This loading is a snapshot: the session works with whatever the files contained at session start. This snapshot semantics will matter again at the end of the article — it explains why a rule edit does not take effect immediately.

Two details about CLAUDE.md: it can import further files via @path/to/file.md — those load at session start as if they were written inline. A regular Markdown link ([text](file.md)) does not import; it is just a reference Claude may follow when needed. And: the price for all of this is the context window — more on that in a moment.

Skills: the Toolbox on Demand

A skill is a subfolder under .claude/skills/ with a SKILL.md: a frontmatter block with name and description at the top, and below it the body with the actual instructions — a procedure, a workflow, a checklist.

  1: ---
  2: name: deploy
  3: description: Rolls out an environment  asks for the target, checks the preconditions.
  4: ---
  5: (the body starts here  it only loads into context on invocation)

At session start, almost nothing happens with this folder: only the name and description land in context — a few tokens per skill. The body stays on disk until the skill is invoked. Only then does it load into the conversation in full.

There are two ways to invoke a skill, and the second one is often overlooked: either the user types the slash command (/deploy) — or Claude invokes the skill itself, because the description matches the current task. The description is therefore not just documentation but the trigger for automatic matching: a sharp description (“Rolls out an environment …”) gets matched reliably, a vague one (“Helps with deployment stuff”) does not. To prevent self-invocation for a skill — say, because a workflow step should deliberately only start on the user’s command — set disable-model-invocation: true in the frontmatter: the skill is then invisible to Claude and costs zero context until the user invokes it explicitly.

A word on history: the older slash commands (.claude/commands/*.md) have been merged into skills — both forms work and produce the same /name, but skills can do more (their own folder with supporting files, frontmatter controls) and are the recommended form.

The Context-Cost Question

Why not just put everything into rules — then at least it always “applies”? Because every rule is paid for in every session — including the session that has nothing to do with its topic. A project without a database that still loads the full SQL ruleset burns context window for nothing. And the budget is not only a cost question: the fuller the context, the weaker the model’s adherence to each individual instruction.

Context timeline in two snapshots: at session start, CLAUDE.md and all rules files sit in the context window as full blocks, with only a thin description line per skill; after invoking /deploy, the body of skills/deploy/SKILL.md joins as the single new block.

The mechanics at a glance — with the two dials that sit between “always in full” and “not at all”:

ArtifactLoad timeWhat sits in contextCost while unused
CLAUDE.md (+ @imports)session startfull contentfull, every session
Rule without frontmattersession startfull contentfull, every session
Rule with paths: patternonly on a matching filefull content after the matchnothing until the pattern matches
Skill (default)session start, header onlyname + descriptiona few tokens per skill
Skill with disable-model-invocation: trueonly on invocationnothingnothing
Skill, invokedon /name or self-invocationfull body

The paths: dial deserves a second look. It takes a glob pattern — a simple syntax for matching files and directories via wildcard characters instead of spelling out every filename. The name comes from the old Unix command glob (“global”), which expanded filenames. The most important wildcards:

PatternMeaningExample matches
*any number of characters (except /)*.sql → customer.sqlorder.sql
**any number of directory levelsdb/** → everything below db/
?exactly one arbitrary characterfile?.md → file1.mdfileA.md
[abc]one of the characters in the bracketsv[12].sql → v1.sqlv2.sql
{a,b}alternatives*.{yml,yaml} → both extensions

You have met this syntax before — .gitignore (*.lognode_modules/) works exactly the same way. A rule with paths: ["db/**"] in its frontmatter loads only when Claude touches a file from db/ or any subdirectory below it, however deep — the official middle ground for rulesets that concern only part of the project.

Rule or Skill? The Decision Rule

The one-liner everything boils down to:

What must always apply belongs in a rule. What runs on command belongs in a skill.

Three test questions turn this into a decision:

  1. Must it also apply to ad-hoc requests? A naming convention, a security floor, the project language — none of that may depend on whether someone invokes a skill. → Rule.
  2. Is it a procedure with steps, inputs and checkpoints? Specifying a feature, rolling out an environment, filing a bug — you invoke that when it comes up. → Skill.
  3. Is it a fact that changes? Stack values, hosts, commands belong in the rules as fact files (they must always be at hand) — but procedures working with them re-read the file at execution time instead of relying on the context copy from session start.

In the starter kit the split looks like this: language.mdsecurity.md and the SQL conventions are rules; /requirements/backend/qa and /deploy are skills — eleven workflow steps plus cross-cutting helpers, each entering the context only when its turn comes.

Why a Skill Still Names the Rules

Anyone reading real skill files stumbles over lines like “Read .claude/rules/stack.md” — and easily draws the wrong conclusion that a skill has to name the rules for them to apply at all. That is the most common misconception in this area, and it is wrong: a skill runs in the main conversation, and the rules have been loaded there all along — since session start, independent of any skill.

The mention has two other jobs:

  • Freshness: the context copy of a rule is a snapshot from session start. For fact files like stack.md, re-reading at execution time pays off — it picks up changes made since the session began.
  • Focus: among many loaded rules, “follow sql/postgres/procedures.md” directs attention to the one that governs the current step — important when similar rulesets sit side by side in context.

One distinction belongs here: for subagents (separate instances the model spawns for subtasks), the same line is in fact load-bearing — a subagent does not inherit the conversation and does not automatically receive the .claude/rules/ files; without the explicit read instruction it simply does not know the convention exists. But that is its own topic with its own mechanics.

Rules Are a Living Document

A project’s rules are not a rulebook written once and then administered — they grow through use. The feedback loop is the same as for any other living document: whenever something about a result is off — a phrasing, an approach, a practice that should apply always or only in one specific case from now on — don’t just fix the one spot; tell the agent to update the rule along with it: “put that into the rule.” Every correction thus moves from the single case into the convention, and the same point never has to be raised twice.

The loading mechanics give this loop one quirk you need to know: a rule edit takes effect in the next session. The context is a snapshot from session start — the running session keeps working with the old version until you start a new one or explicitly have the changed file re-read. If you wonder why “the session ignores my new rule”, you are not seeing a malfunction but exactly this snapshot semantics.

What the loop looks like in practice is shown by the sibling article on deploying a SQL schema without a migration tool: two deploy conventions of the starter kit — convergent schema evolution and the immutability of applied transition scripts — came about exactly this way: first a discussion point about a concrete result, then a rule.

That closes the loop: good Claude Code setups usually consist of a few stable rules and many small, task-specific skills. The clearer this separation, the smaller the context stays — and the more predictably the agent works.

FAQ

What is the difference between rules and skills in Claude Code?

Rules (CLAUDE.md and the files under .claude/rules/) load automatically and in full into the context at every session start and apply to every action. Skills (.claude/skills/) load on demand: only the description line sits in context, and the body joins on invocation — via slash command or because Claude finds the description matches the task.

When should something be a rule, and when a skill?

What must always apply — conventions, security floors, the project language — belongs in a rule, because only rules also apply to ad-hoc requests without a skill invocation. What starts on command as a procedure with steps and checkpoints — specifying a feature, rolling out, filing a bug — belongs in a skill.

Does a skill cost context even if I never use it?

A few tokens: at session start only its name and description sit in context, the body stays on disk. With disable-model-invocation: true in the frontmatter the cost drops to zero — the skill is then completely invisible until you invoke it explicitly.

What belongs in CLAUDE.md, and what in the rules?

Both load automatically — the difference is organization, not mechanics. CLAUDE.md carries the project frame: what the project is, how it is structured, where things live. Conventions belong in individual files under .claude/rules/ — one topic per file, so rulesets can be pruned deliberately or limited to parts of the project via a paths: pattern.

Why doesn’t my rule change take effect?

Because the context is a snapshot from session start: the running session has the old version loaded and keeps it. After a rule edit, start a new session — or have the changed file explicitly re-read in the running one.

Are rules and skills specific to Claude Code?

The names and the frontmatter, yes; the principle, no: auto-loaded base context plus tools fetched on demand shows up in practically every agent setup, just under different labels. The decision rule — always-applies versus on-command — carries over unchanged.