MemoryLake
Back to all articles
TutorialSeptember 8, 2026·12 min read

How to Merge Your Windsurf and Devin Rule Folders So the Right One Wins (2026 Guide)

Someone on your team adds a rule this week and it lands in .devin/rules. The rule that has been governing that same behavior for eight months is sitting in .windsurf/rules. Both folders are read. One of them wins. Nobody on the team can tell you which without looking it up.

This is not a bug, and it is not a migration you were asked to run. It is what backward compatibility looks like from the inside: Devin Desktop reads the new path and keeps reading the old one, so nothing broke, and the rules layer quietly became two rules layers with a precedence relationship that most teams have never read.

One boundary before we start. If your question is about Cascade's auto-generated memories rather than your rule files, that is a different job — moving Devin's Cascade-only memories into skills covers the memory side and the migration wizard. And if you have not moved to Devin Desktop yet, migrating from Windsurf to Devin Desktop is the earlier step. If the symptom is simply that Windsurf keeps forgetting your project rules, the folder split below is a common cause. This guide is specifically about the rule folders after the rename.

Why two rule folders end up disagreeing

The documented precedence is clear once you find it. Devin Desktop's rules discovery section states it directly:

"Devin Desktop automatically discovers rules from multiple locations to provide flexible organization. The .devin/ directory is the preferred location and takes precedence, with .windsurf/ kept as a fallback for backward compatibility."

That is one sentence, and it resolves the headline question. The problem is everything around it.

Discovery does not stop at one folder. It covers "all .devin/rules (and legacy .windsurf/rules) directories within your current workspace and its sub-directories," and for git repositories it "also searches up to the git root directory to find rules in parent directories." When several folders are open at once, "rules are deduplicated and displayed with the shortest relative path."

There is a third file in the workspace scope that most teams have forgotten about entirely:

"The legacy single-file .windsurfrules at the workspace root is also still read."

Above the workspace sits a global file with its own rules: ~/.codeium/windsurf/memories/global_rules.md, described as a "Single file, applied across all workspaces. Always on. Limited to 6,000 characters." Workspace rule files have their own ceiling — 12,000 characters each.

Then there is AGENTS.md, which is not a separate system at all. Its documentation makes the relationship explicit:

"When you create an AGENTS.md file (or agents.md), Devin Desktop automatically discovers it and feeds it into the same Rules engine that powers .devin/rules/ (and the legacy .windsurf/rules/) — just with the activation mode inferred from the file's location instead of frontmatter."

Root-level means always-on. A subdirectory means "a glob rule with an auto-generated pattern of <directory>/**."

And for enterprises there is a system layer, deployed by IT and read-only for users, which has the same old-and-new pair: /Library/Application Support/Devin/rules/ on macOS with Windsurf as a legacy fallback, /etc/devin/rules/ on Linux with /etc/windsurf/rules/ as fallback, and the equivalent pair on Windows. System rules "are merged with workspace and global rules, providing additional context to Cascade without overriding user-defined rules."

Count the surfaces: .devin/rules, .windsurf/rules, .windsurfrules, any number of AGENTS.md files, global_rules.md, and two system directories. Every one of them is live. Two of the pairs exist only because a rename happened and nothing was allowed to break.

There is one more detail that makes drift easy. New rules do not go where you might assume:

"When you create a new rule, it will be saved in the .devin/rules directory of your current workspace, not necessarily at the git root."

So in a monorepo, a rule created while you happen to be inside one package lands in that package, not at the top.

What people try instead

Deleting the legacy folder immediately. Tempting and usually premature. The old folder is still read, which means anyone still on an older client, or any teammate who has not pulled, may be relying on it. Delete it after you have confirmed the content is represented in the new location, not before.

Assuming the newest file wins. It does not. Precedence is by location, not by modification time. A rule you wrote this morning in .windsurf/rules loses to a stale one in .devin/rules.

Putting everything in global_rules.md to avoid the folder question. This trades one problem for a worse one. The global file is always on, applies across every workspace, and is capped at 6,000 characters. It is the wrong container for project-specific conventions, and it will be the first thing to hit a ceiling.

Assuming AGENTS.md sits outside the argument. It does not. It goes through the same rules engine, and a root-level one is always-on — so it competes for the same context budget as your always-on rule files, with its activation inferred from where it sits rather than declared.

Treating auto-generated memories as the durable layer. The documentation is unusually direct about this, and it is worth quoting because it is the vendor telling you what its own feature is for:

"For knowledge you want Cascade to reliably reuse, write it as a Rule or add it to AGENTS.md in your repo rather than relying on auto-generated Memories. Rules are version-controlled, shareable with your team, and give you explicit control over activation."

