What actually transfers
Cursor's rules documentation is precise about the format requirement, and the precision is the point:
"Project rules live in.cursor/rulesas.mdcfiles and are version-controlled. They are scoped using path patterns, invoked manually, or included based on relevance."
"Project rules must use the.mdcextension. A plain.mdfile in.cursor/rulesis ignored by the rules system because it has no frontmatter to specifydescription,globs, andalwaysApply. 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.

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.

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.

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.