MemoryLake
Back to all articles
TutorialSeptember 9, 2026·11 min read

How to Migrate From Cursor to Roo Code Without Losing Context (2026)

Both tools keep project rules in a version-controlled directory of markdown files. Cursor uses .cursor/rules, Roo Code uses .roo/rules. So the migration looks like renaming a folder.

Do exactly that and every rule you carefully scoped to specific files becomes a rule that applies to everything, all the time. No error, no warning, no log line. The reason is that Cursor's conditional activation lives in each file's frontmatter, and Roo Code's rule system has no frontmatter concept at all — it appends what it finds, in alphabetical order by filename.

That is the whole migration in one sentence, and it is worth understanding before you move a single file, because the fix is not a find-and-replace. It is a re-modelling of when each rule should apply, using a mechanism Cursor does not have.

One disambiguation first: Roo Code and Kilo Code are separate forks of Cline, with their own rule systems that diverge from each other. This guide is about Roo Code specifically. If you are choosing between destinations, migrating from Cursor to opencode covers a terminal-native target with a different instruction model again.

What actually transfers

Cursor's rules documentation is precise about the format requirement, and the precision is the point:

"Project rules live in .cursor/rules as .mdc files and are version-controlled. They are scoped using path patterns, invoked manually, or included based on relevance."
"Project rules must use the .mdc extension. A plain .md file in .cursor/rules is ignored by the rules system because it has no frontmatter to specify description, globs, and alwaysApply. If you prefer plain markdown, use AGENTS.md instead."

Three frontmatter fields carry all the conditionality. The docs spell out the key branch:

"If alwaysApply is true, the rule will be applied to every chat session. Otherwise, the description of the rule will be presented to the Cursor Agent to decide if it should be applied."

Plus globs to scope a rule to matching files, and a recommendation to "keep rules under 500 lines."

That extension requirement is worth pausing on, because it is the most common reason people arrive at a migration already frustrated. A rule saved as .md in that directory is not a broken rule — it is not a rule at all, and nothing says so. Half the reports of Cursor forgetting project rules trace back to a file the rules system never picked up.

Now Roo Code. Workspace rules go in .roo/rules/, which the docs call the preferred method, with a single .roorules file at the workspace root as the fallback. Global rules go in ~/.roo/rules/, and that location "is fixed and cannot be customized." Load order is documented plainly: global rules first, then project rules, and "if there's a conflict, workspace rules take precedence."

The fixed global path has a practical consequence for teams: it is a home-directory location, so it is per-machine and outside version control. Anything you put there exists on one laptop, which is the same asymmetry behind Cursor forgetting settings across machines. Put team-relevant rules in the workspace directory, not the global one.

And then the sentence that changes your plan:

"Roo Code reads files recursively (including subdirectories), appending their content to the system prompt in alphabetical order based on filename."

Recursively, appending, alphabetical, by filename. There is no alwaysApply because everything in the directory is applied. There is no globs because nothing is file-scoped. There is no description for the model to evaluate, because the model is not being asked to decide.

So here is what transfers and what does not. The prose of every rule transfers unchanged — it is markdown either way. The directory structure transfers, since Roo Code reads subdirectories too. What evaporates is all three frontmatter fields, and with them the entire distinction between a rule that applies always and a rule that applies to src/api/**/*.ts.

Two consequences follow, and the second one surprises people.

First, your context bill goes up. Every rule you wrote as conditional — the long database conventions file scoped to migrations, the React patterns file scoped to .tsx — is now in the system prompt on every request, including the ones about your build script.

Second, contradictions that never met each other now do. A rule saying "prefer server components" scoped to your app directory and a rule saying "these are all client components" scoped to a legacy folder were never in context together under Cursor. Under a flat append they are, and which one lands later in the prompt is decided by which filename sorts later. This is the mechanism behind reports like Roo Code forgetting project context: the rules are present, and they disagree.

Roo Code does have a conditionality mechanism. It is just somewhere else.

The manual migration

Step 1: Re-express globs scoping as modes