Auto-generated memories are also local: they live under ~/.codeium/windsurf/memories/, and "memories generated in one workspace are not available in another, and they are not committed to your repository." If losing context between sessions is the symptom that brought you here, why Cascade loses context covers that side directly.

The Fix: Consolidate on .devin/rules and make every activation explicit

Three steps. Do them in order — the inventory is what makes the second step safe.

Step 1: Inventory every surface before you move anything

Walk all seven surfaces and write down what is in each. Specifically: every .devin/rules directory in the workspace and in parent directories up to the git root, every .windsurf/rules directory in the same places, the .windsurfrules file at the workspace root if one exists, every AGENTS.md or agents.md at any level, global_rules.md, and — if your organization deploys them — the system directories, both current and legacy.

Two things to record for each rule: its activation mode and whether an equivalent already exists elsewhere. The activation mode matters because it is declared in frontmatter through the trigger field, and the four values have very different costs. The documentation spells out the trade-off: always_on puts the full rule in the system prompt on every message; model_decision puts only the description in the prompt and reads the full file when Cascade decides the description is relevant; glob applies the rule when Cascade reads or edits a file matching the pattern; manual keeps it out of the prompt entirely until you type @rule-name.

Note the two exceptions while you are inventorying: "The global rules file (global_rules.md) and root-level AGENTS.md files don't use frontmatter — they are always on." Those two cannot be scoped. Whatever is in them is in every message.

Step 2: Move each rule to .devin/rules and resolve duplicates by hand

Copy each legacy rule into the .devin/rules directory at the level where it actually belongs — which for most conventions is the git root, not whichever package you were sitting in when you created it.

Where you find the same rule in both folders, read both versions before picking one. This is the step where drift becomes visible, and it is frequently not a clean duplicate: the legacy version has a detail the new one lost, or the new one has a correction the legacy one never got. Merge deliberately, then delete the legacy copy.

.windsurfrules needs a decision of its own. It is a single file with no frontmatter, so everything in it behaves as one undifferentiated block. Split it into individual rule files with declared triggers as you move it — that is the whole benefit of the newer format.

For the AGENTS.md files, decide whether each one is really always-on material. A root-level AGENTS.md cannot be scoped, so anything in it that only applies to part of the tree should become either a subdirectory AGENTS.md (which gets the auto-glob for that directory) or a rule file with an explicit glob trigger.

⚠️ One cross-tool warning while you are touching these files. Devin Desktop is forgiving about the name — "Case insensitive: Both AGENTS.md and agents.md are recognized." Other tools are not. Kilo Code's documentation states plainly: "The filename must be uppercase (AGENTS.md), not lowercase (agents.md)." If your repository is shared with people on other agents, use uppercase. It costs nothing here and it is the difference between a file being read and silently ignored somewhere else. The same class of mismatch shows up when rules move between vendors at all — moving Cursor rules into Windsurf covers the frontmatter side of it.

Step 3: Declare an activation mode for everything that can have one

Once consolidated, go through .devin/rules and check that every file's trigger is a deliberate choice rather than a default.

The honest test is one question per rule: does this need to be in the prompt on every single message? Most rules do not. A convention about test files is a glob rule. A release runbook is manual. A long explanation of the data model is model_decision, where only its description is always present and the body is read on demand.

This step is what buys back the context budget that seven overlapping surfaces were quietly consuming, and it is only possible once the duplicates are gone — you cannot reason about activation costs while the same rule exists three times.

Setting this up in MemoryLake

Consolidation fixes the folders. It does not fix the reason you could not resolve the duplicates quickly: when the same rule existed in two places with two different wordings, nothing recorded which version was current or what changed between them.

MemoryLake keeps that record outside the rules layer entirely and serves it to whichever agent asks, over MCP or the API. Your .devin/rules files stay where they are and keep working exactly as documented; this holds the part the rules engine was never built to store — what each rule is for, what it replaced, and when.

Step 1: Create an API key

Generate a key and make your first request in about thirty seconds. Do it before Step 2 of the consolidation, so you can capture decisions as you resolve duplicates.

Creating a MemoryLake API key so the reasoning behind each rule lives outside both .devin/rules and .windsurf/rules
Creating a MemoryLake API key so the reasoning behind each rule lives outside both .devin/rules and .windsurf/rules

Step 2: Upload your first memories

As you merge each duplicate pair, record what you kept, what you dropped, and why. Add the rules that came from a specific incident — those are the ones whose wording nobody dares change because nobody remembers the reason. Documents and other files go in the same place.

Uploading the decisions scattered across seven Devin Desktop rule surfaces into MemoryLake
Uploading the decisions scattered across seven Devin Desktop rule surfaces into MemoryLake

