Skip to main content
Back to Blog
AI ToolsClaude CodeGitHub CopilotCursorMCP

Extending AI Coding Assistants: Claude Code vs. GitHub Copilot vs. Cursor

May 24, 202614 min

If you have used Claude Code, VS Code GitHub Copilot, and Cursor in the same week, you have probably noticed they share a vocabulary — agents, skills, commands, instructions, hooks, plugins, connectors — and that almost none of those words mean the same thing in any two products. A "skill" in Claude Code is a folder. A "skill" in Copilot is also a folder, but discovered from a different path with stricter naming rules. A "connector" in Anthropic-land is a remote OAuth-authenticated MCP server with a UI listing. A "connector" in GitHub- land is... not a thing GitHub uses that word for at all.

I spent the last few months packaging an MCP server (applypass-mcp) and a plugin marketplace (applypass-plugins) across all three ecosystems, plus OpenAI's Codex CLI, and walked away with a much clearer picture of where these primitives actually overlap, where they diverge, and what the right strategy is if you want to author once and ship everywhere.

This is the write-up.


The seven primitives, defined once

Before any cross-tool comparison, you need a stable definition for each word, because the vendors use them inconsistently. Here is the dictionary I'll use for the rest of the post:

TermWhat it actually is
InstructionsPlain-text Markdown files the harness reads from disk and injects into the model's context — project memory.
SkillsDiscoverable, model-invoked procedural knowledge bundles (a folder containing SKILL.md plus optional scripts/references). The model decides when to load them.
Sub-agentsSpecialized personas the harness can spin up with their own tool whitelist and system prompt. Different from the top-level agent.
Slash commands / promptsUser-invoked Markdown files. The user explicitly types /foo to fire them.
HooksShell commands (or HTTP calls, or MCP calls) the runtime triggers at lifecycle events: PreToolUse, SessionStart, PostToolUse, etc. Deterministic, local.
PluginsPackaged directories bundling some combination of the above plus MCP server refs, installed from a marketplace.
ConnectorsAnthropic-specific noun for remote OAuth-authenticated MCP servers with a UI listing in Claude Desktop / claude.ai. Nobody else uses this word.

The crucial insight that's easy to miss: every tool here does plain text injection in the harness. The model itself doesn't understand any of these file formats. The CLI or IDE extension reads the files off disk, parses frontmatter, decides what's in scope, and assembles the prompt. What you're comparing is which directories each harness walks, what schema it parses, and where in the API request the content lands.

That framing makes the differences a lot less mystical.


The cheat sheet

Here is the whole comparison condensed into one table. The rest of the post is me explaining the entries that are surprising or load-bearing.

