개발도구10 min

Cursor Rules vs CLAUDE.md — A Deep Dive into Context Injection Patterns for AI Coding Tools

How Cursor Rules and CLAUDE.md actually differ under the hood, written by a solo dev running both in the same project. Covers Cursor's 4 modes, CLAUDE.md's 5 locations, and the AGENTS.md single-source-of-truth workflow.

목차 (18)

I run Cursor and Claude Code together on the same projects. Both tools see the same codebase, but they inject rules in fundamentally different ways. Early on I didn't know this and copy-pasted the same markdown to both sides. One side followed it well, the other slowly forgot. After a month of confusion I landed on the conclusion that "these two are different species when it comes to context injection."

This post unpacks that difference from a solo dev's perspective. On the surface they're both just one markdown file, but crack them open and Cursor Rules has four modes, while CLAUDE.md has three layers plus an import system. Use them without knowing this and the same rule ends up injected twice per message eating tokens, or the file exists but the model never reads it.

I run 16 iOS apps and a few SaaS products as a solo indie. Mixing two or more tools is daily life for me. I hate writing the same rule twice, and I hate even more spending time debugging rules that don't get followed. That's the motivation for this post. I'll cover how AI coding tool context injection patterns differ, how to split things when running both, and five common traps — all from my own experience.

> TL;DR
> - Cursor Rules is injected per inline edit. CLAUDE.md is loaded once at session start, with child-dir files added on demand.
> - Cursor's .mdc has 4 modes (Always Apply / Apply Intelligently / Apply to Specific Files / Apply Manually). CLAUDE.md has 5 locations (~/.claude/, project root, CLAUDE.local.md, parent dirs, child dirs) + @import.
> - When writing the same rule in both places, in my experience short imperative for Cursor and descriptive context for Claude makes them both stick. Not an external standard — just my opinion after a year of running this.
> - Never commit globals to git. Project CLAUDE.md gets committed, CLAUDE.local.md goes in gitignore — that's the standard pattern.
> - The 2026 trend is AGENTS.md as the single source of truth + Cursor/Claude/Codex/Copilot all importing from it. I'll cover this at the end.
> - When rules don't stick, it's almost always either "the file wasn't actually read (broken frontmatter, duplicate file)" or "two rules contradict each other."

Before getting into the body, I've put the core of both systems in one table. Helps to see which row each section of this post is unpacking.

