Three AI coding agents, three different answers to the same question: how do you give an agent persistent behavioural instructions that survive across sessions? Claude Code uses SKILL.md files with auto-discovery. Cursor uses a .cursorrules file that's always loaded. Windsurf uses .windsurfrules with similar always-on semantics. This guide walks through how each works, where they differ, and how to migrate between them.
By the end you'll know which model fits your team, how to convert rules between the three formats, and how the interoperability layer is shaking out as more projects start supporting all of them.
If you're skimming, here's the difference in one table. All three tools solve the same surface problem: I want the agent to follow my conventions without me re-explaining them every session. They differ on how the instructions get into the model's context, how you scope them, and how you distribute them.
| Dimension | Claude Code (SKILL.md) | Cursor (.cursorrules) | Windsurf (.windsurfrules) |
|---|---|---|---|
| File location | ~/.claude/skills/<slug>/SKILL.md or .claude/skills/ in repo | .cursorrules at repo root | .windsurfrules at repo root (or global_rules.md for global) |
| Loading model | Description-triggered, on-demand | Always loaded into system prompt | Always loaded into system prompt |
| Multi-rule support | Native — one directory per skill, hundreds coexist | Single file (legacy); .cursor/rules/*.mdc for scoped rules (newer) | Single file; .windsurf/rules/ directory for memories |
| Scope | Project + global, both active | Project only (with newer global rules option) | Project + global |
| Discoverability | Description scanned at startup; body loads on intent match | Eager — entire file in every request | Eager — entire file in every request |
| Packaging | Standalone Git repo per skill; install by copying directory | Copy/paste a file; awesome-cursorrules lists | Copy/paste a file |
| Token cost | Description tokens only until triggered | Full file tokens on every turn | Full file tokens on every turn |
| Frontmatter | YAML required: name, description, optional allowed-tools, model | None (plain text/markdown) | None (plain text/markdown), but .mdc files in newer dir support frontmatter globs |
The headline difference is the loading model. Claude Code treats skills like libraries — you install them once, the runtime decides what to pull in. Cursor and Windsurf treat rules like a project-level system prompt — everything is always there, you pay the token cost on every request. Both philosophies have real trade-offs, which the rest of this article unpacks.
A Claude Code skill is a directory with a SKILL.md file inside. The minimum viable skill is two lines of YAML frontmatter plus a body:
---
name: postgres-migrations
description: Use when writing, reviewing, or rolling back PostgreSQL schema migrations. Covers transactional DDL, backfill patterns, and zero-downtime renames.
---
# PostgreSQL Migrations
Always wrap schema changes in a transaction unless the operation explicitly forbids it (e.g. CREATE INDEX CONCURRENTLY). For backfills, batch updates in chunks of 5,000 rows...
Drop that file at ~/.claude/skills/postgres-migrations/SKILL.md and Claude Code picks it up on next launch. The key mechanic: at startup, Claude scans every skill's frontmatter — just the description, not the body. The descriptions are added to a lightweight index. When you start a conversation and say "help me write a migration to add a nullable column to the users table," Claude matches your intent against those descriptions, decides postgres-migrations is relevant, and loads the full body into context for that turn.
This description-as-trigger pattern is the whole point. It means you can have 200 skills installed and never pay the token cost of skills you don't use today. The cost shows up only when a skill is actually loaded. Writing the description well is therefore the highest-leverage thing you do when authoring a skill — it's the function signature the runtime matches against.
Two more important properties:
~/.claude/skills/ apply everywhere. Skills in .claude/skills/ at a repo root apply only when Claude Code is launched in that directory. Both sets are merged at startup. You can commit project-scoped skills with your code, and they travel with the repo.The format also supports allowed-tools in frontmatter (gate which tools a skill can invoke), model hints, and a few other fields. But the essence — auto-discovery, description-triggered loading, multi-skill composition — is what differentiates the model from Cursor's and Windsurf's.
Cursor's classic mechanism is a single file: .cursorrules at your project root. It's plain text (markdown is fine, no YAML frontmatter required). Whatever you write in it gets prepended to Cursor's system prompt on every request — chat completions, tab completions, agent runs, all of them.
# Project conventions
We're a TypeScript monorepo using pnpm workspaces.
- Always use named exports, never default exports.
- Test files live next to source files as <name>.test.ts.
- We use Vitest, not Jest. Don't import from "jest".
- API responses follow our Result<T, E> pattern in src/lib/result.ts.
# Style
- Prefer early returns over nested ifs.
- No barrel files (index.ts re-exports) — they break tree shaking.
The model is brutally simple: one file, always loaded, scoped to the project. That simplicity is its strength. There's no discovery layer to learn, no frontmatter to write, no convention about how to name things. You write the rules, Cursor reads them. Done.
The trade-offs are real, though. Every turn pays the .cursorrules token cost, which can add up — a 2,000-line rules file is a meaningful tax on every tab completion. Teams that grow their rules file organically end up with stale guidance baked into every request and no way to scope rules to specific paths ("only apply these React conventions in the apps/web/ directory").
Cursor has been adding more mechanisms over time. The newer pattern is a .cursor/rules/ directory with multiple .mdc files. Each file can carry frontmatter that scopes the rule by glob:
---
description: React component conventions
globs: apps/web/**/*.{tsx,jsx}
alwaysApply: false
---
Use function components, never class components.
Memoize expensive children with React.memo.
...
This project rules directory narrows the gap with Claude Code's model — you get per-rule scoping and the option to not always-apply. But the loading mechanic is still glob-based rather than intent-based: if the file you're editing matches the glob, the rule loads. It's a closer cousin to Claude Code's model than the classic .cursorrules, but still not the same thing.
Cursor also added a global rules surface in settings — a text area you fill in that applies across all projects. That covers the equivalent of Claude Code's ~/.claude/skills/ global scope, just with a UI rather than a directory of files.
Windsurf, the Codeium-built editor with the Cascade agent, follows a model very close to Cursor's. A .windsurfrules file in your project root carries plain-text instructions that load on every Cascade turn. Format-wise, it's interchangeable with .cursorrules in practice — same flat text, same always-on loading model, same conventions about writing in markdown.
# Cascade rules for this project
## Stack
- Next.js 14 app router
- Drizzle ORM + Postgres
- Tailwind + shadcn/ui
## Behaviour
- When asked to add a route, also add a corresponding Playwright test in e2e/.
- Never write raw SQL outside src/db/migrations/.
- Server actions go in app/_actions/, never inline in components.
Windsurf supplements this with a couple of mechanisms that differ from Cursor:
~/.codeium/windsurf/memories/global_rules.md. Same format, applied across every workspace. This gives you the equivalent of a global .cursorrules file out of the box..windsurf/rules/ or the global memories directory. Some of these are auto-written by the agent ('I learned the test command is npm run test:ci') and some you write manually. Memories load alongside the rules file..cursor/rules/, Windsurf supports a .windsurf/rules/ directory of multiple files, with frontmatter that controls when each rule activates (always, on-glob, or manually invoked).The Cascade workflow is more agentic than Cursor's chat — it'll run multi-step changes, then summarise. Rules anchor that behaviour: without them, Cascade is happy to deviate from your conventions; with them, you get consistency across sessions and team members.
From a comparison standpoint, treat Windsurf and Cursor as siblings in this dimension. The trade-offs are nearly identical: simple always-on loading model, fixed token cost per turn, optional newer mechanisms for scoping. If you know how to write .cursorrules, you can write .windsurfrules in 90 seconds.
Let's zoom out on the dimensions that actually matter when you're picking a model for your team.
All three support project-scoped rules. Claude Code and Windsurf both support global rules out of the box (filesystem locations); Cursor offers global rules through its settings UI. If your team works across many repos and you want one set of "how we code" instructions, all three can do it.
The interesting difference is composition. Claude Code merges global and project skills automatically — both apply, and if descriptions match, both load. Cursor and Windsurf will load global rules and project rules together when both are configured. None of them has a clean override model ("this project rule replaces the global rule on the same topic"), which is something to watch out for if your global and project guidance contradict.
This is the biggest philosophical split. Claude Code reads descriptions and decides what to load per turn. Cursor and Windsurf load everything that's configured to be on, every turn. The Claude Code model scales further — you can install hundreds of skills without paying a per-turn token tax — but requires more discipline when writing skill descriptions. The Cursor/Windsurf model is dead simple to reason about: what's in the file is what the agent sees.
Claude Code is multi-rule by design. Cursor's classic .cursorrules is single-file, but the newer .cursor/rules/ directory closes the gap. Windsurf likewise supports both a single file and a directory of rules. If you want to maintain ten focused rule documents instead of one 3,000-line file, all three now let you.
Claude Code skills package naturally as Git repos. A skill is just a directory with a SKILL.md — you can publish it on GitHub, clone it into ~/.claude/skills/, and you're done. This is why the SKILL.md ecosystem has grown so quickly: the unit of distribution is well-defined and copy-paste-free.
Cursor rules historically distribute as snippets — you find a .cursorrules file you like on awesome-cursorrules, copy its contents into yours, and merge by hand. The newer .mdc rule files are more portable as standalone artifacts, but there's no installed-but-inactive concept the way there is with Claude Code.
Windsurf rules are in a similar state — copy-paste distribution, growing ecosystem of community-shared rule files, no first-class "install" model.
As of mid-2026, ClaudSkills indexes tens of thousands of public SKILL.md files. The awesome-cursorrules collections cover hundreds of starter rule sets. Windsurf's ecosystem is smaller but growing fast, particularly among teams that prefer the Cascade workflow.
The good news: these formats are close enough that conversion is largely mechanical. Here's a working .cursorrules:
# Database access
Never query the database from a React component. All DB calls go through server actions in app/_actions/ or route handlers in app/api/.
We use Drizzle ORM, not Prisma. Schemas live in src/db/schema/.
Migrations: pnpm db:generate to create, pnpm db:migrate to apply. Never edit the SQL output manually.
To turn that into a SKILL.md, wrap it with frontmatter and write a description that captures the trigger:
---
name: db-access-conventions
description: Use when reading from or writing to the database, designing schemas, or creating Drizzle migrations. Covers where DB calls are allowed, the Drizzle ORM choice, and migration commands.
---
# Database access
Never query the database from a React component. All DB calls go through server actions in app/_actions/ or route handlers in app/api/.
We use Drizzle ORM, not Prisma. Schemas live in src/db/schema/.
Migrations: pnpm db:generate to create, pnpm db:migrate to apply. Never edit the SQL output manually.
Save to .claude/skills/db-access-conventions/SKILL.md. Done. The body is identical; the only work is writing the description. A good description names the situations where the skill applies in the language the user is likely to use — that's what Claude matches against.
Going the other direction (SKILL.md → .cursorrules) is even easier. Strip the frontmatter, paste the body into .cursorrules. If you have multiple skills, concatenate the bodies with ## section headers between them. The catch: you lose Claude Code's intent-routing. Every skill body now loads on every Cursor turn, so your token bill grows and Cursor may attend to less-relevant guidance.
Two patterns to handle this:
.claude/skills/, mirror them as five .cursor/rules/<name>.mdc files with appropriate globs. You get per-file scoping at the cost of glob-based rather than intent-based matching..cursorrules. The stuff that applies to every file (conventions, stack choice, naming) goes in the always-on file. Specialised guidance stays in scoped .mdc rules or, if your team has both editors in play, in SKILL.md files for the Claude Code users.For Windsurf, the migration mechanics are identical to Cursor — same flat text, same trade-off about always-on loading. Many teams just maintain a single rules file and let both Cursor and Windsurf read it via a symlink, since the contents work fine in both.
Tool choice is rarely a pure technical decision — it follows whichever editor your team has standardised on. But if you have a say, here's how the models differentiate.
.cursorrules is easier to review in a PR than a tree of small files.For teams that span multiple editors (very common in 2026 — most orgs have a mix), the pragmatic answer is to support all three. The next section covers how that's playing out.
A growing pattern in open-source projects is shipping all three rule formats in the same repo. You'll find repos with a .claude/skills/ directory, a root .cursorrules, and a root .windsurfrules, all describing the same conventions in formats each tool can read natively. This costs a little duplication but lets every contributor use their preferred editor without losing the project's guidance.
There are a few approaches to managing the duplication:
docs/conventions.md) and a small script that generates .cursorrules, .windsurfrules, and one or more SKILL.md files from it. Run the exporter on pre-commit. This is the cleanest model but requires up-front tooling..cursorrules and .windsurfrules are byte-identical (very common), symlink one to the other. Some teams even symlink a SKILL.md body into .cursorrules with a small header, accepting the slight awkwardness for the convenience of single-source maintenance.A handful of meta-tools have appeared that read multiple formats and translate between them. None has emerged as a dominant standard yet — most teams roll their own exporter when they need one.
The deeper trend worth watching: the formats are converging. Cursor's .cursor/rules/*.mdc looks structurally similar to .claude/skills/*/SKILL.md. Windsurf's directory-of-rules pattern is the same shape. Claude Code's frontmatter conventions are influencing how others structure their files. In two years it would not surprise me to see a shared community convention — call it RULE.md or whatever — that all three (and Cline, Roo Code, Aider, and whatever comes next) read natively.
Until then, the practical advice is: pick the model that fits your dominant editor, write the rules to be self-contained, and if your team is mixed, lean on the exporter pattern. Don't let the choice of rules format determine your editor — these mechanisms are close enough cousins that switching is a weekend of work, not a quarter of migration.
If you're building skills you intend to publish, start with SKILL.md. The format is the most portable (frontmatter + body is straightforward to translate into the other formats), and the auto-discovery model gives you the highest leverage as your library grows. The skills you see in the ClaudSkills category index were almost all written this way first, then ported to other formats by users who wanted them in Cursor or Windsurf.
Found a bug or want a topic covered? Email [email protected] or open an issue via GitHub.
SKILL.md files, not affiliated with, endorsed by, or sponsored by Anthropic.