为什么 Cursor 会搞丢文件位置
你的部分目录树被故意排除在索引之外
这是首先需要检查的一点,也是最让人感到意外的一点,因为没有任何提示。
Cursor 会遵守你的忽略文件。根据文档:“Cursor 会自动遵守你的 .gitignore 规则。被 git 忽略的文件也会被 Cursor 的索引忽略。”除此之外,.cursorignore 还增加了“超出 .gitignore 范围的其他排除项”,并且 Cursor “默认已经忽略了 .env 文件、.git/ 和锁文件”。
结果非常直接:“被忽略的文件无法被索引,也无法被 Agent 访问。”因此,如果你的自动生成 API 客户端、第三方 SDK 或构建输出目录被 git 忽略了(通常确实如此),Agent 根本无法看到这部分结构。它并不是忘记了这些文件在哪里,而是它从未看到过它们。
这里有一个微妙的细节,解释了真正令人困惑的行为。“终端命令和 MCP 工具在 Cursor 的文件访问控制之外运行,因此它们可能仍然能够读取被忽略的文件。”所以,同一个 Agent 在运行 ls 后可能知道某个目录存在,但随后却无法通过搜索在其中找到任何内容。这种不一致性看起来就像是“健忘”。
没有存储的地图——结构每次都是重新发现的
Cursor 关于 @ 提及的指南比看起来更有启发性。在“当你清楚哪些文件相关时”使用它们,并且:“如果你不确定哪些文件重要,请跳过它——Agent 会通过自己的搜索找到相关文件。”
这就是其设计。Agent 会根据每个请求定位它需要的内容,而不是在消息之间保留项目地图。除非有规则规定或你手动附加,否则布局信息不会在对话轮次之间持久存在。Cursor 直接解释了为什么需要持久化:“大语言模型在补全之间不保留记忆。规则在提示词级别提供了持久、可复用的上下文。”
因此,“记住我的文件结构”并不是你没找到的某种记忆设置。这是一个关于你持久化了什么内容以及如何持久化的问题。
你编写的关于结构的规则没有加载
如果你确实编写了放置规则但它被忽略了,这几乎总是以下四种情况之一,Cursor 的常见问题解答(FAQ)指出了前两种:“检查规则类型。对于 Apply Intelligently,确保定义了描述。对于 Apply to Specific Files,确保文件模式与引用的文件匹配。”
规则的前置元数据(frontmatter)表格值得牢记,因为没有设置任何字段的规则并不是损坏的规则——它是一个手动规则。设置 alwaysApply: true 时,它是“始终包含。忽略 Globs 和描述。”设置 alwaysApply: false 并带有 globs 时,它是“当匹配的文件在上下文中时自动附加。”有描述但没有 globs 时,“Agent 会读取描述并在相关时拉入规则。”两者都没有时,它是“仅当你在聊天中 @ 提及该规则时才包含。”
然后是扩展名陷阱:“.cursor/rules 中的普通 .md 文件会被规则系统忽略,因为它没有前置元数据来指定 description、globs 和 alwaysApply。如果你更喜欢纯 Markdown,请改用 AGENTS.md。”
最后是位置。规则会保存在你打开的文件夹的 .cursor/rules 中。如果你将 monorepo 的子目录作为项目打开,那么你的规则范围就仅限于该子目录。
粘贴的目录树不出一周就会出错
即使它成功加载,它也会失效。目录列表是你可以放入常驻文件中失效最快的东西,而过时的目录树比没有目录树更糟糕:它会主动引导 Agent 走向已经移动的路径。这正是 Cursor 所说的规则“随着代码更改而过时”的意思,也是为什么建议引用而不是复制的原因。
开发者们尝试过的方法
将 tree -L 3 的输出粘贴到常驻规则中。 它能加载,在最初几天很准确,然后就开始误导。规则内容“包含在模型上下文的开头”,因此你每条消息都在为此付费。
只写一句“项目是按功能组织的”就结束了。 话虽没错,但无法执行。它没有告诉 Agent 新文件应该放在哪里。
在每次聊天中手动重新附加文件夹。 有效,这就是如何停止向 AI 重复解释上下文中描述的循环。
取消忽略目录以便 Cursor 可以看到它们。 有时正确,但通常不推荐——文档列出了忽略这些内容的原因,包括“大型生成文件会减慢索引速度”以及“敏感信息和凭据排除在 AI 上下文之外更安全”。
将结构规则设置为 Apply Intelligently。 听起来很合理,但它把决定权交给了你花五秒钟写出的描述。描述模糊,规则就无法生效。
要求 Agent 在每个会话中重新扫描代码库。 昂贵且重复,同样的模式也出现在如何阻止 Claude Code 重新读取你的代码库中。
解决方案:存储放置规则,而不是目录树
改变一下思路,这个问题就会变得容易解决:你不需要 Cursor 记住文件在哪里。你希望它知道新文件应该放在哪里,以及为什么。前者是可以推导出来的,而且容易过时;后者是一种约定,能够长期有效。
Cursor 自己的文档在没有明说的情况下证明了这一点。它自动附加规则的示例(范围限定为 globs: src/components/**/*.tsx)包含诸如“将样式共同放置在组件旁边的模块 CSS 文件中”和“保持组件在 200 行以内。当文件超过该行数时,将子组件提取到同一目录中”等行。这些就是放置规则。示例中并没有目录树。
四个步骤。
在编写任何内容之前,先审计忽略文件。 对照 Agent 总是搞错的目录,检查 .gitignore 和 .cursorignore。如果某个文件夹确实应该可见——例如已提交的 schema 目录、你提交的生成客户端——这是一个单行修复,任何规则都无法替代。
编写由 globs 限定范围的放置约定。 每个区域一个规则,通过模式进行附加,以便在你该区域工作时加载。使用文档中记录的 glob 形式:src/** 表示 src/ 下的所有内容,src/**/*.tsx 表示组件,需要两个模式时使用逗号分隔的模式,如 docs/**/*.md, docs/**/*.mdx。说明文件应该放在哪里以及应该如何命名,而不是当前存在什么。
使用嵌套的 AGENTS.md 进行结构化范围限定。 在任何子目录中放置一个,它就会“在处理该目录或其子目录中的文件时自动应用”,其指令“与父目录合并,更具体的指令优先”。没有前置元数据,无需维护 glob,而且文件就放在它所描述的代码旁边——因此在布局发生变化时,它更有可能得到更新。
针对特定需求显式附加文件夹。 当你清楚相关区域时,使用 @ 提及它:“@auth.ts 或 @src/components/ 以包含文件或文件夹(选择文件夹后输入 / 可以导航到更深层)。”这是为了解决眼前的请求,而不是约定的替代方案。
这解决了加载和范围限定的问题。但这些方法都无法保留让布局合理化的核心部分——为什么边界划在这里,你尝试过并回退了哪些重构,哪个目录看起来像残留物但实际上不是。规则的推荐上限是 500 行,旨在指向而不是复制,因此结构背后的论据无处安放。
这正是 MemoryLake 所保存的:将你项目的持久知识保存在一个你的工具可以读取的层中,从而使规则保持简短,同时保留推理过程。设置只需三个步骤。
步骤 1:创建 API 密钥
登录 MemoryLake 并创建 API 密钥。一个凭据即可跨你连接的所有工具使用。