| Item | Cursor Rules | CLAUDE.md |
|------|--------------|-----------|
| Location | .cursor/rules/*.mdc or .cursorrules | ~/.claude/CLAUDE.md + project root |
| Injection timing | Per inline edit / chat | Once at session start |
| Splitting | File-level + conditional globs | Chained via @import syntax |
| Modes | Always / Auto / Agent / Manual | Always injected (only layered) |
| Global area | App settings screen (no text file) | Separate markdown file |

I've personally lived through every one of these five rows. Going through them in order.

Why Cursor Rules and CLAUDE.md are different species

Surface-level, both are markdown. But the tools' usage patterns differ. Cursor's main mode is inline edit. You fix short blocks of code on the spot. Claude Code's main mode is the agent session. Once you start, it autonomously runs dozens of tool calls. That difference is reflected directly in how each rule file is structured.

Cursor builds a fresh system prompt for every inline edit request. So it injects the rules every time. Token cost every time. That's why Cursor Rules works best with short, forceful imperatives. One-line rules like "use Tailwind only" or "App Router only" — the model re-reads them every request.

Claude Code sessions are long. Once you start, it carries the same system prompt all the way through. So CLAUDE.md works better with background context than short commands. Things like "this is why the codebase is structured this way," "here are the danger zones," "here's who I am" — descriptive prose. Material the model references when making its own judgment calls.

When I didn't know this and copy-pasted the same rules to both sides, Claude got annoyed by the imperative tone and started routing around the rules. Cursor was too long, so it only listened to the first 30 lines and skimmed the rest. Just splitting the tone alone visibly improved rule compliance on both tools.

The 4 modes of Cursor Rules

.cursor/rules/*.mdc files are markdown with frontmatter. The frontmatter field combination determines the mode. There are four modes. Early on I didn't read this and just slapped alwaysApply: true on everything, wasting all the efficiency.

```mdc


description: SwiftUI iOS work rules
globs: "**/*.swift"
alwaysApply: false


  • Swift 6, async/await
  • Prefer @Observable macro, no ObservableObject
  • No completion handlers
  • Split long Views with ViewBuilder
  • ```

Always mode (alwaysApply: true) is forcibly injected on every request. Same as the old .cursorrules file. I put danger rules here (no production touches, no force push). Only items where forgetting causes accidents.

Auto mode (alwaysApply: false + globs filled in) auto-injects only when globs match. The example above only injects when touching a .swift file. I split stack-specific conventions into this mode. iOS rules, Next.js rules, Tailwind rules — all separate.

Agent-requested mode (only description filled, both globs and alwaysApply empty) lets the model decide whether to pull it in. If the description looks relevant, the model fetches it. I keep things like occasional code review checklists or migration procedures here.

Manual mode (just the name, all auto-triggers off) only loads when explicitly called via @rulename in chat. For templates I don't want forced but want to summon on demand. I put PR templates and test code boilerplate here.

Mixing these four modes is the heart of Cursor Rules. After a year of running this, my settled ratio is Always 20%, Auto 60%, Agent 15%, Manual 5%. Stuff too much into Always and per-request token cost balloons while the model's attention drops.

CLAUDE.md's 3 layers and @import system

CLAUDE.md doesn't have modes — it has layers. It reads from three places. ~/.claude/CLAUDE.md (global), <project root>/CLAUDE.md (project), and CLAUDE.md inside subfolders (sub-directory). All three get pasted whole at the front of the system prompt at session start.

Global is my personal identity. Name, tone, my regular stack, hard-banned actions — that kind of thing. My global is about 50 lines. Just things like "solo indie dev, ship-fast first, always Korean, never touch .env."

Project root is for that codebase only. Stack structure, folder conventions, danger zones. If something contradicts the global, this is where I explicitly override. For example if global says "TypeScript strict" but some legacy project says "any allowed for now," I write in the project CLAUDE.md: "override the global strict rule for this project." You have to make it explicit for Claude to pick it up.

Sub-directory applies only inside that folder. SwiftUI conventions go in apps/ios/CLAUDE.md, Next.js conventions in apps/web/CLAUDE.md. Works well for monorepos. Claude Code reads that file additionally when working in that folder.

There's also @import syntax. If you write @docs/conventions.md inside CLAUDE.md, it pulls that file in too. When rules get long, don't stuff everything into one file — split by topic and gather them via import. My project CLAUDE.md is about 50 lines and imports two files: @docs/stack.md and @docs/danger.md. Imported files come into context as-is. Sort of a dynamic split.

Context injection timing — every time vs once

This is the most important difference. Also where I tripped most while running both tools together. Cursor and Claude inject rules at fundamentally different moments.

Cursor rebuilds the system prompt every request. One inline edit, one chat message — each is a fresh prompt. Rules get injected every time. Token cost every time. Upside: add a new rule and the next request applies it instantly. No session restart needed.

Claude Code reads once at session start. It carries the same system prompt until that session ends. Token cost is small thanks to prompt cache — the first message is expensive, then it's almost free. Downside: changing a rule doesn't apply to the existing session. You need a new session for the new rule to land.

How that difference shows up in actual work, from my experience: add a rule in Cursor and the next inline edit picks it up. Same scenario in Claude requires /clear to reset the session, or opening a new conversation. I once spent 30 minutes confused about "why isn't it picking up the new rule" before I figured this out.

One more thing. Cursor's inline edit context is short. It looks at one function, one file. So your rules need to fit that scope. Rules like "structure the whole folder this way" don't land in inline edit. Claude has long sessions and uses tools freely. Macro rules like folder structure work well there.

globs matching vs @import — the file-splitting pattern

Long rule files need splitting. The two tools split differently. Here's the pattern I use.

Cursor Rules splits by file via globs. Touch a .swift and only iOS rules come in; touch a .tsx and only Next.js rules come in. No noise in the model context. I lean on this hard. My folder looks like this:

```
.cursor/rules/
├── always-danger.mdc # alwaysApply: true
├── nextjs-stack.mdc # globs: "**/*.{tsx,ts}"
├── ios-swiftui.mdc # globs: "**/*.swift"
├── tailwind.mdc # globs: "**/*.{tsx,jsx,html}"
└── pr-template.mdc # manual
```

Open a Swift file and inline edit, and only always-danger and ios-swiftui hit the system prompt. nextjs and tailwind rules don't load. Saves tokens and reduces rule noise.

CLAUDE.md splits via @import. The main file acts as the entrypoint and imported files trail along. Downside: no globs matching, so everything loads regardless of work context. That is, every import behaves like alwaysApply: true.

```markdown

