Skillwright
 Blog

May 6, 2026 · 9 min read · by Harish Ganapathi

SKILL.md vs .cursorrules vs Windsurf rules vs Copilot instructions

Four formats for the same job: telling an AI coding assistant how you'd like it to work. Each grew out of a different IDE's assumptions, and the differences matter more than they look.

TL;DR

SKILL.mdis Claude Code's plugin-style format — YAML frontmatter, body of instructions, can be triggered by name. .cursorrules is a single plain-text file at the repo root that Cursor injects before every prompt. .windsurfrules follows the same idea for Windsurf (Codeium), with a slightly richer XML-ish syntax for global vs. workspace rules. copilot-instructions.mdis GitHub Copilot's equivalent, also plain markdown but scoped per repo via .github/.

They all do the same conceptual thing — pin context to a project so the AI behaves consistently. They diverge on three axes that bite in practice: scope, activation, and versioning.

DimensionSKILL.md.cursorrules.windsurfrulescopilot-inst.
IDEClaude CodeCursorWindsurf / CodeiumGitHub Copilot
File location.claude/skills/<name>/SKILL.md.cursorrules at repo root.windsurfrules at repo root.github/copilot-instructions.md
FrontmatterYAMLNoneNoneNone
Trigger modelNamed, on-demandAlways-onAlways-onAlways-on
Multiple skillsYes — folder per skillOne file (concat)One file (sections)One file (concat)
VersioningSemver in frontmatterGit history onlyGit history onlyGit history only

1. SKILL.md (Claude Code)

Anthropic's Claude Code uses a folder-per-skill model. Each skill lives at .claude/skills/<name>/SKILL.md with YAML frontmatter that declares metadata and triggers:

---
name: code-review
description: Strict review checklist enforcing security, performance,
  and maintainability standards before merge.
version: 1.2.0
triggers: [code-review, review, pr-review]
tags: [quality, security, review]
---

# Code Review

You are a senior engineer reviewing a pull request...

The big idea is on-demand activation. The skill isn't injected on every prompt — it loads when the user types a triggering phrase or invokes it explicitly. That keeps your context window clean and lets you have many skills coexist without blowing up token budgets.

What it's good at: a library of specialized behaviours (review, refactor, write tests, generate migration). The named-trigger model scales further than a single always-on file.
What it's bad at:always-on context. If you want a rule like “every TypeScript file must use strict mode” to apply automatically, SKILL.md isn't the right tool — Claude Code has separate CLAUDE.md files for that.

2. .cursorrules (Cursor)

Cursor takes the opposite approach. One file at the repo root, plain text or markdown, injected before every prompt the assistant sees:

# Project: Skillwright
## Coding standards

- Strict TypeScript. No `any`, no unguarded type assertions.
- React components are functions with typed props (no React.FC).
- Files stay under 800 lines. Functions under 50.

## Testing

- Vitest for unit, Playwright for E2E.
- 80% line coverage minimum.

## Don't

- Don't run `pnpm install` without me asking.
- Don't introduce a new dependency without flagging it.

It's elegant: one file, no metadata, no schemas. Cursor reads it on every chat. The cost is that everything is always on — no way to scope a rule to one task or one trigger. The file gets long, and long files start contradicting themselves.

What it's good at: codifying repo-wide conventions every contributor (human or AI) needs to follow.
What it's bad at: task-specific behaviour. Trying to use .cursorrulesas both “general standards” and “activate code-review mode” muddles both jobs.

3. .windsurfrules (Windsurf / Codeium)

Windsurf uses a similar root-file convention but with a richer structure: rules can be tagged with scope (global vs. workspace) and grouped semantically:

# Project rules

<rule>
trigger: always
content: |
  Use strict TypeScript. Forbid `any` and unguarded `as` casts.
  All public functions have explicit return types.
</rule>

<rule>
trigger: glob
glob: "**/*.test.ts"
content: |
  Use Vitest. Each test has a single assertion or a tightly
  related group asserting one fact.
</rule>