PrimitiveClaude CodeGitHub Copilot (VS Code)Cursor
Project instructionsCLAUDE.md, .claude/CLAUDE.md, subdir CLAUDE.md (on-demand).github/copilot-instructions.md, AGENTS.md, CLAUDE.md (all merged), *.instructions.md with applyTo: glob.cursor/rules/*.mdc (Always / Auto-attached / Agent-requested / Manual), AGENTS.md, .cursorrules (legacy)
@import recursion in instructions✅ recursive, 5 hops❌ literal text❌ literal text
Reads AGENTS.md?❌ (open since 2025, issue #6235)✅ since late 2025✅ native
Skills (Anthropic SKILL.md spec).claude/skills/<name>/SKILL.md✅ auto-discovers .claude/skills/, .github/skills/, .agents/skills/, ~/.copilot/skills/✅ as "agent-decided rules"
Sub-agents.claude/agents/<name>.md.github/agents/<name>.agent.md (different schema, mcp-servers block, handoffs)None — uses rule-based scoping instead
Slash commands.claude/commands/*.md + skills /skill-name.github/prompts/<name>.prompt.md + /prompt-name@ruleName for manual rules; native custom commands
Hooks✅ first-class, ~32 events, settings.json❌ no standalone hooks; only inside the plugin format✅ added in a late-2025 release, ~23 events
Plugins.claude-plugin/plugin.json + git marketplaces (GA Oct 2025)✅ preview: auto-detects 4 manifest paths including Claude's❌ no native bundle format — VS Code extensions + MCP servers
"Connector" conceptYes — remote OAuth MCP, synced across Claude appsNo — uses "MCP server" + GitHub App ExtensionsNo — uses "MCP server"
MCP supportFirst-class client, @server://resource refsFirst-class, JSON config or per-agent mcp-servers: blockFirst-class, .cursor/mcp.json

Instructions: how each tool reads project memory

Every modern coding assistant reads a "magic Markdown file" at the repo root. They all look the same from a distance and they all behave differently up close.

Claude Code

Claude Code reads CLAUDE.md and (with subdirectory CLAUDE.md files) lazily loads them when work touches that subtree. The single most interesting feature is @import: lines like @README.md or @docs/architecture.md recursively pull in those files, up to 5 hops deep, resolved relative to the importing file. Nobody else does this.

A subtle and undocumented mechanism: CLAUDE.md is not placed in the system prompt. The harness wraps it in a <system-reminder> block and re-injects it into a user message on every turn. The trace looks roughly like:

<system-reminder>
# claudeMd
Contents of /path/to/CLAUDE.md (project instructions):
…your CLAUDE.md content…
</system-reminder>

That has two consequences. First, your CLAUDE.md survives long sessions and compaction events because it's re-attached every turn. Second, you pay for it every turn in tokens — Anthropic's own guidance is to keep it under ~80–300 lines, because the frontier models reliably follow roughly 150–200 instructions and the base Claude Code system prompt already consumes ~50 of those.

Claude Code does not natively read AGENTS.md. The open issues (#6235, #34235) have been ignored for long enough that the community workaround — a one-line CLAUDE.md containing @AGENTS.md, or a symlink — has become the de facto recommendation.

VS Code Copilot

Copilot's discovery pipeline is the most permissive of the three. At the start of every turn it gathers, merges, and injects:

  • .github/copilot-instructions.md
  • AGENTS.md
  • CLAUDE.md (yes — Copilot reads CLAUDE.md too, since late 2025)
  • Any *.instructions.md whose applyTo: glob frontmatter matches the current file scope
  • User-level instructions from VS Code settings

No documented ordering between them; "personal > repository" is the only explicit precedence rule for conflicts. The diagnostics view (right-click in Chat → Diagnostics) is the most useful debugging tool in this entire space, because it shows every loaded file and any parse errors.

*.instructions.md with applyTo: is the killer feature here — Copilot's equivalent of Claude's hierarchical CLAUDE.md, except declarative rather than implicit:

---
applyTo: '**/*.tsx,**/*.ts'
---
TypeScript-only conventions go here.

Cursor

Cursor's .cursor/rules/*.mdc files are the richest instruction format of the three, with four attachment modes selected by frontmatter:

---
description: 'Frontend component patterns for React'
globs: ['src/components/**/*.tsx']
alwaysApply: false
---
TypealwaysApplyglobsdescription
Alwaystrueoptional
Auto-attachedfalsesetoptional
Agent-requestedfalserequired — agent decides
Manual (@ruleName)falseoptional

Cursor also reads AGENTS.md (and explicitly endorses it as a migration target from the legacy .cursorrules). Subdirectory .cursor/rules/ folders work like Claude's per-folder CLAUDE.mds.

Two annoying Cursor quirks worth knowing: the agent will strip YAML frontmatter when generating .mdc files via chat, leaving the rule invalid; and the documented folder-based RULE.md format doesn't actually load in practice — only flat .mdc files do, despite what the docs say.

Honest comparison

For pure power, Cursor's rule taxonomy is the most expressive — four attachment modes with declarative scoping. For ergonomics, Claude's @import recursion is unmatched. For breadth, Copilot reads everyone's format (including yours, literally).

If you only want to maintain one file: AGENTS.md is the closest thing to a portable lingua franca. Cursor reads it natively. Copilot reads it natively. Codex CLI treats it as canonical. Claude Code does not read it natively, but a one-line CLAUDE.md that says @AGENTS.md makes it work everywhere.


Skills: Anthropic seeded a standard

Skills are model-invoked procedural knowledge. The format Anthropic shipped is a folder containing SKILL.md plus optional scripts/, references/, and assets/ subdirectories. The frontmatter looks like this:

---
name: code-reviewer
description: Review staged git changes for security, logic, and style issues. Use when…
allowed-tools: [Bash, Read, Grep]
disable-model-invocation: false
---

Body: the actual procedure, keep under ~2000 words.

Then progressive disclosure: scripts/, references/, assets/ are only loaded
on demand via the Read tool.

The interesting cross-tool fact: GitHub Copilot adopted Anthropic's SKILL.md format almost verbatim, and it auto-discovers four directory paths including .claude/skills/ — meaning a Claude Code skill drops into VS Code Copilot for free, with two caveats:

  1. Don't put a slash or colon in the name field. Copilot silently fails to load namespaced names like myorg/skill.
  2. Copilot ignores argument-hint and model in the frontmatter.