步骤 2:上传你的第一批记忆
简短的条目,每条记录一个主张。具体关于结构应该写些什么:

每种新东西应该放在哪里,以及原因。 “新的 API 处理器放在 src/api/handlers/ 中,每个路由一个文件,因为路由器会匹配该目录。”规则规定了位置;而原因则是阻止下个月出现看似合理但错误的替代方案的关键。
看起来随意但实际上并非如此的边界。 比如不能从另一个模块导入的模块,必须保持无框架的目录。目录树中没有任何内容能传达这种约束。
你已经拒绝的重构方案。 你尝试过的扁平结构,你刻意不设立的 utils/ 目录。每个新的 Agent 都会再次提出这些建议,而代码库中没有任何内容记录这一决策。
排除在索引之外的目录,以及其中的内容。 如果 generated/ 被 git 忽略了,写一行关于里面有什么以及它是如何生成的笔记,比取消忽略 40,000 个文件要有用得多。
步骤 3:连接你的 AI 和 Agent
连接你使用的工具。MemoryLake 可以通过 MCP 和 API 访问,因此支持 MCP 的原生 Agent(包括 Claude Code、Codex 和 OpenClaw)可以通过指向 MCP 服务器进行连接,而其他助手则通过 API 读取相同的记忆。你编写一次的放置约定,就是每个在代码库中工作的 Agent 所读取的相同约定。