The glob trigger is genuinely useful — you can scope rules to test files, migration files, etc. without polluting the global context window. But the syntax is non-portable; you can't paste a .windsurfrules file into Cursor and have it work.

What it's good at: medium-complexity setups where some rules are global and others apply only to certain file patterns.
What it's bad at: portability. The tag-syntax-everywhere model is unique to Windsurf.

4. copilot-instructions.md (GitHub Copilot)

Copilot's answer is the simplest of the four: a markdown file at .github/copilot-instructions.md that Copilot reads into context when it operates inside that repo:

# Copilot instructions for Skillwright

This is a Tauri 2.0 desktop app with a React + TypeScript frontend
and a Rust backend.

## When generating code

- Frontend uses Zustand for state, never React Context.
- Backend commands are `async fn` returning `Result<T, String>`.
- Path APIs use `app_handle.path().app_data_dir()` (Tauri v2).
- Don't use `tauri::api::*` — removed in v2.

This is the lowest-overhead option of the four. It's also the least expressive — no triggers, no scoping, just one file the AI reads when you're in this repo. For most projects it's enough. For projects with many distinct AI workflows, it isn't.

What it's good at: stable cross-team conventions. Easy to review in a PR.
What it's bad at: anything that needs to be conditional on task or file pattern.

Where they overlap

All four formats encode the same handful of things in practice:

For a typical mid-size repo, ~80% of the content is identical across all four files. The remaining 20% is where the formats actually differ — and where things go wrong.

The hidden cost of running all four

Most teams I talk to who use multiple AI coding tools end up with three or four of these files in their repo. The cost shows up six ways:

  1. Drift. Someone updates .cursorrules after a tricky bug. The same lesson never makes it into .windsurfrules or copilot-instructions.md. Six months later, the AI in Windsurf reintroduces the same bug.
  2. Copy-paste rot. Engineers paste the same content into four files with slight reformatting. Now you have four versions of the same rule, none authoritative.
  3. No version history.“When did we add the no-any rule?” can be answered with git log .cursorrules, but only crudely. There's no semantic versioning, no changelog, no “rule v2.1 tightens this”.
  4. No reuse across projects. The TypeScript-strict rules you wrote for one repo get re-typed for the next. Every repo is its own snowflake.
  5. No deactivation path.If a rule is wrong, you find out when the AI generates wrong code, not from a lint warning. There's no npm audit for prompts.
  6. Onboarding cost. A new engineer joining the team has to read four config files in four formats and figure out which one is authoritative — usually nobody knows.

Strategies people try (and why they break)

Strategy A — “Just use one tool”

Tempting, doesn't work in practice. Different team members prefer different IDEs. Different tasks favour different tools (Cursor for tight inline edits; Claude Code for multi-file refactors; Copilot for autocomplete). Forcing one tool wastes more time than it saves.

Strategy B — Symlinks

.cursorrules → copilot-instructions.md. Cute, but the files diverge in syntax (Windsurf's tag-based, Claude's YAML-frontmatter) and you can't symlink across those. Also .github/copilot-instructions.md is in a subdirectory which complicates everything.

Strategy C — Generate from a single source

Write your conventions once in some canonical format and generate the four IDE files at build time with a script. This works — but the script is its own maintenance burden, and most teams never get past the “I'll do it later” stage.

The unified-format approach

We built Skillwright because Strategy C is the right answer and the script is the wrong artifact. Skillwright is a desktop app that holds your skills in a canonical format (YAML-frontmatter SKILL.md), then compiles to all four IDE-native formats — .cursorrules, .windsurfrules, copilot-instructions.md, and Claude Code's SKILL.md folders — and deploys the right files to the right paths in every project you choose.

You author once. You version once. When you fix a rule, the fix propagates to every IDE in every project. Drift becomes a thing Skillwright shows you, not a thing you discover by accident.

We're also publishing a small library of MIT-licensed starter skills — code review, commit conventions, TypeScript strict, security review, TDD, accessibility — that you can drop in without writing anything from scratch.

Comparison summary

If you're picking just one format because you only use one tool:

If you use more than one tool — which most teams do — Skillwright turns the four-files problem into a one-library decision.

Further reading