Most comparisons of AI coding tools rank them on a handful of tasks and a pricing table. Both go stale within months: all three products ship changes constantly, and their plans and model lineups change with them. Earlier versions of this post did exactly that, with April 2025 prices and a five-task “benchmark” that wasn’t reproducible. This version is different. It compares only what each vendor documents (checked on October 10, 2026), shows how to set up one repository so all three behave the same way, and gives three workflows you can run in any of them.
⚡ TL;DR
- All three now cover the same broad ground: an agent in the editor or terminal, cloud agents that work on a branch and open pull requests, automated PR review, hooks, and MCP tools. The differences are in where you work and how you control them.
- Pick by workflow: Claude Code if your team lives in the terminal and wants scriptable runs (
claude -p); Cursor if you want an AI-first editor; Copilot if you’re standardized on GitHub and want agents in issues and pull requests.- Put shared instructions in
AGENTS.md. Cursor and Copilot read it, and Claude Code reads it when there’s noCLAUDE.md, or through an@AGENTS.mdimport.- Enforce limits with hooks and CI, not instructions: a hook can deny edits to
infra/whatever the model decides.- Check current prices on each vendor’s pricing page; don’t trust a blog table, including old versions of this one.
What each tool offers, from the vendor docs
| Capability | Claude Code | Cursor | GitHub Copilot |
|---|---|---|---|
| Where you use it | Terminal CLI, IDE extensions (VS Code, JetBrains), desktop app, web | The Cursor editor, plus a CLI | IDE extensions, GitHub.com, Copilot CLI |
| Agent that edits and runs commands locally | Yes (the core product) | Agent in the editor | Agent mode in the IDE; Copilot CLI |
| Cloud agent that works on a branch | Claude Code in the cloud | Cloud Agents (isolated VMs; push a branch for handoff) | Copilot cloud agent |
| Automated PR review | Code review and CI/CD integrations, including GitHub Actions | Bugbot | Copilot code review |
| Repository instructions | CLAUDE.md, .claude/rules/, or AGENTS.md | .cursor/rules/*.mdc or AGENTS.md | .github/copilot-instructions.md, .github/instructions/*.instructions.md, or AGENTS.md |
| Hooks | Yes (PreToolUse, PostToolUse and more) | Yes | Yes |
| MCP tools | Yes | Yes | Yes |
| Non-interactive / CI runs | claude -p with --allowedTools | CLI headless mode | Copilot CLI programmatic mode |
Product names change: Copilot’s agent that works from issues is now documented as Copilot cloud agent, and Cursor’s Background Agents became Cloud Agents. Check the links at the end before relying on a specific feature.

Choose by workflow
- Terminal-first teams and automation: Claude Code. It started as a CLI, runs non-interactively with
claude -p, and its hooks and permission rules (allow,ask,denyin settings) give fine control over what it can run. - Editor-first teams: Cursor. The agent lives in the editor, rules can be scoped by path, and Cloud Agents and Bugbot extend it to branches and PRs.
- GitHub-centered teams: Copilot. Agents start from issues and pull requests on GitHub, review comes built in, and administration happens in the organization’s Copilot settings.
Many teams use more than one. That works if the repository, not each tool, holds the rules, which is the setup below.
Step 1: One instructions file for every tool
Each vendor documents AGENTS.md support:
- Cursor supports
AGENTS.mdin the project root and subdirectories, as a plain-markdown alternative to project rules. - Copilot uses
AGENTS.mdfiles anywhere in the repository for agents, with the nearest one in the directory tree taking precedence. - Claude Code reads
AGENTS.mdonly when there’s noCLAUDE.mdin the working directory or above it. If you need aCLAUDE.md, start it with@AGENTS.mdto import the shared file, then add Claude-specific lines.
Keep the file short and concrete. Claude Code’s docs recommend under 200 lines per instruction file and instructions specific enough to verify (“Run npm test before committing”, not “test your changes”). A CI check keeps the setup from drifting:
"""CI check: one source of agent instructions (AGENTS.md) that Claude Code, Cursor and Copilot all read."""
import pathlib
import sys
root = pathlib.Path(sys.argv[1] if len(sys.argv) > 1 else ".")
errors = []
agents = root / "AGENTS.md"
if not agents.exists():
errors.append("AGENTS.md missing at the repository root")
claude = root / "CLAUDE.md"
if claude.exists() and not claude.is_symlink() and "@AGENTS.md" not in claude.read_text():
# Claude Code reads AGENTS.md only when no CLAUDE.md exists; otherwise CLAUDE.md must import it.
errors.append("CLAUDE.md exists but doesn't import @AGENTS.md, so Claude Code won't read AGENTS.md")
for extra in [root / ".github/copilot-instructions.md", *root.glob(".cursor/rules/*.mdc")]:
if extra.exists() and agents.exists():
shared = set(agents.read_text().splitlines()) & set(extra.read_text().splitlines()) - {""}
if len(shared) > 3:
errors.append(f"{extra.relative_to(root)} repeats {len(shared)} lines of AGENTS.md; keep tool-specific rules only")
if agents.exists() and len(agents.read_text().splitlines()) > 200:
errors.append("AGENTS.md is over 200 lines; Claude Code's docs recommend under 200 lines per instruction file")
print("\n".join(errors) or "instructions: OK")
sys.exit(1 if errors else 0)Step 2: Enforce limits with a hook
An instruction like “don’t edit infrastructure” is a preference. A hook is enforcement. In Claude Code, a PreToolUse hook receives the tool name and input as JSON on stdin; for the Edit, Write and Read tools, tool_input.file_path is always an absolute path. Printing a permissionDecision of deny blocks the call and tells Claude why:
#!/usr/bin/env python3
"""Claude Code PreToolUse hook: deny edits to paths that need a human (infra, CI, secrets)."""
import fnmatch
import json
import os
import sys
PROTECTED = ["infra/*", ".github/workflows/*", "*.pem", ".env*", "migrations/*"]
event = json.load(sys.stdin)
path = event.get("tool_input", {}).get("file_path", "").replace("\\", "/") # absolute for Edit/Write/Read
root = os.environ.get("CLAUDE_PROJECT_DIR", "").replace("\\", "/").rstrip("/") + "/"
rel = path[len(root):] if root != "/" and path.startswith(root) else path
if any(fnmatch.fnmatch(rel, pat) for pat in PROTECTED):
print(json.dumps({"hookSpecificOutput": {
"hookEventName": "PreToolUse", "permissionDecision": "deny",
"permissionDecisionReason": f"{rel} is protected: propose the change in the PR description instead"}}))
sys.exit(0) # no output = no decision; the normal permission flow applies{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [{"type": "command", "command": "python3 \"${CLAUDE_PROJECT_DIR}/.claude/hooks/protect_paths.py\""}]
}
]
}
}Save the script as .claude/hooks/protect_paths.py and the configuration in .claude/settings.json. Cursor and Copilot have their own hook systems with different configuration formats, so port the same rule to each; your CI should enforce it too (for example with CODEOWNERS on infra/), because CI applies whichever tool wrote the change. The test feeds the hook sample events and runs the instructions check on a temporary repository:
set -e
T=$(mktemp -d); export CLAUDE_PROJECT_DIR=$T
echo '--- hook'
for p in "$T/src/app.py" "$T/infra/stack.ts" "$T/.env.production" "$T/.github/workflows/deploy.yml"; do
printf '{"tool_name":"Edit","tool_input":{"file_path":"%s"},"tool_use_id":"t1"}' "$p" | python3 protect_paths.py | sed "s#^#$(basename $p): #" || true
printf '{"tool_name":"Edit","tool_input":{"file_path":"%s"}}' "$p" | python3 protect_paths.py | grep -q deny || echo "$(basename $p): allowed (no output)"
done
python3 -c "import json;json.load(open('settings.json'))" && echo "settings.json: valid JSON"
echo '--- instructions check'
printf '# Build\nRun make test before every commit.\n' > $T/AGENTS.md
printf '## Claude Code\nUse plan mode under src/billing.\n' > $T/CLAUDE.md
python3 check_instructions.py $T || true
printf '@AGENTS.md\n\n## Claude Code\nUse plan mode under src/billing.\n' > $T/CLAUDE.md
python3 check_instructions.py $T--- hook
app.py: allowed (no output)
stack.ts: {"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "deny", "permissionDecisionReason": "infra/stack.ts is protected: propose the change in the PR description instead"}}
.env.production: {"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "deny", "permissionDecisionReason": ".env.production is protected: propose the change in the PR description instead"}}
deploy.yml: {"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "deny", "permissionDecisionReason": ".github/workflows/deploy.yml is protected: propose the change in the PR description instead"}}
settings.json: valid JSON
--- instructions check
CLAUDE.md exists but doesn't import @AGENTS.md, so Claude Code won't read AGENTS.md
instructions: OKThe application file passes through with no decision, the three protected paths are denied with a reason the agent can relay, and the instructions check catches a CLAUDE.md that would hide AGENTS.md from Claude Code.
Step 3: Three workflows that work in any of them
Tests for legacy code
- Ask the agent to read the module and list its behaviors as test names first, without writing code. Review the list; it’s your spec.
- Have it write characterization tests that pass against the current code, including the odd behavior. Don’t let it “fix” anything yet.
- Run the suite and check coverage. Ask for tests for the uncovered branches only.
- Only then start refactoring, with the tests as a safety net.
Dependency upgrades
- Give the agent the official migration guide or changelog for the version jump, not just the version number; models’ knowledge of recent releases is incomplete.
- Ask for a plan: affected files and the breaking change behind each. Approve it before edits.
- Upgrade one package per pull request, with the lockfile change in the same PR, and run the full test suite.
Debugging with full context
- Paste the exact error, the command that produced it and what changed recently. Ask for hypotheses ranked by likelihood, each with a way to test it.
- Let the agent run the cheapest check first (a log query, a failing test), not the most interesting fix.
- Once fixed, ask for a regression test that fails without the fix.
In every workflow, the agent proposes and runs checks; a human reviews the diff. That holds whichever tool you use.
Running them in CI
All three can run outside an interactive session. For example, Claude Code’s non-interactive mode is claude -p "Find and fix the bug in auth.py" --allowedTools "Read,Edit,Bash", where the allowed tools list limits what it can do without asking. In CI, run agents with a scoped token, no production credentials, and the same gates you’d apply to a human’s PR; see CI gates for agent PRs.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Claude Code ignores AGENTS.md | A CLAUDE.md exists in the directory or above | Add @AGENTS.md at the top of CLAUDE.md |
| Cursor ignores a rule file | Plain .md in .cursor/rules | Project rules must use the .mdc extension |
| Tools behave differently on the same repo | Rules copied into each tool’s file and drifted | Shared rules in AGENTS.md only; run the check in CI |
| Hook never blocks on Windows | Backslash paths compared with forward slashes | Normalize separators first, as the script does |
| Agent follows instructions inconsistently | Long, vague instruction file | Under 200 lines, concrete and verifiable rules |
FAQ
Which one is best?
The one that fits where your team works and that you can control. Trial each on your own repository for a week with the same instructions and gates, and compare merged PRs and review effort, not demos.
Why no pricing table?
Plans and usage limits change often, and a stale table misleads. Check each vendor’s pricing page when you decide.
Can I use two of them on one repository?
Yes, with shared instructions in AGENTS.md and enforcement in hooks and CI.
Do these tools see my secrets?
They see what’s in the files and commands they can access. Keep secrets out of the repository and exclude sensitive paths; see secret-aware context filters.
Official documentation
- Claude Code overview, CLAUDE.md and AGENTS.md, hooks reference, non-interactive mode
- Cursor rules and AGENTS.md, Cloud Agents, Bugbot, hooks
- Copilot repository instructions and AGENTS.md, Copilot cloud agent, Copilot code review
Last updated on October 10, 2026
Watch: 100 Days of AI on YouTube
Short videos from CheatCoders, one AI engineering topic per day.
Most viewed
- Python Decorators Explained: From Simple Wrappers to Production Patterns
- Claude Code vs Cursor vs GitHub Copilot: Choose by Workflow, and Set Up One Repo That Works With All Three
- AI Agent Frameworks in 2025: LangGraph vs CrewAI vs AutoGen vs Raw API
- Python String Methods: Every str Method With Real Production Examples
- REST API Design Best Practices: The Patterns That Make APIs a Joy to Use
Newly added
- AWS Systems Manager Parameter Store: Hierarchical Runtime Config for Coding Agents
- Amazon Cognito Identity Pools: Federate Coding-Agent Tool Callers Without Long-Lived Keys
- Amazon Athena for Coding Agents: Query Tool Audit Logs and Eval Traces on S3 Without a Warehouse
- AWS Batch for Coding Agents: Parallel Overnight PR Reviews and Long-Running Jobs Without Lambda Timeouts
- Amazon Bedrock Prompt Management: Version and A/B Test Coding-Agent System Prompts
Deep-dive PDF
Get the expanded guide for this post — extra diagrams-style checklists, failure modes, and a production walkthrough. Free when you subscribe to CheatCoders.
Already subscribed? or open the subscribe page.
Discover more from CheatCoders
Subscribe to get the latest posts sent to your email.