Project: apsity

@docs/stack.md
@docs/conventions.md
@docs/danger.md

Extra notes

  • Add new routes under app/
  • DB schema changes always via migration files
  • ```

Because of this difference I use different splitting strategies for the two tools. For Cursor I split fine by stack, for Claude I bundle into bigger chunks. Since everything loads on Claude anyway, fine-grained splitting is meaningless. But I never let an imported file go past 200 lines — model attention drops past that line.

Token cost and noise control

Stuffing too many rules in is the trap indie devs fall into most. I did the same — crammed 200 lines into a single page. The result was the model dutifully followed the first 30 lines and "is that even there?" the rest. Long system prompts noticeably tank model attention. I felt it on both tools.

On Cursor this also hits as direct token cost. Rules go in every request, so a 200-line ruleset is 200 lines of tokens per inline edit. If I do 50 inline edits a day, that's 10,000 lines of tokens per day. Not nothing. Split with globs and usually only 30-50 lines load — 1/4 the tokens.

On Claude Code, prompt cache makes token cost small. The first message is expensive, then cached tokens only. So noise is the bigger issue here than tokens. A 200-line system prompt makes the model start out a little scattered. I cap at 80 lines.

The rule-writing guide I've settled on has three parts. First, write in measurable form. "Write clean code" doesn't land — "split functions over 50 lines" does. Second, one rule per line, one command per rule. Bundle two or three into one line and the model only listens to the strongest. Third, attach a short "why." Claude generalizes when it knows the reason.

Strategy for running both tools together

Here's the pattern I settled on. Ran it for a year. The case where one project has both Cursor and Claude Code.

| Area | Location | Tone | Example |
|------|----------|------|---------|
| Danger rules | Both | Short imperative | "no .env, no force push" |
| Stack conventions | Cursor (per glob) | Imperative | "Tailwind utils only, no styled-components" |
| Codebase background | Claude (CLAUDE.md) | Descriptive | "App Router migration done, new code goes under app/" |
| Personal identity | Claude global only | Descriptive | "solo indie, Korean, ship-fast first" |
| PR/review checklist | Cursor (manual) | Steps | "Call via @pr-template" |

Only danger rules duplicate across both. They're items where the model forgetting causes accidents — the duplication cost is far smaller than the omission cost. Things like no .env, no force push, confirm before touching production files. Same tone on both sides.

Stack conventions go heavily on the Cursor side. Rules that need to apply at the inline-edit level are where they have the biggest impact. Short imperatives like "App Router only," "Tailwind utils only." Split by file type via globs and noise drops too.

Codebase background goes heavily on the Claude side. Material the model references when making session-level autonomous calls. Descriptive things like "this SaaS gates auth via RLS, so no backend if-statements." Putting this in Cursor doesn't land well because inline edit context is short.

Personal identity only goes in Claude global. I leave Cursor's global settings mostly empty. Instead, every project's CLAUDE.md auto-pulls the global identity. Concentrate consistency in one place.

Debugging order when rules don't stick

I debug "this rule isn't sticking" more often than I write new rules. Almost every case falls into these 4 steps.

Step 1, confirm the file actually got read. On Claude Code, in the first message of a session, ask "list 3 of the danger rules I put in CLAUDE.md." If the answer is accurate, it read it. Wrong answer means the file location is off, the encoding is broken, or it got truncated for length. On Cursor, ask in the chat "show me the active rules" and active rules appear.

Step 2, recheck the rule mode. In Cursor, if alwaysApply: false and both globs and description are empty, that rule will never auto-inject. Manual call only. I've gotten the mode confused twice and wondered "why isn't it sticking." Always check the frontmatter first.

Step 3, check for rule contradictions. When global vs project, or .cursorrules vs .cursor/rules/*.mdc conflict, the model follows whichever is more strongly worded. I open both files side by side to catch this. They're short anyway, fits on one screen.

Step 4, check whether the rule is too abstract. "Write clean code" doesn't land. "Split functions over 50 lines" lands. Has to be measurable. When I look back at rules that failed, almost all were abstract.

One more thing. Cursor's .cursorrules (old format) and .cursor/rules/*.mdc (new format) both apply when both exist. New format is not preferred. Keeping both around duplicates rules and confuses the model. When I migrated to the new format I deleted the old file immediately.

Security and git commit policy

Common question. My answer is clear. Project-level files always get committed, globals never.

<project>/CLAUDE.md, .cursorrules, .cursor/rules/*.mdc are part of the codebase. New collaborators or future-me need the same rules. Don't put them in .gitignore. Keep them next to the README. I include these files in PR review. Rule changes are decisions as important as code changes.

The opposite for ~/.claude/CLAUDE.md, ~/.gemini/GEMINI.md and other globals — those are personal identity. Email, tone preferences, even names of apps I run. Pushing this to git causes accidents. I keep them in a separate private dotfiles repo and clone on new machines. That's also git-managed but separated from project code.

Another thing to watch — secrets inside rule files. I once accidentally put a Supabase project ID in CLAUDE.md. The ID itself isn't secret, but env var names sat right next to it, which felt iffy. After that I don't put env var names or identifier-style things in rule files. I stop at "env vars live in .env.local."

.cursor/rules/ needs one extra consideration. On a team project, rules pinned there auto-apply on other teammates' machines too. Pinning rules that enforce my personal style annoys colleagues. For team-project Cursor Rules, I only pin codebase safety rules and keep personal style in my own global.

Real example — my SaaS setup

Partial open of the actual config from one SaaS I run. Next.js + Supabase stack, using both Cursor and Claude.

Project root CLAUDE.md (descriptive context):

```markdown

