![]()
一处私密、安静的思考空间。一款只为你 .md 文件而生的简单应用。
English · 简体中文
你的整段人生,都可以放在这里: - 📌 笔记 - 📝 文档、项目 - 💚 日记、习惯 - ✅ 清单、任务
全部以纯 .md 文件保存,本地优先,对 LLM 友好。隐私无虞——任何数据都不会上传到服务器。
让你的数据,以纯粹的本地文件形式属于你。 让打开这些文件的软件,也真正属于你。 用文件和你自己的大脑,去培育知识。 借助 LLM,去打磨文件周围的软件。 属于自己的纯文件与软件,才能穿越时代。
线上体验:app.files.md(Beta)。主站:files.md。
你可以把它用作第二大脑、卡片盒笔记(Zettelkasten)、笔记、日记、任务、清单等等。
这个项目我已经做了 5 年。 欢迎 在 GitHub 上支持作者 💚。
随手记下想法 · 如何深入思考 · 第二大脑? · 日记、任务、清单
也算是。但这一次:
- 只保留必要功能,约束孕育创造力
- 无需安装,一个浏览器就够了
- 离线可用
- 本地优先,文件不会离开你的设备
- 自由开源
- 代码极其简洁。一个人或一个 LLM 能把整个项目装进脑子里
- 换句话说,这个项目具有低认知负荷
- 代码库为 LLM 留好了扩展空间,随你按需添砖加瓦
- 便携,没有任何构建系统,直接打开 web/index.html 即可
- 同步开箱即用,但完全可选
- 服务器就是一个二进制文件(也可以直接用 iCloud / Dropbox / Google Drive 同步)
- Telegram 机器人,方便你在路上随时访问文件
点击地址栏右侧的 "Install files.md":

打开一个本地文件夹,让改动持久化保存
Cmd+Shift+R 强制刷新一下,拿到最新更新| 方案 | 文件存放在哪儿 | 多设备同步 | 是否需要服务器 | 适合的人 |
|---|---|---|---|---|
本地优先,app.files.md 完全不发送任何数据 |
你设备上的某个文件夹 | 否 | 不需要 | 追求极致隐私,数据完全留在本地 |
| 云盘文件夹同步(iCloud / Dropbox / Google Drive) | 你现有的云盘文件夹 | 是 | 不需要(由云服务商负责) | 不想自己跑服务器,也想多设备同步 |
| 自托管同步服务器 | 你自己(或局域网内)的服务器 | 是 | 一个 Go 二进制 | 想在自家或公司网络里多设备同步 |
| 托管同步服务器 | 我们托管的服务器 | 是 | api.files.md |
想立刻上手,不折腾任何配置 |
你可以打开聊天框,随手把脑子里冒出来的想法记下来。