三个坦诚的限制。MemoryLake 不会索引你的代码库,也不会编写你的 Cursor 规则——Cursor 自己的索引负责查找文件,而规则是你引导 Agent 的方式。它只保存你或你的 Agent 放入其中的内容,因此步骤 2 是手动的。而且这是上下文,而不是强制执行;如果某个放置规则确实必须遵守,Lint 规则或 CI 检查才是保证。
这在实践中带来了什么改变
“它把文件放错了地方”变成了两步检查。 目录被忽略了吗?规则的类型和模式正确吗?几乎总是其中之一。
你不再需要在每次添加文件夹时更新规则。 约定在重构中得以幸存,而目录列表则不能。
新贡献者会得到与 Agent 相同的答案。 编写好的放置约定既是入职文档,又恰好能引导模型。
索引排除项不再看起来像 Bug。 一旦你明白 .gitignore 会将文件移出 Agent 的访问范围,“它在 dist/ 中找不到任何内容”的报告就不再神秘了。
布局决策在工具之外依然存在。 无论阅读它的是 Cursor、Claude Code 还是 Codex,其推理过程都是相同的——这就是持久记忆的真正含义中所涵盖的形式。
Cursor 真正遵守的结构最佳实践
首先检查 .gitignore 和 .cursorignore。 被 git 忽略的文件会被 Cursor 的索引忽略,没有任何规则可以绕过这一点。
永远不要将目录树粘贴到常驻规则中。 它是可以推导出来的,不出一周就会过时,而且两个开发商都建议不要这样做。
使用 globs 限定结构规则的范围。 关于组件的规则应该在你打开组件时附加,而不是在每条消息上都附加。
对于每个目录的约定,优先使用嵌套的 AGENTS.md。 更具体的指令优先,无需维护前置元数据,且文件就放在它所描述的内容旁边。
在 .cursor/rules 内部使用 .mdc,绝不要使用普通的 .md。 放在那里的 .md 文件会被静默忽略。
编写命名约定,而不是文件列表。 “每个路由一个文件,以路由命名”比 handlers/ 的任何快照都更长寿。
针对眼前的任务,使用 @ 附加文件夹。 精准定位胜过寄希望于搜索能选中正确的区域。
将推理过程保留在规则之外。 边界存在的原因是让 Agent 能够处理你的约定未预料到的情况——这也是为什么 Agent 会忽略你编写的指令文件中的普遍问题。
结论
Cursor 不会在消息之间保留项目的地图,它也不应该这样做——Agent 每次都会通过自己的搜索找到相关文件,而规则是文档中记录的用于任何需要持久化的内容的机制。因此,当文件放错地方时,按顺序有三件事需要检查:目录是否被 .gitignore 或 .cursorignore 排除,你的规则类型和 glob 模式是否真的导致它加载,以及规则是说明了文件应该放在哪里,还是仅仅描述了它们在哪里。
最后一个是实质性的解决方案,也是 Cursor 和 Claude Code 的文档独立指向的方案:不要把常驻上下文浪费在工具可以推导出的内容上,也不要复制会过时的内容。编写放置约定,将其范围限定在它们管辖的目录中,并将布局背后的推理过程保存在每个工具都可以查询的地方。这样,新文件就会因为约定清晰易懂而被放在正确的地方,而不是因为你的目录树快照碰巧仍然准确。