Cursor recognizes the same format as "agent-decided rules" — the description is shown to the model, which then decides whether to pull in the body. This is actually exactly how Anthropic's skill discovery works under the hood, which is not a coincidence.

The single most important field, across all three, is description. The model matches on it. Anthropic's own internal guidance is that descriptions should be "pushy" — explicit trigger phrases, examples of when to fire — because models undertrigger skills by default. If your skill never activates, your description is too vague.


Sub-agents: Claude's first-class concept, Copilot's parallel format, Cursor's omission

Claude Code's sub-agents live in .claude/agents/<name>.md and behave as additional tool entries in the API request. They have their own tool whitelist (allowed-tools), permission mode, and system prompt.

VS Code Copilot has a parallel concept — .github/agents/<name>.agent.md — with a different schema:

---
description: Reviews PRs against our team's coding standards
tools: ['read', 'edit', 'search', 'custom-mcp/tool-1']
model: claude-sonnet-4-5
mcp-servers:
  custom-mcp:
    type: local
    command: some-command
    env:
      ENV_VAR: ${{ secrets.COPILOT_MCP_ENV_VAR }}
handoffs:
  - label: Start Implementation
    agent: implementation
    prompt: 'Now implement the plan above.'
---

The two formats are not interchangeable. Copilot's tools field uses Copilot tool names; the mcp-servers: block is unique to Copilot; the handoffs: block — one-click transitions to a sibling agent — has no Claude equivalent. Copying a Claude Code agent file into .github/agents/ will silently fail to materialize as a Copilot custom agent.

Cursor has no sub-agent concept at all — it leans on rule-based scoping instead.


Commands: who can call them, who picks them

