Skills vs Rules vs Reads: The Claude Code Subagent Caching Cheatsheet


You have shared content you want every Claude Code agent to know. Coding standards. Accessibility rules. Brand voice guidelines. A list of things that will get your API key revoked.

Where does it go? You have at least four options:

  1. The agent body (markdown in .claude/agents/xxx.md)
  2. .claude/rules/*.md files
  3. A skill at .claude/skills/<name>/SKILL.md (loaded via skills: frontmatter)
  4. A Read call in the agent’s startup checklist

From a “the content is available” standpoint, these look interchangeable. From a caching and subagent reachability standpoint, they are radically different. Two of them work for subagents; two of them don’t. One puts your content in the most cacheable position; another puts it in the least cacheable position.

This is the cheatsheet nobody has written.

What a subagent actually receives

The official docs say it plainly: “Subagents receive only this system prompt (plus basic environment details like working directory), not the full Claude Code system prompt.” [1]

That sentence is doing a lot of work. Here is what it unpacks to:

Subagent context:
  System prompt:
    - Subagent harness (~3-5k tokens)
    - Memory file (if `memory:` is set in frontmatter)
    - Skills content (if `skills:` is set in frontmatter)
    - Agent body (the markdown below the frontmatter)
  Project context:
    - CLAUDE.md (loaded via settingSources)
  Messages:
    - Task prompt (from the parent agent)
    - [conversation begins]

What is missing from this list: .claude/rules/*.md. Rules files do not reach subagents. They are a main-session-only feature.

Also missing from the list: inherited MCP tool definitions. The tool prefix is a separate layer that sits above the system prompt in the cache hierarchy — and it’s a significant cost factor if you’re not managing it explicitly. See The MCP Tool Prefix Trap.

Most people building multi-agent pipelines in Claude Code don’t know this. If you put your shared coding standards in .claude/rules/ and your subagents start ignoring them, now you know why.

The cheatsheet

Where you put itReaches subagents?Caches across agent types?
Agent body (markdown below frontmatter)YesNo — unique per agent type
.claude/rules/*.mdNoN/A — main session only
.claude/skills/<name>/SKILL.md (listed in skills: frontmatter)YesYes — if same skill is listed
Read call in startup checklistYesNo — re-read per spawn
CLAUDE.mdYes (via settingSources)Yes — same per project
memory: frontmatterYesNo — memory varies per agent

The two columns that matter:

  • Reaches subagents determines whether your content arrives at all.
  • Caches across agent types determines whether you’re paying for that content once or on every spawn of every agent type.

Where to put what: the decision tree

“Every agent should know this.”

Put it in a skill with skills: in each agent’s frontmatter.

# .claude/skills/shared-rules/SKILL.md
---
name: shared-rules
description: Cross-project rules every agent should follow.
user-invocable: false
---

# Shared Rules

## Accessibility
- Never use yellow and green together as status indicators.
- Every status indicator needs a symbol + text label alongside any color.

## Python tooling
- Use uv/uvx for all Python package management. Never pip.
# .claude/agents/web-dev.md
---
name: web-dev
description: Front-end development agent
tools: Read, Write, Edit, Bash, Glob, Grep
skills:
  - shared-rules
---

The full skill content is injected into the subagent’s system prompt at startup — “not just made available for invocation,” as the docs put it [2]. Any agent that lists the skill gets it cached for free after the first spawn.

Set user-invocable: false so it stays background knowledge rather than appearing as a slash command.

“This is loka/project context — architecture, conventions, tech stack.”

Put it in CLAUDE.md. It reaches both the main session and subagents via settingSources. It caches across all agent spawns within a project. Keep it lean — a product summary and pointers, not the full documentation.

“This is specific to one agent’s role.”

Put it in the agent body. It caches across spawns of that agent type, but not across other agent types. That is fine; it is role identity, not shared knowledge.

“This is dynamic, per-task data.”

Use a Read call. The agent reads it when needed, the result lands in messages, it does not cache across spawns — and that is appropriate for content that changes per task.

“What about .claude/rules/?”

Use it for main-session context: working agreements, session guides, project conventions the human wants to see enforced. Do not rely on rules files for anything you need subagents to follow. They will not see it.

The most common mistake

Here is the pattern people land on naturally:

# .claude/agents/code-reviewer.md
---
name: code-reviewer
---

# Code Reviewer

## Startup Checklist
1. Read `.claude/rules/coding-standards.md`
2. Read `.claude/rules/security-checklist.md`
3. Read `CLAUDE.md`

Three problems:

Problem 1: .claude/rules/ does not reach subagents. If this agent runs as a subagent, those Read calls will return nothing or fail silently. Your standards are not enforced.

Problem 2: Even if you move the files somewhere the subagent can reach them, Read results land in messages — not in the system prompt. They do not cache across spawns. Every time a new code-reviewer subagent is spawned, it reads those files from scratch.

Problem 3: CLAUDE.md is auto-injected. Reading it explicitly is redundant.

The fix:

# .claude/agents/code-reviewer.md
---
name: code-reviewer
description: Reviews code for quality, security, and standards adherence.
tools: Read, Grep, Glob
skills:
  - shared-rules
  - coding-standards
---

# Code Reviewer

You review code for quality, security vulnerabilities, and adherence to team standards.
The standards are in your preloaded skills -- no need to read them at startup.
# .claude/skills/coding-standards/SKILL.md
---
name: coding-standards
description: Team coding standards and security checklist.
user-invocable: false
---

# Coding Standards

## Style
- Functions under 40 lines. Extract if longer.
- No magic numbers. Named constants only.

## Security
- Validate all user input at the boundary.
- No secrets in source. Environment variables or secrets manager.
- Parameterized queries only. No string concatenation in SQL.

The skill content is injected into the system prompt at agent startup. Every code-reviewer spawn gets it. It caches once and rides free after that.

A worked example: accessibility rules

Say you have an accessibility checklist you want enforced across your UX reviewer, your web-dev agent, and your QA agent.

Option A: in each agent body

# UX Reviewer
...
## Accessibility Rules
- Color alone must never convey meaning -- use symbol + text
- Minimum contrast ratio: 4.5:1 for text
- All interactive elements need keyboard focus states
- No yellow/green adjacent status indicators (partial color vision)
...

You copy this into three agent files. Each agent type has a unique body, so the cache diverges before reaching this content. You’re paying for it three times on every pipeline run that spawns all three agents.

Option B: in .claude/rules/

.claude/rules/
  accessibility.md   <-- contains all the above

This reaches the main session fine. Your subagents never see it.

Option C: as a skill

# .claude/skills/accessibility/SKILL.md
---
name: accessibility
description: Accessibility standards all agents must follow.
user-invocable: false
---

## Accessibility Standards
- Color alone must never convey meaning -- use symbol + text
- Minimum contrast ratio: 4.5:1 for text
- All interactive elements need keyboard focus states
- No yellow/green adjacent status indicators (partial color vision)
# In each agent's frontmatter:
skills:
  - shared-rules
  - accessibility

The content lives once. Every agent that lists the skill gets it injected at startup, in the system prompt, cached across spawns. Three agent types, three spawns each — you pay for the skill content once per agent type on the first spawn, then it’s cached. If the agents share enough of a system prompt prefix (harness + CLAUDE.md + skills), the skill content caches across agent types entirely.

Option C is the right answer. Option A wastes tokens. Option B silently fails for subagents.

The skills: field syntax

The skills field takes a list. You can load multiple skills:

---
name: web-dev
description: Front-end development agent
tools: Read, Write, Edit, Bash, Glob, Grep
skills:
  - shared-rules
  - accessibility
  - coding-standards
---

Subagents do not inherit skills from the parent session. If the parent session has skills loaded via /skill, subagents still start fresh unless you list the skills explicitly in their frontmatter. [1]

The memory: field and subagents

One more thing worth knowing: auto-memory (your MEMORY.md and memory files from the main session) does not reach subagents. When a subagent starts, it gets a fresh context.

If you have preferences saved to memory (“use uv not pip”, “no yellow-green status pairs”), subagents will not see them — unless you:

  1. Put them in a skill (gets them into the system prompt)
  2. State them in the task prompt when spawning the subagent
  3. Give the subagent its own memory: frontmatter field (separate memory per agent type, not shared with the parent)

When memory: is set on a subagent, its MEMORY.md is loaded into the system prompt — specifically the first 200 lines or 25KB, whichever comes first [1]. Useful for agents that accumulate learned context across conversations.

The TL;DR

Content typePut it hereWhy
Rules every agent must followSkill (skills: frontmatter)System prompt, cached, reaches subagents
Project context, conventions, tech stackCLAUDE.mdAuto-injected, reaches subagents
Role identity, judgment heuristicsAgent bodySystem prompt, cached per agent type
Per-task dynamic dataRead callMessages, appropriate for ephemeral data
Main-session-only context.claude/rules/Works for the human, not for subagents

What to audit in your existing setup

If you have agents with startup checklists full of Read calls, run through this:

  1. Is the file they’re reading in .claude/rules/? Move the content to a skill if subagents need it.
  2. Is the content static and shared across agents? Skill.
  3. Is the content role-specific but static? Agent body.
  4. Is CLAUDE.md in the checklist? Delete that line — it’s already there.
  5. Is the content genuinely per-task (a ticket number, a file path, a log output)? Keep the Read call — that is what it’s for.

If you want to audit the CLAUDE.md itself for stale paths and redundant sections before you start reorganizing agents, Lint Your CLAUDE.md covers that in about 10 minutes.

A pipeline that spawns 5 subagents, each doing 3 Read calls to the same shared-rules file, is paying for 15 message-tier reads on every run. Moving that content to a skill that all 5 agents list costs you a one-time system-prompt cache write on the first spawn. After that, it’s cached input at roughly 10% of the normal rate. For a deeper look at how caching works and what busts it, see Prompt Caching Basics.

The math is straightforward. The configuration change is a one-liner in each agent’s frontmatter.


Pricing referenced in this post: Anthropic API prompt caching charges approximately 10% of normal input token cost for cache hits (as of 2026-04-14). Verify current rates at platform.claude.com. To measure whether your skill placements are actually caching across agents, OTel + Jaeger gives you per-request cache_read_tokens breakdowns.

Sources

  1. Create custom subagents — Claude Code Docs — canonical source on what subagents receive; confirmed skills injection behavior and memory field spec
  2. Subagents in the SDK — Claude Code Docs — confirmed CLAUDE.md injection via settingSources, skills field is a list, subagents don’t inherit parent session skills
  3. How Claude Code Builds a System Prompt — dbreunig.com — community analysis of system prompt architecture
  4. Prompt caching — Anthropic API Docs — cache tiers, pricing, minimum thresholds