Roo Code scopes rules by mode, not by file path. Alongside .roo/rules/ you can create .roo/rules-{modeSlug}/ directories, and the documented examples include rules-code/ for Code mode, rules-architect/ for architecture tasks, rules-debug/ for debugging workflows, and rules-docs-extractor/ for documentation extraction. The same pattern exists globally under ~/.roo/. Within each level, the docs note that "mode-specific rules are loaded before general rules."

So go through your .mdc files and sort them by what their globs were really approximating. A rule scoped to test files is usually a rule about how you write tests, which is a Code-mode or Debug-mode concern. A rule scoped to architecture docs belongs in rules-architect/. A rule that was alwaysApply: true goes in .roo/rules/ unchanged, because that is what that directory means.

The rules whose globs were genuinely about paths rather than about kinds of work are the ones with no clean home. Write those as explicit conditionals in the prose instead — a sentence stating which directory the guidance applies to — since the file will be loaded regardless and the model needs to know the boundary from the text. It is less reliable than a glob, and it is honest about what the destination supports.

While you are here, drop the frontmatter blocks rather than leaving them in place. A stray YAML header at the top of a rules file is not parsed by Roo Code, so it becomes content — instructions to the model about alwaysApply that mean nothing.

Step 2: Control the append order deliberately, and watch two traps

Since content is appended in alphabetical order by filename, filenames are now load order. Name them so the order is intentional: a numeric prefix on each file makes the sequence explicit and stops a later rename from silently reordering your system prompt.

Then two documented behaviors to check.

The first is an empty-directory trap: "If the .roo/rules/ directory exists but is empty, Roo Code will fall back to using the .roorules file instead." So a half-finished migration — directory created, files not moved yet — quietly reactivates a legacy root file you may have forgotten about.

The second is legacy file precedence more broadly. The documented load order lists legacy files at the workspace root, .roorules and .clinerules, as "used only if no generic rules directory content was loaded." Roo Code reading .clinerules is convenient if you came from Cline and confusing if you did not: an old file sitting in your repo does nothing while your rules directory has content, and takes over the moment it does not.

Finally, keep your AGENTS.md where it is. Cursor supports it as the plain-markdown alternative to .mdc, and it stays useful across your stack — migrating Cursor rules to a Windsurf-style setup covers the same translation problem for a different destination, and the common thread is that the open convention is the part that survives.

The Better Way: Reasons that do not depend on filenames

Step 1 asked you to decide which mode each rule belongs to, and Step 2 asked you to decide which order they load in. Both decisions are easy when you know why each rule exists and nearly impossible when you do not.

"Prefer server components" versus "these are all client components" is unresolvable as two imperatives sorted alphabetically. It is trivial once you know the second one describes a directory nobody has migrated yet and the first is the standing direction. That reason is not in either tool, and it was not in the .mdc frontmatter either.

MemoryLake holds that layer — the decision, the alternative that lost, and the reason — outside any editor, and serves it to whichever agent asks over MCP or the API. Your .roo/rules/ files stay short and imperative, loaded exactly as the documentation describes, and the reasoning behind them is answerable without being in the system prompt on every request.

Step 1: Create an API key

Generate a key and make your first request in about thirty seconds. Do this before Step 1 above, so you have somewhere to record each conflict as you sort the files.

Creating a MemoryLake API key so scoping decisions do not ride on a filename's sort order
Creating a MemoryLake API key so scoping decisions do not ride on a filename's sort order

Step 2: Upload your first memories

For each rule you kept, write down what it decided, what it ruled out, and why. The pairs that contradicted each other are the highest-value entries, because those are the ones that will resurface. Supporting documents and files go in the same place.

Uploading the reasons behind each .mdc rule into MemoryLake before the frontmatter is dropped
Uploading the reasons behind each .mdc rule into MemoryLake before the frontmatter is dropped

Step 3: Connect your AI & agents

Give Roo Code, Claude, Codex, and your other agents access over MCP or the API. When a rule looks wrong, the answer to "why is this here" arrives with its reasoning rather than as a restatement.

Connecting Roo Code, Cursor and other agents to MemoryLake over MCP and the API
Connecting Roo Code, Cursor and other agents to MemoryLake over MCP and the API

What this changes in practice

The first change is that your rules directory can be small. Once reasoning has a home, each file is a handful of imperative lines, which matters a great deal more under a flat append than it did under conditional loading.