Project: apsity

Stack

  • Next.js 15 App Router, TypeScript strict
  • Supabase (PostgreSQL + Auth + Storage)
  • Vercel deploy, Tailwind v4

Structural decisions

  • Prefer Server Components, 'use client' only for interactions
  • Data fetching: call Supabase directly from Server Components
  • API routes only for webhooks and external calls
  • Auth via RLS, no backend if-statements

@docs/danger.md
@docs/conventions.md
```

Same folder's .cursor/rules/nextjs-stack.mdc (imperative, auto via globs):

```mdc


description: Next.js + TypeScript work rules
globs: "**/*.{ts,tsx}"
alwaysApply: false


  • App Router only. Don't write Pages Router code.
  • Minimize 'use client'. Branch at the top of the component tree.
  • Tailwind utils only. No styled-components.
  • No as casting. If unsure, unknown then narrow.
  • Split functions over 50 lines.
  • Direct await in async Server Components is OK.
  • ```

And .cursor/rules/always-danger.mdc (every-request injection):

```mdc


description: Danger zone guards
alwaysApply: true


  • Confirm with user before editing supabase/migrations/.
  • Never print production env vars.
  • DB schema changes always via migration files.
  • No git push --force.
  • Never read or modify .env files.
  • ```

Same ruleset, but Cursor gets short commands and Claude gets background + reasoning. Cursor enforces code style by re-injecting imperatives per inline edit, while Claude gets codebase intent at session start to support autonomous judgment. They don't conflict.

I sync the two files about once a month. New rules usually start on the Claude side, and once they harden I move a short version to Cursor. The reverse is rare. Imperative rules rarely turn into descriptive context.

Which file in which tool — by situation

Starting a new project, it's easy to get confused about which rule file goes where. Here's a decision table I made from running this.

| Situation | Recommendation | Reason |
|-----------|----------------|--------|
| Cursor only, solo, small project | Single .cursorrules | Splitting cost > benefit |
| Cursor only, two+ stacks | .cursor/rules/*.mdc + globs | Noise control |
| Claude Code only | CLAUDE.md + global separation | Identity vs codebase split |
| Both tools | Two files + tone separation | Only danger rules duplicate |
| Monorepo + stack split | CLAUDE.md in subfolders | Auto-branch by work context |
| Team project | Project files = safety rules only | No personal style enforcement |
| Security sensitive | Never commit globals | dotfiles repo private |

This table alone resolves new-project decisions in 5 seconds. My case (both tools + solo + multiple stacks) uses every row. Conversely, for an indie dev using Cursor only, the .cursor/rules/ folder + globs split gives the biggest payoff.

Other tool files like AGENTS.md, GEMINI.md don't need pre-emptive setup. If you don't use that tool, no reason to pin anything in advance. If you adopt Codex or Gemini later, a symlink from CLAUDE.md handles it. ln -s CLAUDE.md AGENTS.md — done in one line.

FAQ

Can Cursor Rules and CLAUDE.md be merged into one file?

Not entirely. The two tools look at different filenames. You can partially unify via symlinks. I keep the main as CLAUDE.md and put a short imperative excerpt at .cursorrules. The rule body lives in one place. Since the tools work differently, sharing the exact same text shortchanges one side.

When Cursor's .cursorrules and .cursor/rules/*.mdc both exist, which wins?

Both apply. There's no priority — they merge. Result: rules can duplicate or contradict. Cursor's official docs even recommend migrating to the new .cursor/rules/*.mdc format. I delete the old format immediately and use only the new. Keeping both makes debugging hard.

What happens with too many imports in CLAUDE.md?

Imported files all land in the system prompt. No mode system, so they always come in whole. Five 200-line imports → a 1000-line system prompt. Model attention drops. I keep total imports under 200 lines combined. Past that, I trim to truly necessary rules and move the rest to code comments.

Exactly how does .cursor/rules globs match?

Gitignore-style globs. Recursive like **/*.swift, folder-scoped like apps/web/**/*.tsx. The match target is the file currently being inline-edited. In chat, attaching multiple files pulls in any rule that matches at least one of them. After writing globs, I verify once via the preview feature in Cursor's official docs.

Are there cases where you shouldn't use a global CLAUDE.md?

If you mix work and personal machines, leave global empty or split into two. Work conventions on the work machine, personal style on the personal machine. I don't mix the two so one global was enough. But when touching company code I explicitly override some global rules in the project CLAUDE.md. Something like "globally I prefer ship-fast, but for this project pause that — code review first."

I added a new rule in Cursor but it doesn't apply to old chats.

That's intentional, not caching. Rules apply from new chats or new inline edit requests onward. They don't enter ongoing chat flow. Right after adding a rule I open a new chat to test. Inline edit applies instantly because each request is a new prompt.

Doesn't writing rules too short make the model ignore them?

Actually shorter listens better. I cut a 200-line ruleset to 80 lines and compliance went up. Models weight the front of long system prompts more heavily. Move the core to the top, push secondary rules to globs or dynamic injection via import. "Keep it minimal, don't pin rules you won't follow" is my one-year conclusion.

Can MCP servers or tool permissions be controlled from rule files?

Not directly. MCP has its own config file. But you can include guidance in rule files like "use this MCP tool only for X." When I attach a database MCP server, I write in CLAUDE.md "DB MCP: read-only queries first, writes need user confirmation." Permissions are gated in MCP config, and rules are auxiliary guards.

AGENTS.md — the 2026 single-source-of-truth trend

Up to here I've treated Cursor and CLAUDE.md as separate. But pinning the same rule in two files is obviously inefficient. So starting late 2025, AGENTS.md rose as a standard. OpenAI Codex defined it first, and in December 2025 it was donated to Linux Foundation/AAIF, becoming a real common standard. As of 2026, Cursor, Claude Code, Codex CLI, GitHub Copilot, Devin, Windsurf, and Gemini CLI all read AGENTS.md.

My ops pattern got simpler. Keep AGENTS.md as the source of truth, then @AGENTS.md import via a single line in .cursor/rules/index.mdc, @AGENTS.md import in CLAUDE.md, same for other tools. Edit one file and every tool reflects it. Per-tool fine tone differences (greeting patterns, voice) live separately in each file only where really needed.

That said, Claude Code's global (~/.claude/CLAUDE.md) and Cursor's user rules (app settings screen) can't be sync'd outside the tool — personal identity, voice — so they stay out of the AGENTS.md source. The source holds project conventions, codebase rules, and danger rules only.

The single-file .cursorrules is being deprecated by Cursor officially. New projects start with .cursor/rules/*.mdc and existing .cursorrules is migration-recommended. Pinning AGENTS.md as the source means everything imports from it anyway, so this migration also gets resolved in one shot.

Skills and Hooks — areas that shouldn't go in CLAUDE.md

There are two more areas Anthropic explicitly recommends separating. Skills (.claude/skills/) and Hooks (.claude/hooks/). Stuff them all into CLAUDE.md and it bloats past 200 lines, burying the rules you actually use.

Skills hold "domain-specific, occasionally needed procedures." For example, I moved "the procedure for calling the App Store Connect API" to a Skill. No need for it in every session — the model only loads that Skill when a request like "check App Store revenue" comes in. Doesn't go in CLAUDE.md.

Hooks hold "actions that auto-run on specific events." A PostToolUse hook for auto-commit after file edits, a PreCompact hook for saving state right before context compression. These are actions, not rules — not what CLAUDE.md is for.

Knowing these two diets CLAUDE.md down. CLAUDE.md keeps only "core context that should always be pinned," occasional needs go to Skills, automation goes to Hooks.

Wrap-up

Cursor Rules and CLAUDE.md look similar on the surface — both markdown — but inside they're entirely different systems. Cursor is short rulesets injected per inline edit; CLAUDE.md is descriptive context pinned at session level. In my experience, when writing the same rule in both places, you have to match the tone too for both to listen.

My one-year conclusion is simple. Don't pin both files from the start — start with one tool, one file. When that file goes past 80 lines, then split via globs or @import. When you adopt the second tool, that's when you extract AGENTS.md as the source and import from both sides. Build everything up front and you'll just have rules that go unfollowed. Open your project's rule file right now and you'll likely see surprising amounts to cut.

> Official sources
> - Cursor Rules official docs
> - Anthropic Claude Code memory guide
> - Anthropic Claude Code Best Practices
> - CLAUDE.md @import syntax explained
> - AGENTS.md standard (Linux Foundation/AAIF)
> - AGENTS.md — OpenAI Codex guide
> - Anthropic Claude Code Skills official
> - Anthropic Claude Code Hooks official
> - Cursor MDC file format reference
> - Anthropic prompt caching official docs

This post is current as of 2026-04-30. Both Cursor and Claude Code update their rule systems quickly — six months out, this may need a recheck. The SaaS I run, apsity, is built for solo developers. I'm also building a small CLI to reduce the inefficiency of pinning the same rule across multiple tools. Take a look if you're curious.

공유하기
XLinkedInFacebook