Step 3: Connect your AI & agents

Give Claude, Codex, OpenClaw, and your Devin Desktop sessions access over MCP or the API. Once connected, the reasoning behind a rule is retrievable on demand, which is what lets the rule file itself stay short enough to justify an always_on trigger.

Connecting Devin Desktop, Cascade and other agents to MemoryLake over MCP and the API
Connecting Devin Desktop, Cascade and other agents to MemoryLake over MCP and the API

What this changes in practice

The immediate change is that "which rule is actually in force" becomes answerable in one place. One folder, one file per rule, each with a declared activation mode.

The second change is context budget. Seven overlapping surfaces with an unknown number of always-on files is a lot of prompt spent on guidance that applies to a fraction of the work. Deduplicating and then declaring triggers is the only way to bring that down, and it usually recovers more room than people expect.

The third change is that the next rename is boring. This will happen again — vendors merge, products get renamed, paths move, and the responsible thing for a vendor to do is keep reading the old path. If your rules are consolidated and your reasoning lives outside the folder, the next path change is a copy operation rather than another archaeology project.

Best practices for a single rules surface

Consolidate on .devin/rules, since that is the documented preferred location and the one that takes precedence. Do not fight the precedence order; move to the winning side of it.

Put project-wide rules at the git root. New rules are saved in the current workspace directory, "not necessarily at the git root," which is how monorepos end up with conventions buried inside one package.

Split .windsurfrules rather than porting it whole. A single undifferentiated file cannot express activation modes, and that is the main thing the newer format gives you.

Use uppercase AGENTS.md. Devin Desktop accepts either case; other agents in a shared repository may require uppercase.

Keep global_rules.md for genuinely personal, cross-project preferences only. It is always on, applies everywhere, and capped at 6,000 characters.

Delete legacy copies only after verifying the content moved. The old paths are still read, which means a half-finished consolidation is worse than either endpoint.

Do not use auto-generated memories as your team's record. The documentation recommends rules or AGENTS.md for durable, shareable knowledge, and notes that auto-generated memories are workspace-local and not committed. For the second half of that split — what belongs in a store the agent queries rather than in a rule file — memory tools for Windsurf users covers the options.

Conclusion

Devin Desktop reads seven rule surfaces, and two of the pairs among them exist only because a rename happened and backward compatibility was preserved. .devin/ takes precedence over .windsurf/, both are read, .windsurfrules is still read on top of that, and AGENTS.md files feed the same engine with their activation inferred from location.

None of that is broken. All of it is drift waiting to happen, especially since new rules save into whichever workspace directory you happen to be in.

Inventory all seven surfaces, consolidate on .devin/rules at the right level, split the legacy single file, declare an activation mode for everything that can have one, and keep the reasoning behind each rule somewhere the rules engine does not own. Then the answer to "which one wins" is short: there is only one.

Frequently asked questions

Which folder actually takes precedence, .devin/rules or .windsurf/rules?

.devin/rules. The documentation states that .devin/ is the preferred location and takes precedence, with .windsurf/ kept as a fallback for backward compatibility. Both are discovered and read, so the legacy folder is not ignored — it just loses when the two disagree.

Is .windsurfrules still supported?

Yes. The workspace scope documentation notes that "the legacy single-file .windsurfrules at the workspace root is also still read." Because it is a single file without frontmatter, everything in it behaves as one block with no activation control, which is the main reason to split it into individual rule files.

Can I delete .windsurf/rules after copying everything over?

After verifying, yes. The risk in deleting early is that the legacy path is still live for teammates who have not pulled or who are on an older client, so a partial consolidation can leave people with different effective rule sets. Confirm each rule's content exists in .devin/rules first, then remove.

Do AGENTS.md files conflict with my rule files?

They do not conflict so much as compete for the same budget. AGENTS.md is fed into the same rules engine, with activation inferred from location: root-level is always-on, and a subdirectory gets an auto-generated glob of <directory>/**. So a long root-level AGENTS.md behaves like a large always-on rule, and should be treated with the same discipline.

What are the character limits I should plan around?

The global rules file is limited to 6,000 characters, and workspace rule files are limited to 12,000 characters each. Those are the documented ceilings. Hitting them is usually a signal that always-on content should be moved to a model_decision or glob trigger rather than that the limit needs working around.

Do system-level enterprise rules override what my team writes?

No. The documentation describes system-level rules as "merged with workspace and global rules, providing additional context to Cascade without overriding user-defined rules." They are deployed by IT and read-only for end users, and they have the same old-and-new directory pair as the workspace folders, so they are worth including in the inventory.