打开聊天框,发一条消息:
<img src="https://github.com/zakirullin/files.md/raw/main/web/img/note1.png" width="350"/>
挑一个去处(也可以稍后再决定):
<img src="https://github.com/zakirullin/files.md/raw/main/web/img/note2.png" width="350"/>
这条流程足够让你顺手收下笔记、任务、日记和清单。
打开聊天,输入点东西,按 Enter:
<img src="https://github.com/zakirullin/files.md/raw/main/web/img/bot.gif" alt="Saving things in bot" title="Saving things in bot" width="350"/>
就这样,你的笔记已经保存到一个 .md 文件里了。
机器人的完整功能:
<img src="https://github.com/zakirullin/files.md/raw/main/web/img/bot.png" width="700"/>
别担心——默认情况下它比看上去简单得多。
Telegram 机器人入口。其他即时通讯工具也会陆续支持。
让想法相连,让它们彼此叠加,并真正想透。
1) 我用 app.files.md 来沉淀关于大脑和软件开发的认识
2) 我把新笔记放进 brain 或 dev 文件夹,一条笔记只承载一个想法
3) 在 Web 应用里,把彼此相关的笔记连接起来(按 [ 即可)
4) 所有东西最终都连成一片,正如我们的大脑
5) 我会花时间在这些笔记之间穿行、反复琢磨
6) 久而久之,有些 brain 里的笔记和 dev 里的笔记开始看起来意外地相关
7) 跨领域的这种连接,会激发出洞察
8) 我据此写了一篇文章:软件开发中的认知负荷
这个过程帮助我: - 深入思考(在 AI 时代尤其重要) - 系统性地思考,看见更完整的图景 - 写出更有洞见的文字
要做到以上几点,你必须用自己的脑子去想,而不是依赖什么花哨模板或者 AI 工作流。
我和我的朋友用这套朴素的方法已经五年了,效果一直很好。
我想引用 I Deleted My Second Brain 里的一段话:
Obsidian 是一款出色的软件,我深爱它。但任何东西失去节制都会变成陷阱。嵌套文件夹里的 Markdown 文件、追踪你生产力的插件、暗示某种全知感的关系图谱——看着自己的笔记编织成星座般的网络,会让人产生一种掌控的幻觉。但星座只是投影。它们讲故事,却并不等于理解。
刚开始使用知识管理工具时,我以为自己是在解决"遗忘"这件事。后来,我以为自己解决的是"整合"。
最终,我意识到我创造了一个新问题:拖延。系统越是壮大,我就越是把真正的思考工作推给某个未来的自己——那个会整理、贴标签、提炼、淘金的自己。
而那个自己从未到来。
第二大脑是一个迷人的概念。 那些进阶模板、插件、AI 工作流…… 让人忍不住想把整个互联网的智慧都打包收下。 这个整洁的系统看起来真美。每多一条笔记,多巴胺就涌出来一些。 第二大脑越来越好。
可是,第一大脑从来没有真正变得更聪明。 这才是问题——在 AI 时代,你的第一大脑前所未有地宝贵。
用你的脑子去把笔记想透。 工具并不重要,思考才是。
新增一条笔记之前,先试着回答这两个问题: - 这则新知识能不能磨利我的判断、拓宽我的分类框架? - 拥有这份知识后,我能用不同的视角看世界吗?
最糟糕的是,我们因此不再让新的体验发生——因为我们"已经知道了"。这就是一道知识的高墙。生活给了我们去亲身经历的机会,我们却拒绝,理由是"我已经知道了"。
在情绪层面受到的伤害,必须在情绪层面治愈。
不是靠脑力劳动和做笔记。 没有行动的阅读,是娱乐,是一种拖延的形式。 再多自助类书籍也治不好情感的伤口。 真正有帮助的,是心理治疗、改写练习与椅子工作。是冥想。 疗愈来自感受。
如果你的目标是: - 对某件事建立更深入、更有结构的理解 - 做研究 - 写一篇文章或一本书
那么记笔记完全合适。
对什么事情感觉良好?发一条消息。
<img src="https://github.com/zakirullin/files.md/raw/main/web/img/journal.png" title="Journaling" width="350"/>
然后点 "To Journal"。
或者直接在消息末尾加上 jj 或 жж。
你的记录会被妥帖地存进 journal/YYYY.MM Month.md。
你正心流满满地工作着。 同事突然让你发一份报告。 把这件事一直挂在脑子里很耗能。 丢一条消息,继续保持心流。
<img src="https://github.com/zakirullin/files.md/raw/main/web/img/task.png" title="Adding a task" width="350"/>
只添加小而可执行的事项。 不要写"规划一次假期"那种。 写下"反正要做的事情"的第一小步即可。 写你愿意去做的,不是你只是想象会去做但还没动力的。 你的任务列表不该带来负罪感。
要稍后再做的事情,按 "To Later"。
朋友推荐了一本书给你。 家里的黄油和面包没了。 这些事一直挂在脑子里,会让人心累。
丢进聊天框,再转到对应的清单里。
你不必费心想结构,它是预定义的。 当然,你也完全可以按自己的喜好来。
Chat.mdbrain/Note.md、<category>/*.mdRead.md、Watch.md、Shop.md、MyChecklist_.mdjournal/2024.08 August.mdLater.mdhabits/Ate consciously.md、habits/*.mdmedia/*(png、jpg、webp、gif)archive/*.mdconfig.json这份结构也可以在 files.md/llms.txt 取到。
你可以直接复制到 CLAUDE.md 或 AGENTS.md,让你的 AI 助手理解整个目录布局。
| 快捷键 | 操作 |
|---|---|
[ |
插入到某个文件的链接 |
Cmd+K / Ctrl+K |
打开文件搜索框 |
Cmd+N / Ctrl+N |
新建文件 |
Cmd+M / Ctrl+M |
移动文件 |
Cmd+D / Ctrl+D |
删除文件 |
Cmd+Enter / Ctrl+Enter |
打开聊天 |
Cmd+Shift+Enter / Ctrl+Shift+Enter |
切换聊天弹窗 |
Cmd+[ / Ctrl+[ |
跳到上一个文件 |
Cmd+] / Ctrl+] |
跳到下一个文件 |
Cmd+~ / Ctrl+~ |
切换侧边栏 |
Cmd+B / Ctrl+B |
切换粗体 |
Cmd+I / Ctrl+I |
切换斜体 |
Cmd+Y / Ctrl+Y |
插入复选框 |
Cmd/Ctrl + Click |
复制纯文本 / 打开链接 |
Ctrl+Cmd+Space |
插入 emoji(macOS) |
所有脚本都在 cmd 目录下,请在你的笔记文件夹里运行。请先安装 Go。
go run /abs/path/to/files.md/cmd/whoop/whoop.go
把 [[wikilinks]] 转成标准的 [Name](/path.md)(支持 --dry-run):
go run /abs/path/to/files.md/cmd/tomdlinks/tomdlinks.go .
在被引用的文件里加上回链(支持 --dry-run):
go run /abs/path/to/files.md/cmd/backlink/backlink.go
把日记文件中的时间戳整体平移 N 小时(换时区后很实用):
go run /abs/path/to/files.md/cmd/shifttime/shifttime.go
在自己的服务器上部署 Telegram 机器人 同步流程 集成测试
web —— Web 应用(PWA),入口是 index.htmlweb/lib —— 前端依赖库cmd/server —— 服务端入口cmd/*/ —— 处理 .md 文件的脚本server/bot.go —— 机器人server/sync/ —— 同步 API 服务端vendor —— 后端依赖tests —— 端到端测试,会同时覆盖 Web 应用和服务端vendor 和 web/lib 都在仓库里更完整的原则请参考 这份指南。
get* 前缀命名方法.md 文件里PATCHED 关键字标注CodeMirror,那就太棒了/web/index.html,它仍然要能直接跑await 会引入竞态filename —— 带扩展名的文件名,例如 "note.md"(用它作为 ID)header —— 去掉扩展名并首字母大写后的文件名,例如 "Note"body —— 文件内容dir —— 用来按类别存放笔记的目录,例如 "happiness"userID —— 即 chatID。大多数场景下我们就直接用 chatID(私聊机器人)ctime —— 数据块或元数据变更时间:所有权、位置、文件类型、权限变更都会触发。父目录改名不会触发,移动文件会触发,重命名会触发。我们需要它来追踪文件的位置变化,比如什么时候被移到归档、追踪任务的"愤怒度"等mtime —— 文件内容最近一次被修改的时间。和 ctime 不同,所有权、权限、改名都不会影响它。我们用它来做同步ctime —— 增删文件或子目录会触发(类似 mtime,再加上 inode 的变化,比如改名)每个文件都可以通过文件名与所在目录唯一定位。我们只支持一层嵌套。
项目跑起来飞快 :) 如果你怕用文件或互斥锁会带来性能开销,看一眼这张对比:
Mutex 加 / 解锁 = 25 ns
从 SSD 随机读 4K = 150,000 ns
1 ms = 1,000,000 ns
06.05.2026 从 Today.md 切回 Chat.md。用户访谈发现"chat"这个概念用户更容易理解。而且 "open chat" 这句话在机器人和网页应用里语义都一致。02.05.2026 hide-token 现在在每次变更时同步运行;之前的 100ms 防抖会让链接和格式化文本在逐字删除时出现抖动。06.05.2026 把 Inbox.md 和 Today.md 合并成了 Today.md。"Inbox"这个名字太抽象、太"生产力"和 GTD 味道。我想要的是从容和简洁。Today 更像"我活在聊天里的那一页"。23.04.2026 把 API_HOST、APP_HOST 改成了 API_URL、APP_URL。不同环境下,配置里能携带 schema 等更多信息总归更好。22.04.2026 机器人里的 Inbox 条目改用稳定的内容哈希识别(对去掉 - [ ] / - [x] 标记后的块取 fs.Hash),而不是位置序号。这样即便中间有条目被新增/删除/完成,按钮也仍指向正确的那一行。06.05.2026 同时存在 "to inbox" 和 "to chat" 两个按钮,心智上挺累。也很难轻松地把任务往 chat 里随手一丢——因为它会先落到 inbox,还要多点一次。这一次多余的点击,正是让"添加新任务"变得令人厌烦的原因。我放弃了两条不同的流程,现在一切都先进 inbox,每一项都是 Markdown 复选框。额外的好处:PWA 默认展示 chat 里的任务,特别顺手。也许 "inbox" 这个词心智负担太重,"chat" 听起来更轻松。再观察一下。11.04.2026 虽然我希望以纯 Markdown 链接形式存储链接,但视觉上我希望它们能像极简的 [link] 一样工作。所以当光标停在该行时,我会隐藏 (...) 那部分。仅对指向 md 文件的链接生效。11.04.2026 又把标准 Markdown 链接拉回来了。我希望这个知识库跨平台可用,它必须在 GitHub 上也能正常显示。05.04.2026 试过把 web/* 移到根目录以求简洁,结果发现是个坏主意——必须有一个显式的目录,作为服务器上的公开 DOCROOT。19.04.2026 改成了 [link] 形式的链接。[link](full%20path) 太重也太突兀,我们也不想处理路径变更。21.09.2025 移除了 WASM。我当时遇到一个 bug:从 Inbox.txt 删除一条消息后,按"move to file"没有把它写到目标文件里。我没复现出来,但发现了一大堆复杂度:JS -> Go(writeFile)-> Go 等待来自 JS 的 promise -> 中间的 JS Golang 运行时 -> JS(writeFile)-> Go(promise 返回)-> 把结果发回 JS。而且这一切还得跑在独立 goroutine 里,因为 WASM 和 JS 共用一个线程。再加上 Go 的 WASM 仍是实验性的。组件太多、不确定性太大。当时我不愿意用 JS 重写已经能用的逻辑,于是用了 WASM 撑了一段时间。现在该用 JS 把它重新实现,把这一整摞复杂度都甩掉。另外 inbox.wasm 大约 8MB,我希望整个应用尽可能小。11.07.2025 决定先用 OPFS 作为文件系统的初始驱动。浏览器兼容性更好,对用户更省心。应用默认以 OPFS 启动;用户需要时可以打开一个本地目录,切到 Local FileSystem API。DirHandle 会被保存到 IndexedDB,下次复用。08.07.2025 根目录现在是 / 而不是空字符串。Web 应用里所有文件按路径唯一标识,不再用 dir + filename,并限制为一层嵌套。11.04.2026 Dropbox 会改动新创建文件的某些元数据,因此 ctime 会被改写。我考虑过把同步切到 mtime,但这样就检测不出重命名(虽然我们另有机制检测重命名),而 mtime 整体上更可靠:权限/所有权变更也不会触发同步。最终切换到了 mtime。mtime 用于内容级同步,ctime 用于追加式同步日志(重命名 / 删除)。另外 mtime 可以从 .git/archive 里恢复,ctime 不行。30.06.2025 决定把所有流程,包括待办列表,都迁移到 Chat.md。补充:这种流程不太方便处理多行任务,可能需要同时支持文件和索引。两种实现思路:参数统一编码,复用同一个命令处理器加 if 分支;或者用不同的命令处理器分别处理 chat / 文件。我选了后者。补充:如果走分流,"move to" 按钮的配置会更复杂。补充:也许在"move to file"时把文件移回 Chat.md,复用现有流程?补充:目前看来还不错。我们的 chat.md 充当一个仅追加日志。额外的好处是:即便某些流程(比如安排时间 / 移动)没走完,内容也保留在日志里,下次可以继续。06.05.2026 所有新进消息现在默认进 Chat.md。在此之前它们会被移到 /chat 并变成任务,这对简单的 to-do 列表很合适,但对其他用例不够灵活。我意识到开会时,我真正需要的就是一个简单的输入框,把脑子里乱七八糟的东西先丢进去,不必立即决定怎么处理,回头再整理就好。它们可能是任务、可能是日记、也可能就是文件。同时保持一条简单到无需理解的默认流程,对用户更友好——所有消息都丢进同一个文件,仅此而已。27.06.2025 Chat 现在默认是"一个大文件"模式,也就是把所有消息都堆进同一个文件,不做更多事。还是那句话:从最简单的流程开始,不要一上来就把用户淹没。补充:如果选了完整模式,我们就得提前建好目录,"to habits"、"to read/shop" 之类才能工作。用户用不上的话,把目录删了我们就不再自动重建(不像"按需创建"模式那样)。所以"按需创建"并不适合所有场景。26.06.2025 之前是提前把所有目录都建好,现在改成按需创建。这样不会一上来就把用户的知识库塞得乱七八糟。24.06.2025 同步时改用微秒级别追踪文件变化。连续创建文件之间的间隔通常在 1000μs–5000μs,足够区分。没用纳秒是因为 JS 处理 int64 精度有问题。补充:Linux 用的是内核缓存时间,按 CONFIG_HZ 间隔更新(grep CONFIG_HZ /boot/config-$(uname -r)),我这里是 1000(1ms)。实际操作之间的间隔通常远大于 1ms:用户交互、网络延迟、磁盘 I/O 都会拉长间隔。只有在原生紧凑循环里更新文件才可能踩坑。16.06.2025 我觉得是时候让知识库真正跨平台了——禁掉文件名里的 :?<>* 等字符。这些字符在某些环境(Windows、PWA)里本来就不允许。15.09.2025 我想在浏览器里有类机器人的能力。又不想把已经被良好测试过的代码用 TypeScript 重写一遍,所以用了 wasm。它确实跑得挺好。12.06.2025 我们把 Telegram 机器人当作通往知识库的"无干扰、只写"入口。唯一的问题是它在欧美没那么流行。后来想到:把窗口缩小后,app.files.md 也可以直接呈现成一个聊天界面!这将是移动端的默认形态。04.06.2025 引入了用于同步的追加式日志。无状态同步实现起来很费劲——每次请求都要把所有文件发过去。既然服务器端只处理重命名,那我们只追踪重命名就好。04.06.2025 仅做内容同步(不含重命名 / 删除)时,服务端不存任何状态,只比较哈希和最近的 ctime。11.11.2024 移除了 Wikilinks 支持。只保留纯 Markdown 链接,我们的知识库必须保持互操作性。26.10.2024 更新现在按用户串行处理。原因是并发写文件出现过竞态。同时还遇到过转发消息乱序的问题,导致无法合并成一条。06.10.2024 移除了 fyne.io。一开始我只是想找一个比 Electron 更轻量的方案,fyne.io 看起来是个理想候选。用了几天,机器人 80% 的功能已经搬过来了,体验也不错。但要把剩下 20% 落地,得花上巨大的工夫——滚动行为、emoji 渲染、文本选择、链接支持等等细枝末节。未来还要做图片上传、Markdown/HTML 渲染,在一个不基于 webview 的工具集里这些会非常痛苦。尽管我个人挺反感用 Web 技术做桌面应用,但似乎没得选。试试 wails.io。09.09.2024 我们用 vendoring 管理依赖。我希望所有的少量依赖都在仓库里,这样就不必担心依赖被屏蔽或下线。我们的仓库就是自给自足的"唯一可信源"。09.06.2025 我们在 db、journal、userconfig 里使用细粒度锁,而不是给每个用户上一把全局锁,以避免瓶颈。Workers 可能要调外部 API(如 ChatGPT),不希望长期持有用户锁。已 PATCHED——加入了按用户串行更新,bot 自身不会导致竞态,但 bot 和 worker 之间仍可能竞态,所以继续保留细粒度锁。20.08.2024 我们在每次访问时都从配置文件读取 userconfig 的每个字段。不需要在 bot.Answer() 前后整体加载/保存配置。修改时必须重新读取,避免写回过时数据。设想一下:如果只在 bot.Answer() 之前加载一次,而 bot.Answer() 中又有可观的网络延迟(比如对外部接口发请求要 2 秒),那这 2 秒内 `worker.MoveDueT$ claude mcp add files.md \
-- python -m otcore.mcp_server <graph>