The second is that mode assignment gets decidable. Sorting a rule into rules-code/ versus rules-architect/ is a judgment about what kind of work it governs, and that judgment is obvious when the rule carries its purpose and guesswork when it does not.

The third is that filename ordering stops being load-bearing. You still want deliberate names, but you are no longer relying on alphabetical accident to resolve a genuine disagreement — the disagreement got resolved once, on purpose, and recorded.

The fourth is that the next tool is a smaller job than this one. Cursor put conditionality in frontmatter, Roo Code puts it in modes, and the tool after that will do something else. What does not change is the set of decisions your project has made, which is the same reason what coding agents actually read is a more durable question than which extension a given tool requires.

Best practices after moving to Roo Code

Assume everything in .roo/rules/ is always on. There is no alwaysApply equivalent because that directory is the always-on layer. Anything you would not want in every request belongs in a mode directory or not at all.

Use mode directories as your scoping tool. rules-code/, rules-architect/, rules-debug/ and their global counterparts are where conditionality lives now.

Make filenames express load order. Content is appended alphabetically by filename, so a numeric prefix turns an implicit ordering into an explicit one.

Never leave .roo/rules/ empty. An empty directory falls back to .roorules, which turns a partly finished migration into a live legacy config.

Audit for stray .clinerules and .roorules files. They are inert while your rules directory has content and authoritative the moment it does not.

Strip frontmatter when you convert. Unparsed YAML becomes prose, and prose about alwaysApply is noise the model has to read.

Keep AGENTS.md in the repository. It is the surface that does not change between these two tools, or the next one.

Conclusion

Cursor requires .mdc files with frontmatter, and states that a plain .md file in .cursor/rules is ignored because it lacks the fields that specify description, globs, and alwaysApply. Roo Code reads plain markdown recursively from .roo/rules/ and appends it in alphabetical order by filename, with mode-specific directories as its scoping mechanism and a documented fallback to .roorules when the directory is empty. Both are reasonable designs. They are not the same design, and a folder rename silently converts every conditional rule into an unconditional one.

The migration that works is a re-modelling: globs become modes, alwaysApply becomes the default, filenames become load order, and the rules that were only ever compatible because they never met each other have to be genuinely reconciled. That last part needs the reasons, not just the rules — so put the reasons somewhere neither tool owns, and the next rule system you adopt is a translation instead of an excavation.

Frequently asked questions

Can I copy .cursor/rules straight into .roo/rules?

The prose will work and the behavior will change. Cursor's .mdc frontmatter carries description, globs, and alwaysApply, and Roo Code's rules system has no frontmatter concept — it appends files recursively in alphabetical order by filename. Every conditionally scoped rule becomes an always-loaded rule, and no error tells you.

Does Roo Code support file-glob scoping for rules?

Not through rule frontmatter. Its documented scoping mechanism is mode-specific directories such as .roo/rules-code/ or .roo/rules-architect/, which load for the corresponding mode, and within each level mode-specific rules load before general rules. Path-based conditions have to be stated in the rule prose instead.

What decides which rule wins in Roo Code?

Two documented things. Across levels, project rules in project/.roo/ take precedence over global rules in ~/.roo/ when they conflict. Within a level, content is appended in alphabetical order by filename, so ordering is a function of what you named the files.

Does Roo Code read Cline's .clinerules file?

Yes. The documented load order lists workspace-root legacy files, .roorules and .clinerules, as used only when no generic rules directory content was loaded. That makes an old Cline file harmless while .roo/rules/ has content, and active the moment it is empty.

Where do Roo Code's global rules live, and can I move them?

In ~/.roo/rules/ on Linux and macOS, with mode-specific siblings such as ~/.roo/rules-code/, and the equivalent path under your user profile on Windows. The documentation states the global rules directory location is fixed and cannot be customized.

Should I keep using AGENTS.md?

Yes. Cursor documents it as the plain-markdown option for people who do not want .mdc frontmatter, and it is an open convention that multiple tools read. It is the one instruction surface that means the same thing on both sides of this migration, so it is the safest place for conventions you expect to outlive your current editor.