Slash commands are user-invoked Markdown files. The user types /foo and the file body becomes a prompt.

  • Claude Code.claude/commands/*.md, plus every skill is exposed as /<skill-name> if invoked manually.
  • Copilot.github/prompts/<name>.prompt.md with optional frontmatter selecting agent/model/tools.
  • Cursor — manual rules invoked via @ruleName, plus native custom commands defined in the UI.

These are roughly equivalent in capability. The differentiator is whether the file format also carries metadata that controls which agent runs or which tools are exposed during the command — Copilot's prompt files do, Claude's commands don't (they're just prompts), Cursor's are UI-managed.


Hooks: the biggest gap between the three

Hooks are where the three tools diverge most sharply. A hook is a shell command the runtime triggers at a lifecycle event — PreToolUse, SessionStart, PostToolUse, and so on.

Claude Code

Claude Code has by far the most developed hook system. The event catalog is ~32 events spanning session lifecycle, every tool call, sub-agent lifecycle, state changes (FileChanged, CwdChanged, InstructionsLoaded), and MCP interactions. The schema:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "./scripts/audit.sh",
            "timeout": 30,
            "statusMessage": "Auditing command"
          }
        ]
      }
    ]
  }
}

The five handler types are command, http, mcp_tool, prompt, and agent — the last two are particularly interesting because they let you gate an action on an LLM-evaluated yes/no decision or on a verifier sub-agent's output.

Exit-code semantics: 0 = success, 2 = blocking error (the action is prevented and stderr is fed back to the model as the reason), anything else = non-blocking error. For PreToolUse, a JSON object on stdout can rewrite the tool input before it runs:

{
  "hookSpecificOutput": {
    "permissionDecision": "allow",
    "updatedInput": { "command": "rewritten command" },
    "additionalContext": "shown to Claude"
  }
}

Cursor

Cursor added hooks in a late-2025 release with a schema that's almost a copy of Claude Code's, with three notable differences:

  1. Event names are camelCase (preToolUse) instead of PascalCase.
  2. There are dedicated events for shell execution (beforeShellExecution, afterShellExecution) and MCP execution (beforeMCPExecution, afterMCPExecution), separate from generic preToolUse.
  3. There's a failClosed: true opt-in. If the hook crashes or times out, Claude Code and Codex CLI fail open (the action proceeds). Cursor fails open by default too — but you can flip individual hooks to fail closed when they're security-critical. This is a meaningful improvement.

Cursor's hooks also have an agentic-loop primitive: a stop or subagentStop hook can return a followup_message that auto-submits as the next prompt, with a loop_limit (default 5). Neither Claude Code nor Copilot has this.

Copilot

Copilot has no standalone hook system. Hooks exist only as components inside the agent-plugins preview format (more on that next). There is no ~/.copilot/hooks.json for personal-machine event interception.

The closest thing for the Copilot cloud agent is GitHub Actions — workflows triggered on issue_comment or pull_request events. Functionally equivalent for cloud workflows, but it isn't a hook system in the local- developer sense.

Hooks portability

If you want hooks that run in Claude Code and Cursor and Copilot's plugin format, the realistic playbook:

  1. Author against the Claude Code event vocabulary (PreToolUse, PostToolUse, SessionStart, UserPromptSubmit, Stop) — this is the intersection set.
  2. Use only type: "command" handlers (the only handler all three implement).
  3. Read JSON from stdin, write JSON to stdout for decisions, use exit 2 + stderr for blocks.
  4. Reference ${CLAUDE_PLUGIN_ROOT} — Codex aliases it, Copilot's plugin loader honors it.
  5. Keep a parallel ~/.cursor/hooks.json in camelCase if Cursor support matters. There's no automatic translator.

Plugins: the surprise winner is the Claude format

Claude Code plugins went GA in October 2025. A plugin is a self-contained directory bundling skills, commands, agents, hooks, MCP server refs, LSP servers, output styles, themes, and settings, distributed via a Git-hosted marketplace manifest. The plugin manifest:

{
  "name": "applypass-devkit",
  "version": "1.2.0",
  "description": "ApplyPass developer toolkit",
  "skills": "./skills/",
  "commands": ["./commands/deploy.md"],
  "agents": ["./agents/reviewer.md"],
  "hooks": "./hooks/hooks.json",
  "mcpServers": "./.mcp.json"
}

Only name is required. The marketplace manifest at .claude-plugin/marketplace.json lists plugins with version, category, and source. Users install via /plugin marketplace add owner/repo then /plugin install <name>@<marketplace>.

Then comes the surprise: VS Code Copilot's preview agent-plugins format auto-detects four manifest paths in order, and .claude-plugin/plugin.json is one of them. Copilot honors ${CLAUDE_PLUGIN_ROOT}. It picks up the same skills directory layout. It runs Claude-format hooks (subset of events).

This means a well-authored Claude Code plugin — .claude-plugin/plugin.json at the root, skills/ and commands/ and hooks.json and .mcp.json in standard locations — installs into VS Code Copilot unchanged. You build once, you ship to both.

Cursor is the holdout. Cursor has no plugin bundle format as of May 2026. "Cursor plugin" colloquially means either a VS Code extension or an MCP server entry in .cursor/mcp.json, both of which are pre-existing mechanisms. The Anthropic knowledge-work-plugins repo migration to Cursor that I worked through earlier this year confirmed this in practice — you end up shipping the MCP server and abandoning the bundled skills/commands/hooks story, or telling users to install components individually.

(Codex CLI also has plugins, with a .codex-plugin/plugin.json manifest heavily mirrored on Claude's. Codex even goes out of its way to alias CLAUDE_PLUGIN_ROOT and CLAUDE_PLUGIN_DATA env vars inside its plugin hooks for cross-compat. A separate manifest is needed, but it's a 30-minute copy-and-rename job.)


Connectors: the word is Anthropic-specific

This is the term with the most cross-vendor confusion, so let's be precise.

A Connector, in Anthropic's vocabulary, is a remote MCP server packaged for end-user consumption — typically OAuth-authenticated, hosted by a third party, and listed in the directory at claude.ai/connectors. The Help Center is explicit: "A Connector is a remote MCP server… that Claude calls on your behalf, after you authorize it via OAuth."

Three flavors:

  1. Pre-built connectors — Anthropic-curated (Google Drive, Gmail, GitHub, Notion, Slack, Atlassian, etc.). One-click OAuth.
  2. Custom remote connectors — any HTTPS MCP server URL the user pastes into Customize → Connectors.
  3. Messages API mcp_servers block — gated behind the anthropic-beta: mcp-client-2025-11-20 header.

The defining property versus a local MCP server is that the connection origin is Anthropic's servers, not the user's machine. The implication is that installing a connector on Claude Desktop Mac instantly makes it available on Windows desktop and the web — because the integration lives in your Anthropic account.

GitHub Copilot does not use the word "connector." The discovery surface is the GitHub MCP Registry at github.com/mcp; the integration mechanism is plain MCP servers configured at .vscode/mcp.json (repo) or ~/.copilot/mcp.json (user) or repo-level for the cloud agent. There's also the unrelated GitHub- App-based Copilot Extensions architecture — an HTTPS webhook a GitHub App exposes for @app-name chat mentions — but that's a separate protocol, not MCP.

Cursor doesn't use the word either. Cursor's MCP system covers stdio, SSE, and Streamable HTTP transports including OAuth. Configured in .cursor/mcp.json. One-click install URLs exist via Cursor Marketplace and cursor.directory. The one notable Cursor limit: a hard ceiling of roughly 40 active tools across all MCP servers; exceed it and the agent silently loses access to some.

The bottom line on the noun: when Anthropic says "Connector," they mean a hosted remote OAuth MCP server with a UI listing. When anyone else says "connector" in this space, they usually mean "MCP server." The underlying protocol is the same.


What's actually portable

The architecturally important conclusion from all of this: MCP is the cross-vendor standard that quietly won. Every major coding-assistant vendor in 2026 — Anthropic, GitHub, OpenAI, Cursor, Windsurf — consumes MCP. The plugin formats and connector listings are convenience wrappers on top.

If you build a single thing today, build a remote MCP server with OAuth + Dynamic Client Registration (DCR) per RFC 7591. That single artifact reaches:

SurfaceHow it gets in
Claude Desktop / claude.aiCustom remote connector — paste the URL
Claude Code.mcp.json entry or bundled in a plugin
Claude APImcp_servers array on the Messages API
Cursor.cursor/mcp.json entry (one-click install URL works)
VS Code Copilot.vscode/mcp.json entry or user MCP config
Copilot CLI~/.copilot/mcp.json
Copilot cloud agentRepo-level MCP registry config
Codex CLI.mcp.json user config or plugin

Same backend. Eight surface integrations. The OAuth + DCR combination is what makes this work cleanly — every harness can self-register as a client without you handing out client IDs.

For the convenience layer above MCP, the practical advice depends on who you want to reach:

  • Solo dev / Claude Code only — just write skills, commands, agents directly in your .claude/ directory.
  • Want to ship to other Claude Code users — package as a plugin in a git-hosted marketplace.
  • Want to also reach VS Code Copilot — same plugin format. The .claude-plugin/plugin.json is auto-detected. Free.
  • Want to also reach Cursor — ship the MCP server, accept that bundled skills/commands/hooks don't transport. Document them as installable rules.
  • Want to also reach Codex CLI — copy your plugin manifest to .codex-plugin/plugin.json with minor edits. Or just ship the MCP server and let Codex users wire it up themselves.
  • Want to reach Claude Desktop / claude.ai users — host the MCP server remotely with OAuth-DCR and submit it to the Anthropic Connectors Directory. This is a productization step (review + listing), not engineering.

The case for also building a GitHub Copilot Extension (the GitHub App architecture) is weak unless you specifically want @your-app mentions on github.com PRs and issues. The Extension format doesn't carry skills or commands — it's a chat-handler webhook. Skip it unless that exact surface is the goal.


tl;dr

  • Instructions — every tool reads a magic Markdown file at the repo root, and they almost all read each other's. AGENTS.md is the portable lingua franca. Claude Code is the lone holdout; bridge it with a one-line CLAUDE.md containing @AGENTS.md.
  • Skills — Anthropic's SKILL.md format is the de facto standard. Copilot auto-discovers .claude/skills/. Cursor reads them as agent-decided rules. Write one set, run everywhere.
  • Sub-agents — Claude and Copilot have parallel-but-incompatible schemas. Cursor has no equivalent. Not portable.
  • Slash commands — roughly equivalent across the three, separate file layouts. Not portable, but trivially translatable.
  • Hooks — Claude Code has the richest system (~32 events). Cursor has ~23 with a failClosed opt-in nobody else has. Copilot has none outside the plugin format. Author against the intersection set if you need portability.
  • Plugins — Claude Code's format is the winner: VS Code Copilot auto-detects it, Codex CLI mirrors it. Cursor has no plugin bundle format at all. The Claude plugin you build is the most portable plugin you can build.
  • Connectors — the word means "remote OAuth MCP server with a UI listing" in Anthropic-land and nothing in particular in Copilot- or Cursor-land. The underlying transport is MCP, which is universal.
  • What to build — a single remote MCP server with OAuth + DCR reaches every coding-assistant ecosystem in 2026. Bundle a Claude-format plugin on top of it if you want skills and commands too. Everything else is a convenience wrapper on those two artifacts.

If you only remember one thing: MCP is the standard. Plugins and connectors are distribution sugar. Build the MCP server first; everything else is a 30-minute manifest file.