Cursor vs VS Code stopped being an either-or choice this month. On October 12, 2026, Cursor moved its paid plans into The X Subscription, with Free at $0, Plus at $8, Premium at $30, Super at $100 and Ultra at $200 a month, while VS Code stayed free and GitHub Copilot kept its own credit-based plans. Plenty of developers now keep both editors installed and open the same repository in whichever one fits the task.
That habit breaks quietly. One editor follows your coding rules and the other ignores them. A test task exists in one place but not the other. Somebody commits a personal theme, and the diff noise starts. This tutorial fixes the repository side of the problem, and it pairs with our settings sync walkthrough, which handles your personal user settings across the two editors.
You will build a small Node.js project in 13 steps and about 50 minutes. It carries a shared AGENTS.md, a folder-scoped override, Cursor-only rules, shared VS Code workspace files, two MCP configs without secrets, a drift-check script, a pre-commit hook and a CI job. Every file in the article ran on Node 20 before it went into the text, and the sample output comes from those runs.
The audience for this setup is large. Many developers use Visual Studio Code, and a growing share use Cursor. Those groups overlap heavily, which is exactly why one repository needs to behave in both editors.
Timing matters too. VS Code announced a modernized interface preview on October 15, 2026, Copilot has billed by usage since June 1, 2026, and Cursor changed how third-party models are billed on October 12. Every model call now costs real money in both products, so a clean, short, shared instruction file is no longer a style preference. It is a line item.
This guide stays away from the question of which editor is better. Plenty of articles argue that point, and the answer depends on your tasks, your budget and your tolerance for change. The question here is narrower and more practical: once you decide to use both, what do you commit to the repository so that the second editor does not feel like a stranger’s laptop? We keep the scope tight on purpose. There is no plugin to install, no sync service and no paid tier required.
Don't miss new tech stories on Google
Add Tech Insider once in the Google app and our stories appear in your news suggestions.
Prerequisites and Versions for a Dual-Editor Repo
You need two editors, a runtime for the sample project and a Git setup that can run hooks. None of it costs anything. The table lists what the walkthrough used and how to check your own copy.
| Component | Version used | Check it with |
|---|---|---|
| Visual Studio Code | 1.141 or later (the October 2026 release line) | code --version |
| Cursor | Latest stable build from cursor.com, Free plan is enough | cursor --version |
| Git | 2.x, any current release (tested on 2.43.0) | git --version |
| Node.js | 20 LTS or newer (tested on v20.20.2) | node --version |
| npm | Ships with Node (tested on 10.8.2) | npm --version |
| GitHub Copilot | Free plan at $0 is enough to test chat in VS Code | Sign in from the Accounts menu in VS Code |
| Shell | POSIX shell (Git Bash on Windows) | sh --version or Git Bash |
Install the shell commands for both editors first. In VS Code, open the Command Palette and run the shell command install action. In Cursor, do the same from its Command Palette. After that, code . and cursor . both open the current folder from a terminal. If you want the Copilot sandbox details for the October release, our VS Code 1.141 agent sandbox guide walks through the setup, and local sandboxing for agent sessions reached general availability on October 9, 2026 at no extra Copilot charge.
Budget about 50 minutes. Steps 1 to 4 take roughly 15 minutes, steps 5 to 10 take 20 and the last three take 15, including the canary tests in both editors. Nothing in the project needs a paid plan.
Which File Does Each Editor Read? The Three-Layer Map
Before touching any file, decide what belongs where. A dual-editor repo works when it has three layers. The shared layer holds rules every agent must follow. The editor layer holds files only one editor understands. The personal layer holds your taste and never enters Git.
The shared layer centers on AGENTS.md, a plain Markdown file at the repo root that tells coding agents how to build, test and behave. Community documentation describes it as a format read by Cursor, Copilot, Codex CLI, Windsurf, Zed and others. In a monorepo you can add more of these files in subfolders, and agents use the nearest applicable one. OpenAI’s help center also says Codex can generate a starter AGENTS.md through /init in the ChatGPT desktop app.
One caution shapes the rest of this tutorial. The official VS Code, Copilot and Cursor pages we checked on October 23, 2026 do not promise that a shared AGENTS.md behaves identically in both editors. Secondary documentation says Cursor reads it and lists VS Code among supporting tools, but you should confirm that on your own build. Step 12 gives you a two-minute canary test for exactly that.
| File | Purpose | Cursor | VS Code with Copilot | Commit? |
|---|---|---|---|---|
AGENTS.md | Project-wide commands and rules | Reads it per secondary docs | Listed among supporting tools, verify with the canary | Yes |
src/AGENTS.md | Folder-scoped rules, nearest file wins | Same as above | Same as above | Yes |
.cursor/rules/*.mdc | Cursor-only rules triggered by file globs | Native | Ignored | Yes |
.github/copilot-instructions.md | Copilot repository instructions, here only a pointer | Not its native format | Native | Yes |
.vscode/settings.json | Workspace settings | Reads it (VS Code fork) | Native | Yes |
.vscode/extensions.json | Recommended extensions | Prompts from it | Prompts from it | Yes |
.vscode/mcp.json | MCP servers for VS Code | Ignored | Native | Yes, no secrets |
.cursor/mcp.json | MCP servers for Cursor | Native | Ignored | Yes, no secrets |
*.code-workspace, ~/.cursor, user settings | Personal state | Local | Local | No |
The personal layer deserves as much attention as the other two, because it is where most accidental commits start. Your user-level settings, keybindings, snippets and chat history follow you from project to project, and they should never ride along inside a repository. If you want to move that layer between machines or between the two editors, use the approach in the settings sync tutorial linked in the introduction. Everything in this tutorial lives one level lower, inside the repo itself, where a teammate who has never seen your laptop can still get the same behavior after a clone.
The design rule is simple. Write each instruction once, in the lowest layer that reaches every tool. Only when an instruction truly applies to one editor does it move up into that editor’s own files. If you want to see how Cursor’s rule files work in more depth, our guide to building tooling around Cursor rules covers the frontmatter format and validation.
What Cursor, VS Code and Copilot Cost in October 2026
Cost shapes how long your instruction files should be, so it belongs up front. VS Code itself costs nothing, according to a Microsoft page updated on October 23, 2026. The AI layer is where money enters, through Cursor’s plans or through Copilot’s.
| Product | Plan | Monthly price | What the plan includes |
|---|---|---|---|
| VS Code | Editor | $0 | Free editor, AI through Copilot |
| Cursor | Free | $0 | Entry tier of The X Subscription |
| Cursor | Plus | $8 | Shared usage pool across Cursor and Grok products |
| Cursor | Premium | $30 | Closest replacement for legacy Pro, third-party models billed separately |
| Cursor | Super | $100 | Larger shared usage pool |
| Cursor | Ultra | $200 | Top tier of the shared usage pool plans |
| GitHub Copilot | Free | $0 | 2,000 completions a month, selected models |
| GitHub Copilot | Pro | $10 | Unlimited completions, $15 in monthly credits |
| GitHub Copilot | Pro+ | $39 | Premium models including Opus, $70 in monthly credits |
| GitHub Copilot | Business | $19 per user | Pooled credits, admin controls, 1,900 credits per user |
Three details change the math. First, Cursor’s old Pro plan at $20 a month is a legacy plan that no longer sells to new customers, and Premium at $30 is described as the closest replacement. Second, third-party models such as Claude, GPT and Gemini move to API pricing under the new plans, and they are reportedly billed through prepaid top-ups instead of the shared allowance. Third, Copilot switched to usage-based billing on June 1, 2026, where one AI credit equals $0.01 and code completions stay unlimited and unbilled.
For this tutorial the practical reading is easy. You can run the whole setup for $0 with VS Code, Copilot Free and Cursor Free. Once you pay, every agent session that reads your instruction file spends tokens on it, whether those tokens come out of a Copilot credit balance or a Cursor top-up. A 600-line rules file is a tax on every task. A 40-line one is not. For a wider price comparison that includes Devin, see our Cursor, Devin Desktop and Copilot plan comparison, and for more guides in this area browse the software section.
Steps 1 and 2: Create the Repo and a Baseline Project
Step 1. Create the folder and initialize Git. Use a fresh directory so you can compare behavior without old config getting in the way. The project is a tiny ESM library that turns titles into URL slugs. It is deliberately boring, because the interesting part is the config around it.
mkdir dual-editor-repo && cd dual-editor-repo
git init -b main
mkdir -p src scripts .cursor/rules .github/workflows .vscode .githooks
Step 2. Add the package file, the library and three tests. The package file sets "type": "module" and defines the three scripts the rest of the tutorial leans on. Using Node’s built-in test runner keeps the dependency count at zero, which matters later when your instruction file says to avoid new runtime dependencies.
{
"name": "dual-editor-repo",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"start": "node src/index.js",
"test": "node --test",
"check:editors": "node scripts/check-editor-drift.mjs"
},
"engines": {
"node": ">=20"
}
}
export function slugify(input) {
return String(input)
.normalize("NFKD")
.replace(/[̀-ͯ]/g, "")
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "");
}
import test from "node:test";
import assert from "node:assert/strict";
import { slugify } from "./slugify.js";
test("lowercases and joins words with hyphens", () => {
assert.equal(slugify("Cursor vs VS Code"), "cursor-vs-vs-code");
});
test("strips accents and punctuation", () => {
assert.equal(slugify(" Café, déjà vu! "), "cafe-deja-vu");
});
test("returns an empty string for symbols only", () => {
assert.equal(slugify("***"), "");
});
import { slugify } from "./slugify.js";
const title = process.argv.slice(2).join(" ") || "Cursor vs VS Code on One Repo";
console.log(slugify(title));
Run the tests and the demo to confirm the baseline works before you add any editor config.
npm test
npm start
npm start -- "Hello, World & Café"
Expected output from the run used for this article:
# tests 3
# suites 0
# pass 3
# fail 0
# cancelled 0
# skipped 0
# todo 0
cursor-vs-vs-code-on-one-repo
hello-world-cafe
Three passing tests and two slugs. If the tests fail, check that you are on Node 20 or newer, because the file uses ES modules and the built-in test runner.
Steps 3 and 4: Write the Shared AGENTS.md Files
Step 3. Create the root AGENTS.md. This is the one file you want every agent to follow, so it carries facts any new teammate would need on day one: what the project is, how to install, run and test it, what style to use, what never to touch and what done means. Keep it under 150 lines. The one below is 28.
# AGENTS.md
Shared instructions for every AI coding agent that works in this repository.
Cursor, GitHub Copilot in VS Code and Codex all read this file. Keep it short.
## Project
A tiny Node.js 20+ ESM library that turns titles into URL slugs.
Source lives in `src/`. Helper scripts live in `scripts/`.
## Commands
- Install: `npm install`
- Run the demo: `npm start`
- Run tests: `npm test`
- Check editor config for drift: `npm run check:editors`
## Conventions
- Use ES modules only. No CommonJS `require`.
- Two-space indentation, double quotes, semicolons.
- Every exported function gets a test next to it in `src/*.test.js`.
- Do not add runtime dependencies without asking first.
## Boundaries
- Never edit `package-lock.json` by hand.
- Never commit secrets, tokens or `.env` files.
- Do not touch files under `.github/workflows/` unless the task says so.
## Done means
`npm test` and `npm run check:editors` both exit with code 0.
Notice the structure. The commands section uses exact strings in backticks, and the drift script in step 11 will check that each npm run command named there exists in package.json. That turns a file of prose into something a machine can keep honest. The boundaries section is short on purpose. Agents handle a few firm limits better than a page of soft preferences.
The conventions section should describe your repo as it is, not as you wish it were. If the code uses two-space indentation, say so. If you do not want a new dependency without a conversation, say that too. Avoid vague lines such as write clean code, since no agent can act on them and each one burns tokens in every session.
Step 4. Add a folder-scoped override. In a monorepo, nested files let a package carry its own rules. Agents use the nearest applicable file in the directory tree. We add one inside src/ to keep modules small and pure.
# AGENTS.md for src/
These rules apply only to files inside `src/`. They add to the root file.
- Keep each module under 80 lines.
- Pure functions only. No file system or network access inside `src/`.
- Name test files `<module>.test.js` and keep them beside the module.
Here is the catch. If a tool loads only the nearest file and not the root one, rules like the boundary on secrets would vanish inside src/. The nested file says it adds to the root, but whether a given editor merges the two is a behavior you test, not assume. In the canary step you will check both levels. If an editor does not merge them, copy the two or three rules that must never be lost into the nested file.
Commit the baseline now so later diffs stay readable.
git add -A
git commit -m "chore: baseline project and AGENTS.md"
Steps 5 and 6: Add Cursor Rules and a Copilot Pointer
Step 5. Write Cursor-only rules as .mdc files. Cursor keeps project rules in .cursor/rules/ as .mdc files. Each starts with a small frontmatter block. The description tells the agent when the rule is relevant, globs lets the rule attach to matching files, and alwaysApply forces it into every session. Use globs for most rules. Reserve always-apply for the few lines that truly cannot wait for a match.
---
description: Cursor-only habits for editing JavaScript in this repo
globs: src/**/*.js
alwaysApply: false
---
- Prefer small diffs. Do not reformat lines you did not change.
- When you add an export, add or update its test in the same edit.
- Use the Composer or agent panel for multi-file edits, and Tab for single-line fixes.
- Shared project rules live in the root AGENTS.md. Do not copy them here.
---
description: How to write and run tests in this repo
globs: **/*.test.js
alwaysApply: false
---
- Use `node:test` and `node:assert/strict`. Do not add Jest or Vitest.
- One behavior per test. Name the test after the behavior.
- Run `npm test` after every change to a test file.
Look at what these files leave out. There is no copy of the indentation rule or the dependency rule, because both live in AGENTS.md. What stays here is behavior that only makes sense in Cursor: prefer small diffs, use Composer for multi-file edits and Tab for one-line fixes. The last line of the first rule even points back to the root file, which discourages the next person from pasting shared rules in.
If you want to tune how Cursor applies edits, such as diff versus full rewrite behavior, that belongs in a rule too, and our walkthrough on tuning diff versus rewrite edits with Cursor rules shows the options. Keep those tweaks Cursor-only. VS Code has no matching feature, so they do not belong in the shared layer.
Step 6. Add a Copilot pointer file. GitHub Copilot in VS Code has its own repository instructions file at .github/copilot-instructions.md. Instead of copying your rules into it, make it a two-line pointer to AGENTS.md. That way, even if your Copilot build does not read AGENTS.md on its own, it still reaches the same text.
Follow the instructions in AGENTS.md at the repository root, and the nearest AGENTS.md
in the folder you are editing. Do not duplicate those rules here.
A pointer is a hedge, not a guarantee. Whether the agent follows the pointer depends on the model, so the canary test covers this path as well. If it fails, the fallback is to paste a short summary of the root file here and add a drift check that compares the two. We keep that out of the default build because duplicated text is the first thing to rot.
Steps 7 and 8: Share VS Code Workspace Files, Tasks and Launch Configs
Step 7. Commit workspace settings, extension recommendations and EditorConfig. Cursor is a fork of VS Code, so it reads the same .vscode/ folder for workspace settings, recommended extensions, tasks and launch configurations. That makes this the easiest layer to share. It is also the easiest to pollute, so keep it small.
{
// Shared by VS Code and Cursor. Keep personal taste in user settings.
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.tabSize": 2,
"files.eol": "\n",
"files.insertFinalNewline": true,
"files.trimTrailingWhitespace": true,
"search.exclude": {
"**/node_modules": true,
"**/coverage": true
},
"[markdown]": {
"files.trimTrailingWhitespace": false
}
}
{
// Only list extensions that exist in both the VS Code Marketplace and Open VSX.
"recommendations": [
"esbenp.prettier-vscode",
"editorconfig.editorconfig"
]
}
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
Three choices deserve a note. The settings file only holds things the whole team should agree on: format on save, the default formatter, tab size and line endings. It carries no theme, no font and no zoom level. VS Code’s October 15, 2026 UI preview introduced new Dark 2026 and Light 2026 themes, and people will want to try them, but a color theme is personal and should stay in user settings. Second, the extensions file lists only extensions that exist in both marketplaces. Third, the EditorConfig file backs up the settings file for any editor that does not read .vscode/ at all.
The file is JSON with comments, which VS Code accepts and plain JSON parsers do not. That detail trips up scripts, and the drift check below handles it. If you maintain extensions yourself, see how to publish a VS Code extension to Open VSX so Cursor users can install it too.
Step 8. Share tasks and a launch configuration. A task defined once in .vscode/tasks.json shows up in both editors’ task pickers. A launch configuration does the same for the debugger. Point both at the npm scripts so there is a single source of truth for how to run things.
{
"version": "2.0.0",
"tasks": [
{
"label": "test",
"type": "npm",
"script": "test",
"group": { "kind": "test", "isDefault": true },
"problemMatcher": []
},
{
"label": "check editors",
"type": "npm",
"script": "check:editors",
"problemMatcher": []
}
]
}
{
"version": "0.2.0",
"configurations": [
{
"name": "Run demo",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/src/index.js",
"args": ["Hello", "Dual", "Editor"],
"console": "integratedTerminal"
}
]
}
Test it. In either editor, open the Command Palette, run the task picker, and choose test. The integrated terminal should show the same three passing tests you saw in step 2. Then press F5 with the demo configuration selected and confirm the debugger prints the slug hello-dual-editor. If you see that in both editors, the shared run layer works.
Steps 9 and 10: Share MCP Config Without Secrets and Protect Personal Files
Step 9. Create one MCP file per editor. The Model Context Protocol lets an agent call external tools. VS Code reads project servers from .vscode/mcp.json and Cursor reads .cursor/mcp.json. The two use different top-level keys, servers for VS Code and mcpServers for Cursor, so one file cannot serve both. Keep them side by side and keep them identical in intent. The URL below is a placeholder, so swap in your real endpoint.
{
"servers": {
"docs": {
"type": "http",
"url": "https://example.com/mcp"
}
}
}
{
"mcpServers": {
"docs": {
"url": "https://example.com/mcp"
}
}
}
Never paste a token into either file. If a server needs credentials, read them from an environment variable or the editor’s own input prompt, and put a reminder in AGENTS.md that secrets never enter the repo. The drift script flags strings that look like API keys or bearer tokens. For a deeper look at how each editor wires up servers, our Cursor MCP servers versus VS Code agents guide covers the differences, including what happens when a server fails to connect.
Step 10. Keep personal editor state out of Git. Add rules to .gitignore so workspace files, history folders and Cursor’s local state never get committed, while the two things you do want to share stay tracked.
node_modules/
coverage/
.env
.env.*
# Personal editor state stays out of Git
.vscode/*.code-workspace
.vscode/.history/
.cursor/*
!.cursor/rules/
!.cursor/mcp.json
The order matters. The line ignoring everything under .cursor/ comes first, and the two exceptions follow. Git cannot re-include a file if its parent folder is excluded, which is why the pattern ignores the folder contents with a star rather than the folder itself. Check the result with this command:
git check-ignore -v .cursor/rules/tests.mdc .cursor/mcp.json .cursor/state.db
# The first two print nothing (tracked). The last one points at the ignore rule.
Step 11: Build the Editor Drift Check Script
Config files rot. Someone renames an npm script, someone else adds a rule without a trigger, and a week later one editor behaves differently from the other. A short script catches that before review. This one uses only Node built-ins, so it adds no dependency and runs the same on every machine.
import { readFileSync, readdirSync, existsSync } from "node:fs";
import { join } from "node:path";
const root = process.cwd();
const problems = [];
const read = (path) => readFileSync(join(root, path), "utf8");
const fail = (message) => problems.push(message);
// Strip // and /* */ comments so VS Code style JSONC parses with JSON.parse.
function parseJsonc(text, label) {
const stripped = text
.replace(/\/\*[\s\S]*?\*\//g, "")
.replace(/(^|[^:"'])\/\/.*$/gm, "$1");
try {
return JSON.parse(stripped);
} catch (error) {
fail(`${label} is not valid JSON: ${error.message}`);
return null;
}
}
// 1. The shared instruction file exists and stays short.
if (!existsSync(join(root, "AGENTS.md"))) {
fail("AGENTS.md is missing at the repository root");
} else {
const lines = read("AGENTS.md").split("\n").length;
if (lines > 150) fail(`AGENTS.md has ${lines} lines, keep it under 150`);
}
// 2. Every command named in AGENTS.md exists in package.json.
if (existsSync(join(root, "AGENTS.md"))) {
const scripts = JSON.parse(read("package.json")).scripts ?? {};
const named = [...read("AGENTS.md").matchAll(/`npm run ([\w:-]+)`/g)].map((m) => m[1]);
for (const name of named) {
if (!scripts[name]) fail(`AGENTS.md mentions "npm run ${name}" but package.json has no such script`);
}
}
// 3. Each Cursor rule has frontmatter, a description and a trigger.
const rulesDir = join(root, ".cursor", "rules");
if (existsSync(rulesDir)) {
for (const file of readdirSync(rulesDir).filter((f) => f.endsWith(".mdc"))) {
const text = readFileSync(join(rulesDir, file), "utf8");
const match = text.match(/^---\n([\s\S]*?)\n---/);
if (!match) {
fail(`.cursor/rules/${file} has no frontmatter block`);
continue;
}
if (!/^description:\s*\S+/m.test(match[1])) fail(`.cursor/rules/${file} has no description`);
if (!/^globs:\s*\S+/m.test(match[1]) && !/^alwaysApply:\s*true/m.test(match[1])) {
fail(`.cursor/rules/${file} has neither globs nor alwaysApply: true`);
}
}
}
// 4. Shared VS Code files carry no machine-specific paths.
const machinePath = /(\/Users\/|\/home\/[a-z]|[A-Z]:\\\\)/;
for (const file of ["settings.json", "tasks.json", "launch.json", "extensions.json"]) {
const path = join(".vscode", file);
if (!existsSync(join(root, path))) continue;
const text = read(path);
parseJsonc(text, path);
if (machinePath.test(text)) fail(`${path} contains an absolute personal path`);
}
// 5. Extension IDs are lowercase publisher.name pairs.
if (existsSync(join(root, ".vscode", "extensions.json"))) {
const data = parseJsonc(read(".vscode/extensions.json"), ".vscode/extensions.json");
for (const id of data?.recommendations ?? []) {
if (!/^[a-z0-9-]+\.[a-z0-9-]+$/.test(id)) fail(`extension id "${id}" should be lowercase publisher.name`);
}
}
// 6. MCP files hold no inline secrets and use each editor's own top-level key.
const mcpFiles = [
{ path: ".vscode/mcp.json", key: "servers" },
{ path: ".cursor/mcp.json", key: "mcpServers" },
];
const secretLike = /(sk-[A-Za-z0-9]{16,}|ghp_[A-Za-z0-9]{20,}|Bearer\s+[A-Za-z0-9._-]{16,})/;
for (const { path, key } of mcpFiles) {
if (!existsSync(join(root, path))) continue;
const text = read(path);
const data = parseJsonc(text, path);
if (data && !data[key]) fail(`${path} should use the "${key}" top-level key`);
if (secretLike.test(text)) fail(`${path} looks like it contains a secret, use an input or env reference`);
}
if (problems.length) {
console.error(`editor drift check failed with ${problems.length} problem(s):`);
for (const p of problems) console.error(` - ${p}`);
process.exit(1);
}
console.log("editor drift check passed: AGENTS.md, Cursor rules, VS Code files and MCP configs agree");
The script runs six checks. It confirms that AGENTS.md exists and stays under 150 lines. It verifies that every npm run command named in the file exists in package.json. It makes sure each Cursor rule has frontmatter, a description and either globs or alwaysApply: true. It scans the shared VS Code files for personal absolute paths. It validates extension IDs as lowercase publisher and name pairs. And it checks that each MCP file uses its editor’s own top-level key and holds nothing that looks like a secret.
The comment stripper deserves a second look. It removes block comments, then removes line comments only when the two slashes are not preceded by a colon or a quote. That keeps URLs such as https://example.com/mcp intact. It is a pragmatic parser for config files, not a general JSONC library, and it is good enough here.
Run it on the healthy repo first.
npm run check:editors
> [email protected] check:editors
> node scripts/check-editor-drift.mjs
editor drift check passed: AGENTS.md, Cursor rules, VS Code files and MCP configs agree
Now break four things on purpose in a scratch copy: add an absolute path to the settings file, mention a missing script in AGENTS.md, create a rule with no trigger and rename the key in the VS Code MCP file. Here is what the check printed when we did exactly that:
editor drift check failed with 4 problem(s):
- AGENTS.md mentions "npm run lint" but package.json has no such script
- .cursor/rules/broken.mdc has neither globs nor alwaysApply: true
- .vscode/settings.json contains an absolute personal path
- .vscode/mcp.json should use the "servers" top-level key
exit=1
Each message names the file and the fix. That is the standard to hold any repo check to. If a failure needs a minute of detective work, people will stop running it.
You can extend the script without much effort. A natural next check compares the headings of AGENTS.md against the descriptions in your Cursor rules and warns when a heading appears in both. Another useful one fails the build when a canary phrase is still sitting in a committed file. Resist the urge to turn the script into a framework. Six checks that everyone understands beat thirty that nobody reads, and each added check is one more thing to maintain when an editor changes its behavior.
Steps 12 and 13: Run the Canary Test, Add the Hook and Wire Up CI
Step 12. Prove both agents load the shared file. A canary is a harmless, unique instruction that you plant, test and remove. Add a line to the root file and a different one to the nested file:
# Add to AGENTS.md (temporary)
When asked for the canary phrase, answer exactly: BLUE-HERON-7
# Add to src/AGENTS.md (temporary)
When asked for the folder canary phrase, answer exactly: RED-FOX-3
Now open the folder in Cursor and start a fresh agent chat. Ask: What is the canary phrase from the project instructions? Then open src/slugify.js so the nested file applies, and ask for the folder canary phrase. Repeat both questions in VS Code with Copilot chat in agent mode. Always start a new chat, because an old conversation can carry stale context.
| Question | Expected answer | If wrong |
|---|---|---|
| Root canary in Cursor | BLUE-HERON-7 | Cursor is not loading AGENTS.md, see troubleshooting item 1 |
| Folder canary in Cursor | RED-FOX-3 | Nested file not loaded, repeat key rules in src/AGENTS.md |
| Root canary in VS Code | BLUE-HERON-7 | Copilot is not following the file or the pointer, see item 2 |
| Folder canary in VS Code | RED-FOX-3 | Same fix as Cursor, copy the rules down |
Record the result for your team. Some builds will pass all four checks, and some will not, and the answer can change after an update. That is the reason to keep the test around. When you finish, delete both canary lines and run git diff to confirm nothing temporary remains.
Step 13. Turn on the pre-commit hook and the CI job. The hook lives in the repo, so teammates get it with one config line. Git does not run hooks from a tracked folder unless you point it there.
#!/bin/sh
npm run --silent check:editors
git config core.hooksPath .githooks
chmod +x .githooks/pre-commit
name: editors
on:
pull_request:
push:
branches: [main]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm test
- run: npm run check:editors
The CI job repeats the same two commands on every pull request, which catches people who skip the hook. Commit everything. The hook runs on the commit and prints the same pass line you saw earlier.
git add -A
git commit -m "feat: dual-editor config with drift check"
git ls-files
.cursor/mcp.json
.cursor/rules/javascript.mdc
.cursor/rules/tests.mdc
.editorconfig
.githooks/pre-commit
.github/copilot-instructions.md
.github/workflows/editors.yml
.gitignore
.vscode/extensions.json
.vscode/launch.json
.vscode/mcp.json
.vscode/settings.json
.vscode/tasks.json
AGENTS.md
package.json
scripts/check-editor-drift.mjs
src/AGENTS.md
src/index.js
src/slugify.js
src/slugify.test.js
That is the complete working project: 20 tracked files, zero runtime dependencies, one shared instruction file, and a check that fails loudly when the two editors drift apart. Clone it on another machine, open it in either editor, and the same rules, tasks and debug targets show up.
A Daily Workflow: When to Reach for Cursor and When for VS Code
With the repo shared, the choice of editor shrinks to a matter of fit. A few patterns hold up well in practice, and none of them depend on a benchmark number.
Reach for Cursor when the task spans many files and you want an agent to plan and carry out the edit. Refactors that touch a dozen modules, test suites that need a new fixture everywhere and API changes that ripple through callers all suit an agent-first editor. Cursor now sells model access through a shared usage pool, so these heavier tasks are where the plan you pay for earns its keep. Cursor added Grok 4.5 as a first-party model on July 8, 2026, and reports suggest its own models such as Composer 2.5 count toward the included usage, while Claude, GPT and Gemini draw on separately billed top-ups.
Reach for VS Code when you want a quiet editor with AI on tap rather than AI in charge. Single-file fixes, debugging sessions, reviewing a pull request and long stretches of manual typing all benefit from unlimited completions and a familiar interface. Copilot also added Gemini 4 Argon on October 13, 2026 and Claude Haiku 5.5 on October 9, so the model menu inside VS Code is wider than it was a quarter ago, which helps when you want a fast, cheap model for small jobs.
The shared repo makes switching cheap, and that is the point. You can start a refactor in Cursor, step through a failing test with the VS Code debugger configuration from step 8 and finish the pull request in whichever window is open. Because commands, conventions and boundaries live in files both tools can see, the handoff costs a few seconds. For a broader view of how the leading editors compare, our VS Code, Cursor and Zed setup comparison covers more of the field.
One habit keeps this workflow honest. After each major update to either editor, rerun the canary test and the drift check, then note the result in your team wiki. Both products ship changes weekly, and the October pricing change at Cursor showed how quickly the commercial side can move even when the repository side stays stable.
Common Pitfalls When Running Cursor and VS Code on One Repo
Most failures with this setup come from the same handful of habits. Watch for these before they land in a pull request.
- Copying rules into three places. A rule pasted into AGENTS.md, a Cursor rule and the Copilot file will diverge within a month. Write it once in AGENTS.md and let the editor files point at it.
- Committing personal taste. Themes, fonts, zoom levels and keybindings belong in user settings. With new themes arriving in VS Code’s October preview, expect them to creep into workspace files unless the drift check or review catches them.
- Recommending an extension only one editor can install. The Visual Studio Marketplace and Open VSX do not carry identical catalogs, and Cursor’s registry can lag. Recommend only extensions you have installed in both editors.
- Putting a token in an MCP file. Both files are tracked. Use environment variables or prompts, and keep the secret pattern check in the drift script.
- Letting AGENTS.md grow without limit. Every agent session reads the file, and model usage is now metered in both products. Trim it each quarter, and enforce a line cap in the script.
- Assuming both agents obey the same file the same way. The vendors’ own pages do not promise identical behavior. Rerun the canary after every major update to either editor.
- Trusting the nearest-file rule blindly. If an editor loads only the closest AGENTS.md, rules in the root vanish inside subfolders. Repeat the few non-negotiable rules where they apply.
Troubleshooting: 10 Problems and Fixes
- 1. Cursor ignores AGENTS.md. Start a fresh chat, since old sessions keep old context. Confirm the file sits at the folder you opened, not one level up. If the canary still fails, move the key rules into a Cursor rule with
alwaysApply: trueas a stopgap and report it to Cursor. - 2. Copilot chat in VS Code does not follow AGENTS.md. Check that you are in agent mode, signed in and on a plan that includes chat. Confirm the pointer file exists at
.github/copilot-instructions.md. Look in the chat settings for an option that controls instruction file loading, and make sure it is on. - 3. A Cursor rule never triggers. The glob probably does not match.
src/**/*.jsmatches nested files, while*.jsonly matches the repo root. Open a matching file and start a new chat, because globs attach on file context. - 4. The same rule fires twice. You copied it into both AGENTS.md and a rule file. Delete the copy and keep the shared one.
- 5. An extension recommendation fails in Cursor. The extension may not exist in Cursor’s registry under that ID. Search for it by name, install a VSIX manually if the vendor provides one, or remove it from
extensions.json. - 6. Red squiggles in settings.json. The editor flags comments only if the file language mode is plain JSON. Set the mode to JSON with Comments, or associate
.vscode/*.jsonwith that mode. - 7. The drift script says the JSON is invalid. A trailing comma or an unusual comment form usually causes this. The script’s stripper handles
//and block comments, but not trailing commas. Remove the comma. - 8. An MCP server will not start in one editor. Check the top-level key first,
serversfor VS Code andmcpServersfor Cursor. Then check that the URL or command works from a terminal. - 9. Diffs show line-ending noise. One editor wrote CRLF. Make sure
.editorconfigis installed in both editors, keepfiles.eolset to LF and rungit add --renormalize .once to clean history in the working tree. - 10. The pre-commit hook does not run. Run
git config core.hooksPathand confirm it prints.githooks. On macOS and Linux, check the executable bit. On Windows, run commits from Git Bash or confirm Git for Windows is on your PATH.
If none of these fit, run the drift check first. It surfaces most config mistakes in seconds, which narrows the search before you open a single log.
Advanced Tips for Teams Using Both Editors
Use Git worktrees so the editors never fight over files
Two editors writing the same working tree can overwrite each other when both agents edit at once. Give each one its own checkout of the same repository. Git worktrees do this without a second clone:
git worktree add ../dual-editor-cursor -b try/cursor
git worktree add ../dual-editor-vscode -b try/vscode
cursor ../dual-editor-cursor
code ../dual-editor-vscode
VS Code introduced experimental multi-folder agent sessions, plus experimental reuse of ignored folders across worktrees, which cuts repeated dependency installs. If you run agents in parallel, the combination is worth a trial. Because these features are experimental, do not make them a hard requirement for your team yet.
Benchmark before you standardize
Opinions about which editor is faster for your codebase rarely survive a test. Run the same task set in both, score the results blind and compare cost per task. Our 13-step benchmark of Cursor and VS Code on your own codebase provides a harness, and it slots into this repo as another script under scripts/.
Control cost with a short file and a mixed toolset
Keep AGENTS.md lean, and send routine work to the cheapest path. Copilot completions are unlimited and unbilled, so inline typing in VS Code costs nothing beyond the plan. Heavy multi-file edits suit an agent, and that is where credits or top-ups go. If you pair Cursor with an external CLI agent, our Cursor and Claude Code workflow guide shows how to split the work so each tool does what it is best at.
Cursor vs VS Code Setup FAQ
Can Cursor and VS Code open the same repository at the same time?
Yes. Both use ordinary project folders and Git, so nothing blocks it. The risk is two agents editing the same files at once. Use separate Git worktrees when you run agent tasks in both.
Does Cursor read AGENTS.md?
Secondary documentation says it does, and it also supports .cursor/rules for Cursor-specific behavior. The vendor pages we checked on October 23, 2026 did not spell out the exact behavior, so run the canary test in step 12 on your build.
Does GitHub Copilot in VS Code read AGENTS.md?
Secondary sources list VS Code among the tools that support the file, but the official pages we checked did not guarantee identical behavior. That is why this tutorial adds a pointer in .github/copilot-instructions.md and a canary test.
Do I still need .cursor/rules if I have AGENTS.md?
Only for Cursor-specific behavior or rules that should attach to particular file patterns. Project-wide commands and conventions belong in AGENTS.md so every tool sees them.
What is the cheapest way to run both editors?
VS Code is free, Copilot Free costs $0 and Cursor Free costs $0. Among paid options, Cursor Plus is $8 a month and Copilot Pro is $10. Usage rules differ, so compare how you actually work before you pay.
Is Cursor Pro still $20 a month?
No for new customers. The $20 Pro plan is a legacy plan, and new customers are directed to The X Subscription, where Premium at $30 a month is described as the closest replacement.
Can I share one settings file between both editors?
Yes for workspace settings. Cursor is a VS Code fork and reads .vscode/settings.json. MCP files are the exception, since each editor uses its own file and top-level key.
Does the drift script work on Windows?
The Node script runs on any platform. The pre-commit hook is a shell script, so run commits from Git Bash or another environment where sh is available.





