内容
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="assets/hatchdoor-wordmark-dark.png">
<img src="assets/hatchdoor-wordmark.png" alt="Hatchdoor" width="340">
</picture>
</p>
<p align="center">
<a href="https://hatchdoor.battercloud.cc"><img alt="Live demo" src="https://img.shields.io/badge/live_demo-hatchdoor.battercloud.cc-e4572e"></a>
<a href="https://hub.docker.com/r/battermanz/hatchdoor"><img alt="Docker Hub" src="https://img.shields.io/docker/v/battermanz/hatchdoor?sort=semver&label=docker%20hub&color=2496ed"></a>
<a href="https://github.com/BattermanZ/Hatchdoor/blob/main/Dockerfile"><img alt="Rootless and distroless image" src="https://img.shields.io/badge/image-rootless_%26_distroless-2ea44f"></a>
<a href="LICENSE"><img alt="License: AGPL-3.0" src="https://img.shields.io/badge/license-AGPL--3.0-blue"></a>
</p>
# Hatchdoor
Hatchdoor 是一个自托管的、**agent-native** 的 Obsidian 风格的 Markdown 仓库的网页应用。你可以在快速的网页界面中浏览、搜索和编辑你的笔记,并为 AI 代理提供与 Model Context Protocol(MCP)相同权限的访问权限。
你可以将像 Claude、Claude Code、Codex、Cursor 或 Hermes 这样的 MCP 客户端指向 Hatchdoor,你的代理可以读取、搜索(关键词和语义)、创建、编辑、移动和链接笔记。每个操作都经过相同的原子化仓库操作,确保安全性和一致性,并可选地自动进行 git 提交和推送。网页界面和你的代理是同一个仓库的两个入口。
你的 Markdown 文件始终是真实的来源。Hatchdoor 为快速浏览、链接、反向链接、关键词搜索、语义搜索、图数据和元数据构建了一个可丢弃的 SQLite 读取模型。如果缓存被删除,Hatchdoor 将从仓库中重建它。
Hatchdoor 是与 AI 编码代理一起构建的,主要包括 Claude Code 和 Codex,并在人类密切监督下进行测试,并带有文档化的安全模型。
<p align="center">
<a href="https://hatchdoor.battercloud.cc">
<img src="assets/screenshots/hero-light.png" width="900"
alt="Hatchdoor 浏览一个笔记:左侧是仓库资源管理器,中间是渲染的 Markdown,右侧是页面大纲">
</a>
</p>
<p align="center">
<b><a href="https://hatchdoor.battercloud.cc">▶ 尝试在线演示</a></b>,一个只读的公共仓库。
</p>
<details>
<summary><b>目录</b></summary>
- [你能得到什么](#你能得到什么)
- [截图](#截图)
- [它适合谁](#它适合谁)
- [使用 Docker 快速开始](#使用-docker-快速开始)
- [数据和安全模型](#数据和安全模型)
- [权限](#权限)
- [配置](#配置)
- [使用 Hatchdoor](#使用hatchdoor)
- [MCP 代理访问](#mcp-代理访问)
- [Git 同步](#git-同步)
- [在没有 Docker 的情况下运行](#在没有-docker的情况下运行)
- [故障排除](#故障排除)
- [API 参考](#api-参考)
- [安全说明](#安全说明)
- [开发](#开发)
- [项目文档](#项目文档)
- [许可证](#许可证)
</details>
## 你能得到什么
- 用于浏览文件夹和 Markdown 笔记的网页界面。
- `/n/:slug` 处的干净的笔记 URL。
- Obsidian 风格的 wikilinks,支持 `[[Note]]`、`[[Folder/Note]]` 和 `[[Note|Alias]]`。
- GitHub-flavored Markdown 渲染,支持数学、Mermaid 图表、frontmatter、图像、附件和损坏链接样式。
- 关键词搜索和语义搜索。
- 最近的笔记、反向链接、外部链接、统计数据和图视图。
- 当 vault 挂载可写时,支持浏览器写入。
- 附件上传和本地资产服务。
- 一个一级的 MCP 服务器,允许 AI 代理读取、搜索、创建、编辑和链接笔记,安全性与网页界面相同。
- 可选的自动 git 提交和推送,用于 Hatchdoor 写入。
- PWA 资产和服务工作线程缓存,用于常见的读取路径。
- 无依赖的、rootless 的容器镜像(无 shell,运行为 `nonroot` 用户),可使用 Docker 或 Podman 部署。
## 截图
<table>
<tr>
<td width="50%" valign="top">
<img src="assets/screenshots/graph-light.png" width="100%" alt="交互式知识图谱,包含笔记、链接和标签">
<p align="center"><sub><b>知识图谱</b>:笔记、链接和标签</sub></p>
</td>
<td width="50%" valign="top">
<img src="assets/screenshots/search-light.png" width="100%" alt="搜索结果,包含自然语言查询的片段">
<p align="center"><sub><b>语义 + 关键词搜索</b></sub></p>
</td>
</tr>
<tr>
<td width="50%" valign="top">
<img src="assets/screenshots/hero-dark.png" width="100%" alt="暗色主题下的笔记视图">
<p align="center"><sub><b>暗色主题</b></sub></p>
</td>
<td width="50%" valign="top" align="center">
<img src="assets/screenshots/mobile-light.png" width="260" alt="手机上的响应式布局">
<p align="center"><sub><b>响应式且可安装(PWA)</b></sub></p>
</td>
</tr>
</table>
## 它适合谁
如果你有一个 Markdown 笔记文件夹,并希望一个私有的网页界面来访问它们,Hatchdoor 就是一个合适的选择。
它足够初学者使用,可以使用 Docker Compose 运行,但也为想要代理访问、git 备份的 vault 同步、语义搜索和本地开发的人员提供了高级功能。
Hatchdoor 不是一个托管的同步服务,不是一个多用户协作平台,也不是 Obsidian 的替代品。它是一个自托管的 Markdown 仓库伴侣,你可以完全控制它。
## 使用 Docker 快速开始
### 1. 需求
你需要:
- Docker 和 Docker Compose(Podman 和 `podman compose` 也支持)
- 一个 Markdown 仓库文件夹,或一个空文件夹,如果你想让 Hatchdoor 创建一个启动仓库
### 2. 创建你的配置文件
复制示例环境文件:
```bash
cp .env.example .env
```
编辑 `.env` 并至少设置以下值:
```env
HOST_VAULT_PATH=/absolute/path/to/your/markdown-vault
HOST_CACHE_PATH=./data/cache
HATCHDOOR_WEB_BEARER_TOKEN=选择一个长随机令牌
```
这些设置的作用:
- `HOST_VAULT_PATH` 是主机上的 Markdown 仓库路径。
- `HOST_CACHE_PATH` 存储 Hatchdoor 生成的 SQLite 缓存。
- `HATCHDOOR_WEB_BEARER_TOKEN` 保护浏览器中的笔记。
Docker Compose 将 Hatchdoor 绑定到容器内的 `0.0.0.0`,因此发布的端口有效。Hatchdoor 拒绝在非回环绑定上启动,除非设置了 `HATCHDOOR_WEB_BEARER_TOKEN`,否则在显式只读演示模式下除外。
### 3. 启动 Hatchdoor
```bash
docker compose up -d
```
打开:
```text
http://localhost:42824
```
输入网页令牌。
### 4. 容器镜像和路径
镜像发布在 [Docker Hub](https://hub.docker.com/r/battermanz/hatchdoor):
```text
battermanz/hatchdoor:latest # 还有版本号标签,例如 2.2.0
battermanz/hatchdoor:podman-latest # 适用于 Podman 用户(还有 podman-<version>)
```
运行时镜像是 **无依赖的且无 root 用户** 的。它基于 `gcr.io/distroless/cc-debian13:nonroot` 构建,不包含 shell 或包管理器,运行为非特权 `nonroot` 用户。Hatchdoor 也在 Podman 下运行不变;交换 `docker` / `docker compose` 为 `podman` / `podman compose`。
Docker Compose 挂载:
| 容器路径 | 用途 |
| --- | --- |
| `/data/vault` | Markdown 仓库,真实来源 |
| `/data/cache` | 生成的 SQLite 缓存 |
| `/data/attachments-inbox` | MCP 附件导入的临时暂存文件夹 |
## 数据和安全模型
Hatchdoor 围绕一个简单的规则设计:你的 Markdown 仓库是真实的来源。
- Markdown 文件存放在 `VAULT_PATH`。
- SQLite 是一个生成的缓存,可以重建。
- SQLite 缓存应位于仓库之外。
- Hatchdoor 扫描 vault 下的 `.md` 文件,排除 `.hatchdoor-trash`。
- 删除操作会将笔记和引用的资产移动到 `.hatchdoor-trash`。
- 存档操作会将笔记移动到 `HATCHDOOR_ARCHIVE_PREFIX` 下。
- 浏览器写入操作仅在 vault 可写时可用。
- MCP 默认禁用。
- MCP 需要启用时使用自己的 Bearer Token。
如果 `VAULT_PATH` 包含没有 Markdown 文件,Hatchdoor 会创建一个小型启动仓库,然后在第一次索引构建之前。现有的仓库不会被此启动步骤播种或修改(`.hatchdoor-trash` 文件夹被忽略以决定 vault 是否为空)。
启动仓库布局了一个轻量级 PARA 样式结构,包含索引笔记和入门参考:
```text
README.md
10-topics/Topics Index.md
20-projects/Projects Index.md
30-areas/Areas Index.md
40-reference/Hatchdoor — Getting Started.md
40-reference/Hatchdoor — Agent Guide.md
40-reference/Hatchdoor — Agent Skill.md
40-reference/Hatchdoor — Markdown Feature Showcase.md
40-reference/Hatchdoor — Starter Vault Organisation.md
```
这些是普通的笔记,你可以像其他笔记一样编辑、移动或删除。参考笔记兼作入门文档,包括一个可用的 **代理技能** 模板(参见 [MCP 代理访问](#mcp-代理访问)),用于通过 MCP 将 AI 代理连接到仓库。
## 权限
Docker 镜像以非 root 用户运行。
对于只读浏览:
- 如果需要,可以将 vault 只读挂载。
- 保持缓存目录可写。
对于浏览器写入、MCP 写入、附件上传或 git 同步:
- 容器运行时用户必须能够写入 vault 挂载。
- 缓存目录必须可写。
- 当启用 MCP 附件导入时,附件暂存目录必须可写。
如果 Hatchdoor 启动但写入功能被禁用,请检查 `.env` 中的 `HOST_VAULT_PATH` 是否解析为实际的 vault 并不是输入错误或 Docker 卷的影子遮蔽挂载。
## 配置
复制 `.env.example` 到 `.env` 并调整值。
### 基本服务器和存储
| 变量 | 默认值 | 用途 |
| --- | --- | --- |
| `HOST_VAULT_PATH` | `./vault` | Docker Compose 的主机端 vault 路径 |
| `HOST_CACHE_PATH` | `./data/cache` | Docker Compose 的主机端缓存目录 |
| `VAULT_PATH` | `/data/vault` | Hatchdoor 读取的运行时 vault 路径 |
| `HATCHDOOR_CACHE_DB` | `/data/cache/hatchdoor-cache.sqlite3` | 运行时 SQLite 缓存文件 |
| `HOST` | `127.0.0.1` | 本地 `cargo run` 的绑定主机 |
| `PORT` | `42824` | HTTP 端口 |
| `RUST_LOG` | `hatchdoor=info,tower_http=info,axum::rejection=warn` | 后端日志过滤器 |
### 网页认证
| 变量 | 默认值 | 用途 |
| --- | --- | --- |
| `HATCHDOOR_WEB_BEARER_TOKEN` | 空 | 保护 `/api/*`、` /vault-assets/*` 和笔记下载 |
| `HATCHDOOR_DEMO_MODE` | `false` | 允许未经身份验证的公共浏览,同时禁用 Hatchdoor 写入功能 |
当设置此令牌时,受保护的请求必须发送:
```text
Authorization: Bearer <token>
```
捆绑的 PWA 在 `401` 响应后本地存储令牌,并在 API 调用中附加它。对于图像、下载和服务器发送的事件 URL,无法设置标头,前端会追加一个 `access_token` 查询参数。
Hatchdoor 拒绝在 `HOST=0.0.0.0` 或其他非回环绑定上启动,除非设置了 `HATCHDOOR_WEB_BEARER_TOKEN`。
对于一个公共测试实例,人们可以在没有凭证的情况下浏览,使用演示模式:
```env
HOST=0.0.0.0
HATCHDOOR_DEMO_MODE=true
HATCHDOOR_WEB_BEARER_TOKEN=
HATCHDOOR_MCP_ENABLED=false
HATCHDOOR_GIT_SYNC_ENABLED=false
```
演示模式故意为只读。它禁用浏览器写入操作和手动 `/api/refresh` 索引,报告通过 `/api/write-capabilities` 写入不可用,并拒绝启动,如果启用了 MCP 或自动 git 同步。
演示模式不限制请求速率。搜索计算每个查询的嵌入式模型,笔记下载会将附件捆绑在内存中,因此匿名访问者可以生成实际的 CPU 和内存负载。将公共演示放在速率限制反向代理(例如 nginx `limit_req`,Caddy `rate_limit` 或 Traefik `rateLimit` 中间件)后再公开给互联网。
### 仓库行为
| 变量 | 默认值 | 用途 |
| --- | --- | --- |
| `HATCHDOOR_ARCHIVE_PREFIX` | `90-archive/` | 仓库相对文件夹前缀,用于存档操作和存档链接样式 |
## 使用 Hatchdoor
### 浏览
Hatchdoor 从你的 vault 文件夹和 Markdown 文件构建文件夹资源管理器。UI 根目录命名为 `Vault`。文件夹名称直接来自你的文件系统;Hatchdoor 不需要 PARA、Zettelkasten 或编号的文件夹方案。
### 笔记 URL 和链接
笔记 slug 从 Markdown 文件名生成。重复的文件名会收到唯一的后缀,因此路由保持稳定。
支持的 wikilinks 包括:
```text
[[Note]]
[[Folder/Note]]
[[Note|Alias]]
```
Hatchdoor 将链接、反向链接、标题、标签、图数据和损坏链接状态解析到 SQLite 缓存中。
### 搜索
Hatchdoor 存储:
- 完整的 Markdown 内容
- 文件元数据
- 标签和标题
- Wikilinks 和反向链接
- FTS5 关键词搜索数据
- sqlite-vec 语义向量
递归的 vault 监视器在 Markdown 或资产更改后刷新缓存。浏览器客户端订阅 `/api/vault-events` 并在广播的修订版广播后重新加载可见数据。
### 手动缓存重建
如果你想从头重建缓存:
```bash
rm ./data/cache/hatchdoor-cache.sqlite3
docker compose restart hatchdoor
```
调整路径如果你更改了 `HOST_CACHE_PATH`。
## MCP 代理访问
嵌入的 MCP 端点默认禁用。仅限于受信任的客户端启用。
MCP 需要启用时使用 Bearer Token,因为 `/mcp` 跳过网页身份验证层并可以暴露整个 vault。
```env
HATCHDOOR_MCP_ENABLED=true
HATCHDOOR_MCP_BEARER_TOKEN=change-me
```
启用单独启用写入工具:
```env
HATCHDOOR_MCP_WRITE_ENABLED=true
```
将端点注册到流式 HTTP MCP 客户端:
```text
http://127.0.0.1:42824/mcp
```
发送:
```text
Authorization: Bearer <token>
```
### 代理技能
Hatchdoor 随附一个可用的 **代理技能**,用于通过 MCP 驱动 vault。当 Hatchdoor 播种启动 vault 时,它会将模板写入 `40-reference/Hatchdoor — Agent Skill.md`;源代码位于 [`docs/starter-vault/40-reference/Hatchdoor — Agent Skill.md`](docs/starter-vault/40-reference/Hatchdoor%20%E2%80%94%20Agent%20Skill.md)。
复制其 `hatchdoor-vault` 技能块到你的代理技能目录,教导代理遵循 Hatchdoor 的约定:搜索前编辑,传递返回的内容哈希,进行小幅编辑,让 Hatchdoor 管理反向链接、移动和 git 同步。
### MCP 附件导入
附件导入使用 vault 外部的暂存文件夹:
```env
HOST_ATTACHMENT_STAGING_PATH=./data/attachments-inbox
HATCHDOOR_MCP_ATTACHMENT_STAGING_PATH=/data/attachments-inbox
HATCHDOOR_MCP_MAX_ATTACHMENT_BYTES=10485760
HATCHDOOR_MCP_ADVERTISE_HOST_PATHS=false
```
仅当本地/开发代理需要查看主机暂存路径时,请设置 `HATCHDOOR_MCP_ADVERTISE_HOST_PATHS=true`。请在共享或远程部署中保持其为假。
## Git 同步
Git 同步是可选的,默认情况下是禁用的。当成功的 Hatchdoor 写入工具提交并将 vault 更改推送到配置的远程。
```env
HATCHDOOR_GIT_SYNC_ENABLED=true
HATCHDOOR_GIT_REMOTE=origin
HATCHDOOR_GIT_BRANCH=main
HATCHDOOR_GIT_HTTPS_USERNAME=hatchdoor
HATCHDOOR_GIT_HTTPS_TOKEN=your-token
HATCHDOOR_GIT_DEBOUNCE_SECONDS=30
HATCHDOOR_GIT_AUTHOR_NAME=Hatchdoor
HATCHDOOR_GIT_AUTHOR_EMAIL=hatchdoor@localhost
```
需求:
- vault 目录必须是 git 仓库根目录。
- 检出的分支必须与 `HATCHDOOR_GIT_BRANCH` 匹配。
- 远程 URL 来自存储库的现有远程配置。
- 身份验证使用 HTTPS 用户名/令牌凭证。
- 合并冲突保留供人类解决在服务器上。
使用 `get_git_sync_status` MCP 工具检查最近的写入是否已提交并推送。
## 在没有 Docker 的情况下运行
在构建前端:
```bash
cd frontend
npm ci
npm run build
cd ..
```
运行后端:
```bash
cargo run
```
默认情况下,本地源代码运行绑定到 `127.0.0.1:42824` 并读取 `./vault`。通过以下方式将 Hatchdoor 指向真正的 vault:
```bash
VAULT_PATH=/path/to/notes cargo run
```
对于前端开发模式:
```bash
# terminal 1
cargo run
# terminal 2
cd frontend
npm run dev
```
可选:预取语义搜索使用的嵌入式模型:
```bash
cargo run -- --prefetch-embedder
```
## 故障排除
### Hatchdoor 拒绝在 `0.0.0.0` 启动
设置 `HATCHDOOR_WEB_BEARER_TOKEN`,绑定到 `127.0.0.1`,或启用 `HATCHDOOR_DEMO_MODE=true` 以获取公共演示。
这是故意的。非回环绑定可以公开你的 vault 到网络,因此 Hatchdoor 需要网页身份验证,除非演示模式禁用了应用程序的写入表面。
### Docker 启动,但 UI 无法写入
检查容器运行时用户挂载的 vault 目录是否可写。浏览器写入支持依赖于文件系统权限。
### 缓存错误或过时数据
删除生成的 SQLite 缓存并重启:
```bash
rm ./data/cache/hatchdoor-cache.sqlite3
docker compose restart hatchdoor
```
### 应用程序启动时带有启动仓库
Hatchdoor 仅在 `VAULT_PATH` 包含没有 Markdown 文件时才会播种启动笔记。如果你期望现有的 vault,这几乎总是意味着容器挂载了一个空目录,因此请仔细检查 `HOST_VAULT_PATH` 在 `.env` 中是否解析为实际的 vault 而不是输入错误或 Docker 卷的影子遮蔽挂载。
有关 Hatchdoor 创建的完整笔记列表,请参见 [数据和安全模型](#数据和安全模型)。
### MCP 返回 `401` 或 `403`
检查:
- `HATCHDOOR_MCP_ENABLED=true`
- 设置了 `HATCHDOOR_MCP_BEARER_TOKEN`
- 客户端发送 `Authorization: Bearer <token>`
- 浏览器源的 MCP 请求来自 `HATCHDOOR_MCP_ALLOWED_ORIGINS` 中允许的来源
### Git 同步不推送
检查:
- vault 是 git 仓库根目录。
- 当前分支与 `HATCHDOOR_GIT_BRANCH` 匹配。
- 远程存储库存在于仓库配置中。
- HTTPS 令牌可以推送。
- 没有等待手动解决的合并冲突。
## API 参考
常用路由:
| 方法 | 路径 | 目的 |
| --- | --- | --- |
| `GET` | `/health` | 健康检查 |
| `GET` | `/api/tree` | 文件夹和笔记树 |
| `GET` | `/api/recently-modified` | 最近修改的笔记 |
| `GET` | `/api/note/:slug` | 读取笔记 |
| `GET` | `/api/note/:slug/links` | 外链和反向链接 |
| `GET` | `/api/note/:slug/download` | 下载 Markdown 导出 |
| `GET` | `/api/resolve?target=...` | 解析维基链接目标 |
| `POST` | `/api/resolve-batch` | 批量解析维基链接目标 |
| `GET` | `/api/search?q=...` | 搜索笔记 |
| `GET` | `/api/stats` | 保险库统计 |
| `GET` | `/api/graph` | 图形数据 |
| `POST` | `/api/refresh` | 触发缓存刷新 |
| `GET` | `/api/vault-events` | 服务器发送的保险库修订事件 |
| `GET` | `/api/write-capabilities` | 检查写入可用性 |
| `POST` | `/api/note` | 创建笔记 |
| `PUT` | `/api/note/:slug` | 更新笔记 |
| `PATCH` | `/api/note/:slug/rename` | 重命名笔记 |
| `PATCH` | `/api/note/:slug/move` | 移动笔记 |
| `PATCH` | `/api/note/:slug/archive` | 存档笔记 |
| `PATCH` | `/api/note/:slug/move-rename` | 移动和重命名笔记 |
| `DELETE` | `/api/note/:slug` | 移动笔记到回收站 |
| `POST` | `/api/attachment` | 上传附件 |
| `GET` | `/vault-assets/*path` | 提供保险库资产 |
| `POST` | `/mcp` | 可流式传输的 HTTP MCP 端点 |
## 安全注意事项
- 使用长随机 `HATCHDOOR_WEB_BEARER_TOKEN`。
- 不要在没有 HTTPS 的情况下公开暴露 Hatchdoor。
- 仅在只读公共测试实例中使用 `HATCHDOOR_DEMO_MODE=true`。
- 除非需要,否则保持 MCP 禁用。
- 将 MCP 写入模式视为强大:它可以创建、编辑、移动、删除和导入内容。
- 将 SQLite 缓存保持在保险库之外。
- 将 `.env` 文件排除在 git 之外。
- 在启动容器之前检查 Docker 卷路径。
## 开发
后端检查:
```bash
cargo fmt --check
CARGO_BUILD_JOBS=1 cargo clippy --all-targets -- -D warnings
CARGO_BUILD_JOBS=1 cargo test
```
前端检查:
```bash
cd frontend
npm run format:check
npm run typecheck
npm run lint
npm test
npm run build
```
构建和发布 Docker 镜像:
```bash
docker build -t battermanz/hatchdoor:latest .
docker tag battermanz/hatchdoor:latest battermanz/hatchdoor:2.2.0
docker push battermanz/hatchdoor:2.2.0
docker push battermanz/hatchdoor:latest
```
## 项目文档
- [设计系统](docs/design-system.html):前端使用的视觉令牌、组件模式、布局规则和交互状态。
- [语义搜索策略](docs/adr/semantic-search-strategy.md):在运行时路径中发送纯语义搜索而不是混合检索或交叉编码重新排序的决策记录。
## 许可证
Hatchdoor 仅在 GNU Affero 通用公共许可证 v3.0 下获得许可。
参见 [LICENSE](LICENSE)。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器