Skip to content

Claude Code Skills vs CLAUDE.md vs Prompts: What's the Difference?

Purpose

This post explains the difference between Claude Code skills, CLAUDE.md, and system prompts. I keep seeing the three words used as if they meant the same thing, and that confusion is what makes the online “skill” files look so broken. They are not skills at all. They are system prompts mislabeled.

Direct Answer

They live at three different layers of Claude Code:

  • CLAUDE.md is project-wide, always-loaded context. It holds global tone, repo conventions, and pointers to important files. It is the README for the agent.
  • System / system-level prompts are global, always-on instructions set by the runtime or the user. They shape the model’s persona and behavior across the whole session.
  • Skills are small, named, on-demand modules the agent decides to load. Each skill is atomic, scoped, and has a clear condition under which it should fire.

Use CLAUDE.md for project rules the agent must always know. Use the system prompt for global persona and behavior. Use a skill for an atomic correction, procedure, or tool bundle that only matters in a specific situation.

Architecture diagram comparing a fixed connector node (n8n LLM Node with templated prompt, single input and single output) against an autonomous subagent node (Claude Code step with a goal, a model loop, and tools such as filesystem, bash, and MCP)

I use this mental model: a system prompt and a CLAUDE.md are the always-on rails. A skill is the side-tool the agent picks up when its description matches the task.

Environment

  • Claude Code (current release, with skills support)
  • A project repo with CLAUDE.md at the root
  • A skills folder at .claude/skills/<name>/SKILL.md for on-demand modules

What happened?

I started using CLAUDE.md for everything. I put the project stack, the lint rules, the deploy command, the bug-report template, and the “no comments in code” rule, all in one file. The file grew past 300 lines. Every conversation started by reading all 300 lines, and most of them were irrelevant to the current task.

Then I tried the other extreme. I put everything into a “skill” file that looked like a system prompt. The agent loaded it once and ignored most of it. The behavior did not change.

The problem in both cases was the same. I was using the wrong layer.

How to solve it?

I split my project config into the three layers based on one question: when does this rule need to be active?

Solution 1: Put always-on project rules in CLAUDE.md

CLAUDE.md
# CLAUDE.md
## Stack
- Python 3.12, FastAPI, SQLAlchemy Core (no ORM), PostgreSQL.
- Use `python -m venv venv` for the virtual environment.
## Code style
- No type comments. No docstrings on obvious functions.
- All SQL lives in `data_access/`. Never inline raw SQL in routes.
## Logging
- Console + daily rotated log files in `logs/`.

The agent reads this on every turn in the repo. It costs context, but the cost is worth it because every rule here applies to every task.

Solution 2: Move per-project procedures out of CLAUDE.md and into a skill

A bad CLAUDE.md looks like this:

CLAUDE.md (bad shape)
## Skill: deploy-to-staging
Run `rsync -avz --delete ./build/ deploy@staging:/srv/app/`.
Then run `ssh deploy@staging "systemctl restart bswen-manage"`.

That is a procedure, not a project rule. It only matters when the user asks to deploy. The better shape is a skill:

.claude/skills/deploy-staging/SKILL.md
---
name: deploy-staging
description: Use when the user asks to deploy the current build
to the staging server. Bundles the rsync and the service restart.
---
Run, in order:
1. `rsync -avz --delete ./build/ deploy@staging:/srv/app/`
2. `ssh deploy@staging "systemctl restart bswen-manage"`
3. Tail `logs/$(date +%F).log` for 10 lines and paste any error
into the reply.
If step 1 or 2 exits non-zero, stop and report. Do not retry
automatically.

CLAUDE.md is back to project rules. The skill is loaded on demand. The agent sees the description, decides the trigger matches, and reads the body.

Solution 3: Keep persona in the system prompt, not in a skill

.claude/skills/senior-engineer-persona/SKILL.md (do not write this)
---
name: senior-engineer-persona
description: Be a senior engineer.
---
You are an expert full-stack developer with 20 years of experience
in React, Node.js, and TypeScript. Always write clean, maintainable
code.

This belongs in the system prompt, not in a skill. It is a persona, not an atomic procedure. Putting it in a skill means the agent has to decide when “be a senior engineer” is the right trigger, and the answer is almost never. Move it to the system prompt or the CLAUDE.md voice section.

The reason

I think the three layers exist because they answer three different questions:

LayerWhere it livesWhen the agent sees itGood fitBad fit
System promptRuntime / userAlways, session-widePersona, global behavior, hard rulesOne-off procedures, project trivia
CLAUDE.mdRepo rootAlways, when working in the repoProject conventions, file map, repo voiceAtomic corrections, scripts
Skill.claude/skills/<name>/SKILL.mdOn demand, when the agent decides the description matchesAtomic correction, procedure, script bundleProject-wide rules, persona

The cleanest test for “is this a skill?”:

  • If it must always be on, it is CLAUDE.md or system prompt.
  • If it only matters in a specific situation, it is a skill.
  • If it could be one command or one file the agent runs, it is a skill.

Why This Matters

  • Cost. CLAUDE.md and the system prompt are loaded every turn. Putting a 200-line procedure there is expensive. Putting it in a skill is cheap, because the agent only loads it when relevant.
  • Discoverability. A skill’s name and description let the agent pick it on its own. A CLAUDE.md rule has no such trigger, so the model has to remember it from the always-on context.
  • Composability. Skills are atomic. You can copy a skill from one project to another. CLAUDE.md is repo-specific by design.

Common Mistakes

  • Putting persona in a skill. That belongs in the system prompt or the CLAUDE.md voice section.
  • Putting per-project rules in a skill. They will not fire on other repos. Either move them to CLAUDE.md or name the skill with a project prefix and accept the scope.
  • Putting one-off tasks in a skill. If you will only use it once, type the instruction. A skill earns its place only when the same text is re-typed more than once.
  • Treating a skill as a hook. A skill is not a hook. It is content the agent reads when it decides the trigger matches.
  • Skills vs slash commands. A skill is passive. The agent decides to load it. A slash command is active. The user types it. Some configs let you bind a slash command to a skill, but they are still two different mechanisms.
  • Skills vs subagents. A subagent is a separate Claude session with its own context and tools. A skill is a chunk of text the current agent reads. Use a subagent when the work needs isolation, a skill when it needs a recipe.
  • Skill discovery. The agent matches the skill description to the current task. Be specific. “Be a senior engineer” matches almost everything. “Use when finishing a code edit. Strips decorative comments” matches one thing, which is what you want.

Summary

In this post, I explained the difference between Claude Code skills, CLAUDE.md, and system prompts. The key point is that they live at three different layers. CLAUDE.md is always-loaded project context. The system prompt is always-loaded global behavior. Skills are atomic, on-demand, named modules the agent loads by description match. If you find yourself writing “skill” but mean “global rule” or “persona”, put it in the right layer. If you find yourself re-typing the same block of text, that is a skill.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments