内容
<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 是一款适用于 Obsidian 风格 Markdown 仓库的自托管、**原生代理** 网页应用。你可以在快速的网页界面中浏览、搜索和编辑笔记,并为 AI 代理提供与同一个仓库进行交互的能力,遵循模型上下文协议(MCP)。
将 MCP 客户端(如 Claude、Claude Code、Codex、Cursor 或 Hermes)指向 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 和 wikilinks,右侧是页面大纲">
</a>
</p>
<p align="center">
<b><a href="https://hatchdoor.battercloud.cc">▶ 尝试在线演示</a></b>,一个只读的公共仓库。
</p>
<details>
<summary><b>目录</b></summary>
- [您将获得](#您将获得)
- [截图](#截图)
- [适用人群](#适用人群)
- [使用 Docker 快速入门](#使用-docker-快速入门)
- [数据和安全模型](#数据和安全模型)
- [为 LLM 维基组织仓库](#为-llm-维基组织仓库)
- [权限](#权限)
- [配置](#配置)
- [使用 Hatchdoor](#使用-hatchdoor)
- [MCP 代理访问](#mcp-代理访问)
- [Git 同步](#git-同步)
- [在没有 Docker 的情况下运行](#在没有-docker的情况下运行)
- [故障排除](#故障排除)
- [API 参考](#api-参考)
- [安全说明](#安全说明)
- [开发](#开发)
- [项目文档](#项目文档)
- [许可证](#许可证)
</details>
## 您将获得
- 用于浏览文件夹和 Markdown 笔记的网页界面。
- `/n/:slug` 处的干净笔记 URL。
- Obsidian 风格的 wikilinks,支持 `[[Note]]`、`[[Folder/Note]]` 和 `[[Note|Alias]]`。
- 使用 GitHub 风格的 Markdown、数学、Mermaid 图表、frontmatter、图像、附件和损坏链接样式进行 Markdown 渲染。
- 关键词搜索和语义搜索。
- 最近的笔记、反向链接、外部链接、统计数据和图形视图。
- 当仓库挂载可写时,支持浏览器写入。
- 附件上传、本地资产服务和链接的 PDF 仓库资产的内联预览。
- 一流的 MCP 服务器,允许 AI 代理使用与 UI 相同的安全性读取、搜索、创建、编辑和链接笔记。
- 可选的自动 git 提交和推送,以进行 Hatchdoor 编写。
- 用于常见读取路径的 PWA 资产和服务工作器缓存。
- 无依赖、 无 root 容器镜像(无 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 支持的仓库同步、语义搜索和本地开发的人员提供了高级功能。
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
HOST_MODELS_PATH=./models
HATCHDOOR_WEB_BEARER_TOKEN=choose-a-long-random-token
```
这些值的含义:
- `HOST_VAULT_PATH` 是主机上的 Markdown 仓库路径。
- `HOST_CACHE_PATH` 存储 Hatchdoor 生成的 SQLite 缓存。
- `HOST_MODELS_PATH` 存储下载的搜索模型和本地 Gemma 条款收据。
- `HATCHDOOR_WEB_BEARER_TOKEN` 保护浏览器中的笔记。
Docker Compose 在容器内将 Hatchdoor 绑定到 `0.0.0.0`,因此发布的端口有效。 除非设置了 `HATCHDOOR_WEB_BEARER_TOKEN`,否则 Hatchdoor 拒绝在非环回绑定上启动,但在显式只读演示模式下除外。
### 3. 启动 Hatchdoor
```bash
docker compose up -d
```
打开:
```text
http://localhost:42824
```
输入提示时输入网页 bearer token。
### 4. 选择您的搜索模型
Hatchdoor 镜像不包含任何模型权重。 在第一次启动时,Hatchdoor 会要求您选择如何设置语义搜索,然后再下载任何内容。
- **设置 Gemma** 是默认选项。 EmbeddingGemma 是多语言的,并提供最佳的搜索质量。 在网页界面中阅读并接受 Gemma 条款(或通过首次运行的 MCP 设置工具); 然后 Hatchdoor 下载模型,扫描仓库,并自动构建索引。
- **使用 Nomic 代替** 拒绝 Gemma 并使用 Nomic Embed Text v1.5 启动相同的设置。 它不需要 Gemma 接受,但仅限英语,不适合多语言仓库。
接受 Gemma 条款仅允许 Hatchdoor 下载和使用该模型。 它不会改变您对仓库或其内容的的所有权,Hatchdoor 不会将仓库内容发送到任何地方。 下载的模型和本地接受收据保留在 `HOST_MODELS_PATH` 中,因此在容器重启后保持不变。
UI 和日志显示下载和索引进度。 在设置准备好之前,仓库功能不可用; 如果模型下载失败,Hatchdoor 呈现重试操作而不是静默更改模型。
### 5. 容器镜像和路径
镜像在 [Docker Hub](https://hub.docker.com/r/battermanz/hatchdoor) 上发布:
```text
battermanz/hatchdoor:latest # 还有版本号标签,例如 2.4.0
battermanz/hatchdoor:podman-latest # 适用于 Podman 用户(也支持 podman-<version>)
```
运行时镜像**无依赖且无 root**。 它基于 `gcr.io/distroless/cc-debian13:nonroot`,不包含 shell 或包管理器,并以非特权用户 `nonroot` 运行。 Hatchdoor 也在 Podman 下运行(包括无 root); 交换 `docker` / `docker compose` 为 `podman` / `podman compose`。
Docker Compose 挂载:
| 容器路径 | 用途 |
| --- | --- |
| `/data/vault` | Markdown 仓库,真实来源 |
| `/data/cache` | 生成的 SQLite 缓存 |
| `/models` | 下载的搜索模型和本地 Gemma 条款收据 |
## 数据和安全模型
Hatchdoor 围绕一个简单的规则设计:您的 Markdown 仓库是真实来源。
- Markdown 文件存储在 `VAULT_PATH` 中。
- SQLite 是一个生成的缓存,可以重建。
- SQLite 缓存应位于仓库之外。
- Hatchdoor 扫描 `.md` 文件下的仓库,同时排除内置和配置的噪声路径(包括 `.hatchdoor-trash`)。
- 删除操作会将笔记和引用的资产移动到 `.hatchdoor-trash`。
- 存档操作会将笔记移动到 `HATCHDOOR_ARCHIVE_PREFIX` 下。
- 浏览器写入操作仅在仓库可写时可用。
- 默认禁用 MCP。
- 启用 MCP 时需要其自己的 bearer token。
- 默认禁用 git 同步。
如果 `VAULT_PATH` 不包含任何 Markdown 文件,Hatchdoor 会在第一次索引构建之前创建一个小型启动仓库。 现有仓库不会被此启动步骤播种或修改(`.hatchdoor-trash` 文件夹在决定仓库是否为空时会被忽略)。
启动仓库布局了一个轻量级的 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 代理连接到仓库。
## 为 LLM 维基组织仓库
Hatchdoor 适用于 [Andrej Karpathy 描述的 LLM Wiki 模式](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f): 将原始源材料与 LLM 维护的 Markdown 维基分开。
一个简单的仓库布局如下所示:
```text
vault/
├── raw/ # 原始文章、剪辑、转录、PDF 等
│ └── .hatchdoor-layer # 将原始文件放在其自己的 Hatchdoor 层上
├── wiki/ # 您或 LLM 维护的 Markdown 页面
└── AGENTS.md # 可选的代理维护 wiki 的说明
```
### 将原始来源放在单独的层上
在包含原始源材料的目录中创建以下文件:
```text
# raw/.hatchdoor-layer
raw
```
文件内容是层名称。 在此示例中,`raw/` 下的每个 Markdown 笔记都属于 `raw` 层。 它保持在 Hatchdoor 的浏览器界面和默认搜索结果之外,而 MCP 客户端可以显式选择它,方法是设置 `layers: ["raw"]`。 使用不同的名称,如果您愿意,例如 `sources`、`research` 或 `evidence`。
层是可见性和搜索边界; 它 **不** 使文件变为只读。 如果必须保持原始来源不变,请在您的代理说明中说明此规则(例如 `AGENTS.md` 或 `CLAUDE.md`)。
### 不要将层与排除混淆
当代理应该能够单独读取文件时使用层。 仅当 Hatchdoor 应该完全忽略某个路径时,才使用 `HATCHDOOR_EXCLUDE`:
```env
HATCHDOOR_EXCLUDE=imports/,*.bak
```
如果代理需要搜索或读取 `raw/`,请勿设置 `HATCHDOOR_EXCLUDE=raw/`; 被排除的文件在 Hatchdoor 的索引中不存在。
如果您的原始层很大,并且您希望避免为其创建向量嵌入,请设置:
```env
HATCHDOOR_EMBED_LAYERS=false
```
原始层在 MCP 客户端选择它时仍可进行关键词查找,无需使用向量索引资源。
## 权限
Docker 镜像以非 root 用户身份运行。
对于只读浏览:
- 如果您想挂载只读仓库,请这样做。
- 保持缓存目录可写。
对于浏览器写入、MCP 写入、附件上传或 git 同步:
- 仓库挂载必须对容器运行时用户可写。
- 缓存目录必须可写。
如果 Hatchdoor 启动但写入功能被禁用,请检查仓库挂载的权限,并从身份验证的浏览器会话中调用 `/api/write-capabilities`。
## 配置
复制 `.env.example` 到 `.env` 并调整值。
### 基本服务器和存储
| 变量 | 默认值 | 用途 |
| --- | --- | --- |
| `HOST_VAULT_PATH` | `./vault` | Docker Compose 的主机端仓库路径 |
| `HOST_CACHE_PATH` | `./data/cache` | Docker Compose 的主机端缓存目录 |
| `HOST_MODELS_PATH` | `./models` | Docker Compose 的持久化下载模型目录 |
| `VAULT_PATH` | `/data/vault` | Hatchdoor 读取的运行时仓库路径 |
| `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_WEB_BEARER_TOKEN`,否则 Hatchdoor 拒绝在非环回绑定上启动。
对于可以无需凭证浏览的公共测试实例,请使用演示模式:
```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_EXCLUDE` | 空 | 以 gitignore 样式的路径分隔列表,从索引中省略,附加在内置噪声规则之后 |
| `HATCHDOOR_EMBED_LAYERS` | `true` | 设置为 `false` 以保持降级层可进行关键词搜索,但跳过其向量嵌入 |
## 使用 Hatchdoor
### 浏览
Hatchdoor 根据您的仓库文件夹和 Markdown 文件构建文件夹资源管理器。 UI 根目录命名为 `Vault`。 文件夹名称直接来自您的文件系统; Hatchdoor 不需要 PARA、Zettelkasten 或编号文件夹方案。
### 仓库层和排除项
文件夹可以通过添加 `.hatchdoor-layer` 文件将其笔记放在命名、降级的层上。 最小的实用标记是 YAML 标量:
```text
# 在包含原始源代码的目录中创建以下文件:
# raw/.hatchdoor-layer
raw
```
文件内容是层名称。 在此示例中,`raw/` 下的每个 Markdown 笔记都属于 `raw` 层。 它保留在 Hatchdoor 的浏览器界面和默认搜索结果之外,而 MCP 客户端可以显式选择它,方法是设置 `layers: ["raw"]`。 使用不同的名称,如果您愿意,例如 `sources`、`research` 或 `evidence`。
层是可见性和搜索边界; 它 **不** 使文件变为只读。 如果必须保持原始来源不变,请在您的代理说明中说明此规则(例如 `AGENTS.md` 或 `CLAUDE.md`)。
### 不要将层与排除混淆
当代理应该能够单独读取文件时使用层。 仅当 Hatchdoor 应该完全忽略路径时,才使用 `HATCHDOOR_EXCLUDE`:
```env
HATCHDOOR_EXCLUDE=imports/,*.bak
```
如果代理需要搜索或读取 `raw/`,请不要设置 `HATCHDOOR_EXCLUDE=raw/`; 被排除的文件在 Hatchdoor 的索引中不存在。
如果您的原始层很大,并且您希望避免为其创建向量嵌入,请设置:
```env
HATCHDOOR_EMBED_LAYERS=false
```
原始层在 MCP 客户端选择它时仍然可进行关键词查找,无需使用向量索引资源。
## 权限
Docker 镜像以非 root 用户身份运行。
对于只读浏览:
- 如果您想挂载只读仓库,请这样做。
- 保持缓存目录可写。
对于浏览器写入、MCP 写入、附件上传或 git 同步:
- 仓库挂载必须对容器运行时用户可写。
- 缓存目录必须可写。
如果 Hatchdoor 启动但写入功能被禁用,请检查仓库挂载的权限,并从身份验证的浏览器会话中调用 `/api/write-capabilities`。
## 配置
复制 `.env.example` 到 `.env` 并调整值。
### 基本服务器和存储
| 变量 | 默认值 | 用途 |
| --- | --- | --- |
| `HOST_VAULT_PATH` | `./vault` | Docker Compose 的主机端仓库路径 |
| `HOST_CACHE_PATH` | `./data/cache` | Docker Compose 的主机端缓存目录 |
| `HOST_MODELS_PATH` | `./models` | Docker Compose 的持久化下载模型目录 |
| `VAULT_PATH` | `/data/vault` | Hatchdoor 读取的运行时仓库路径 |
| `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_WEB_BEARER_TOKEN`,否则 Hatchdoor 拒绝在非环回绑定上启动。
对于可以无需凭证浏览的公共测试实例,请使用演示模式:
```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_EXCLUDE` | 空 | 以 gitignore 样式的路径分隔列表,从索引中省略,附加在内置噪声规则之后 |
| `HATCHDOOR_EMBED_LAYERS` | `true` | 设置为 `false` 以保持降级层可进行关键词搜索,但跳过其向量嵌入 |
## 使用 Hatchdoor
### 浏览
Hatchdoor 根据您的仓库文件夹和 Markdown 文件构建文件夹资源管理器。 UI 根目录命名为 `Vault`。 文件夹名称直接来自您的文件系统; Hatchdoor 不需要 PARA、Zettelkasten 或编号文件夹方案。
### 仓库层和排除项
文件夹可以通过添加 `.hatchdoor-layer` 文件将其笔记放在命名、降级的层上。 最小的实用标记是 YAML 标量:
```text
# 在包含原始源代码的目录中创建以下文件:
# raw/.hatchdoor-layer
raw
```
文件内容是层名称。 在此示例中,`raw/` 下的每个 Markdown 笔记都属于 `raw` 层。 它保留在 Hatchdoor 的浏览器界面和默认搜索结果之外,而 MCP 客户端可以显式选择它,方法是设置 `layers: ["raw"]`。 使用不同的名称,如果您愿意,例如 `sources`、`research` 或 `evidence`。
层是可见性和搜索边界; 它 **不** 使文件变为只读。 如果必须保持原始来源不变,请在您的代理说明中说明此规则(例如 `AGENTS.md` 或 `CLAUDE.md`)。
### 不要将层与排除混淆
当代理应该能够单独读取文件时使用层。 仅当 Hatchdoor 应该完全忽略路径时,才使用 `HATCHDOOR_EXCLUDE`:
```env
HATCHDOOR_EXCLUDE=imports/,*.bak
```
如果代理需要搜索或读取 `raw/`,请不要设置 `HATCHDOOR_EXCLUDE=raw/`; 被排除的文件在 Hatchdoor 的索引中不存在。
如果您的原始层很大,并且您希望避免为其创建向量嵌入,请设置:
```env
HATCHDOOR_EMBED_LAYERS=false
```
原始层在 MCP 客户端选择它时仍然可进行关键词查找,无需使用向量索引资源。
## 权限
Docker 镜像以非 root 用户身份运行。
对于只读浏览:
- 如果您想挂载只读仓库,请这样做。
- 保持缓存目录可写。
对于浏览器写入、MCP 写入、附件上传或 git 同步:
- 仓库挂载必须对容器运行时用户可写。
- 缓存目录必须可写。
如果 Hatchdoor 启动但写入功能被禁用,请检查仓库挂载的权限,并从身份验证的浏览器会话中调用 `/api/write-capabilities`。
## 配置
复制 `.env.example` 到 `.env` 并调整值。
### 基本服务器和存储
| 变量 | 默认值 | 用途 |
| --- | --- | --- |
| `HOST_VAULT_PATH` | `./vault` | Docker Compose 的主机端仓库路径 |
| `HOST_CACHE_PATH` | `./data/cache` | Docker Compose 的主机端缓存目录 |
| `HOST_MODELS_PATH` | `./models` | Docker Compose 的持久化下载模型目录 |
| `VAULT_PATH` | `/data/vault` | Hatchdoor 读取的运行时仓库路径 |
| `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_WEB_BEARER_TOKEN`,否则 Hatchdoor 拒绝在非环回绑定上启动。
对于可以无需凭证浏览的公共测试实例,请使用演示模式:
```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_EXCLUDE` | 空 | 以 gitignore 样式的路径分隔列表,从索引中省略,附加在内置噪声规则之后 |
| `HATCHDOOR_EMBED_LAYERS` | `true` | 设置为 `false` 以保持降级层可进行关键词搜索,但跳过其向量嵌入 |
# sources/.hatchdoor-layer
来源
`sources/` 目录下的每个 Markdown 便笺都被分配到 `sources` 层。
它在浏览器树、浏览器搜索和其他默认表面结果中不可见,但仍可供明确选择该层的受信任 MCP 客户端访问。映射标记可以添加一个面向操作员的描述:
```yaml
name: 来源
description: 真实剪辑和参考资料。
```
嵌套标记会覆盖其父标记。在嵌套文件夹中使用 `name: default` 可使该子树返回到默认表面。命名标记不能位于保险库根目录下,而 `default`、`all`、`noise` 和 `none` 不能作为层名。
MCP 读取和搜索工具默认使用默认表面。传递 `layers: ["sources"]` 可选择一个命名层,传递 `layers: ["default", "sources"]` 可同时包含两者,或传递 `layers: ["all"]` 以包含所有层。`get_note` 可以根据 slug 或保险库相对路径获取已知便笺,而无需考虑其层。浏览器故意没有层选择器。
噪音模式会阻止文件进入索引。Hatchdoor 始终排除 `.obsidian/`、`.trash/`、`.hatchdoor-trash/`、`.DS_Store`、`*.tmp` 和 `*.sync-conflict-*`;`.hatchdoor-layer` 文件始终被读取,即使广泛的模式原本会匹配它们。使用逗号分隔的环境值添加部署特定的模式:
```env
HATCHDOOR_EXCLUDE=imports/,*.bak
```
模式使用 gitignore 语法,并在内置模式之后应用,因此如果需要,可以使用前导的 `!` 重新启用默认模式:
```env
HATCHDOOR_EXCLUDE=!*.sync-conflict-*
```
写入排除的目标会被拒绝,而不是创建一个索引会隐藏的文件。标记更改会触发完全重新索引;如果格式错误的标记导致启动索引失败,修正它将允许保险库观察器在无需重启服务器的情况下恢复。
要检查活动的规则、标记、层计数和冲突,请调用 `GET /api/diagnostics`(可选 `?path=sources/Clip.md`)或 MCP `layer_diagnostics` 工具。演示模式下禁用诊断,因为它们可能会透露降级路径。
### 便笺网址和链接
便笺 slugs 从 Markdown 文件名生成。重复的文件名会接收唯一的后缀,因此路由保持稳定。
支持的维基链接包括:
```text
[[便笺]]
[[文件夹/便笺]]
[[便笺|别名]]
```
Hatchdoor 将链接、反向链接、标题、标签、图数据和损坏链接状态解析到 SQLite 缓存中。
### 搜索
Hatchdoor 存储:
- 完整的 Markdown 内容
- 文件元数据
- 标签和标题
- 维基链接和反向链接
- FTS5 关键词搜索数据
- sqlite-vec 语义向量
递归保险库观察器在 Markdown 或资产更改后刷新缓存。浏览器客户端订阅 `/api/vault-events`,在广播刷新修订版后重新加载可见数据。
### 手动缓存重建
如果您想从头开始重建缓存:
```bash
rm ./data/cache/hatchdoor-cache.sqlite3
docker compose restart hatchdoor
```
调整路径如果您更改了 `HOST_CACHE_PATH`。
## MCP 代理访问
嵌入式 MCP 端点默认禁用。仅为受信任的客户端启用它。
MCP 需要 bearer token,即使在只读模式下,因为 `/mcp` bypass 了 web auth 层,可以公开整个保险库。
```env
HATCHDOOR_MCP_ENABLED=true
HATCHDOOR_MCP_BEARER_TOKEN=change-me
```
单独启用写入工具:
```env
HATCHDOOR_MCP_WRITE_ENABLED=true
```
使用 Streamable HTTP MCP 客户端注册端点:
```text
http://127.0.0.1:42824/mcp
```
发送:
```text
Authorization: Bearer <token>
```
### MCP 元数据查询
`search_notes` 接受可选的精确元数据过滤器,以及语义或关键词检索。过滤器支持所有精确标签匹配、层次标签前缀(`topic/selfhosting` 前缀也匹配 `topic/selfhosting/immich`)、保险库相对路径前缀、必需属性名称和类型属性相等。搜索结果始终包含规范化的标签和别名;使用 `include_properties` 返回代理所需的仅 frontmatter 字段。
在元数据完全定义请求且没有有意义的内容查询时使用 `query_notes`——例如,使用 `status: active` 列出每个标签为 `type/device` 的便笺。它需要至少一个过滤器,并返回便笺摘要而不是重复的块。`get_note` 返回单个便笺的完整规范化元数据对象。
日期值当前作为 frontmatter 值公开,并支持精确匹配。日期范围和更广泛的 Dataview 样式查询语言不是 2.3.0 元数据过滤器合同的一部分。
### 代理技能
Hatchdoor 配备了可用的 **代理技能**,用于通过 MCP 驱动保险库。当 Hatchdoor 播种启动保险库时,它会将模板写入 `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 同步。
### 附件上传
代理和 Web UI 直接上传附件——无需挂载共享临时文件夹。有两种路径可以解决大小/兼容性权衡:
- **`POST /api/attachment`**(multipart)——默认。Web UI 和任何可以发出 HTTP 请求的代理(例如 shell out 到 `curl`)使用。接受 web bearer token 或 MCP bearer token,因此 MCP 代理可以重用其现有凭证。由 `HATCHDOOR_MAX_ATTACHMENT_BYTES` 限制(默认 10 MiB)。
- **`import_attachment` MCP 工具**——备用方案,用于无法发出带外 HTTP 请求的 MCP 客户端。发送文件字节 base64 编码内联;适用于任何 MCP 客户端,但 base64 位于 JSON-RPC 消息中,当文件增长时变得不可靠。由 `HATCHDOOR_MCP_MAX_BASE64_BYTES` 限制(默认 5 MiB),按解码文件测量。
```env
HATCHDOOR_MCP_MAX_BASE64_BYTES=5242880
HATCHDOOR_MAX_ATTACHMENT_BYTES=10485760
```
代理可以调用 `get_attachment_import_config` 以发现两种方法、大小限制和要使用的方法。
## Git 同步
Git 同步是可选的,默认禁用。启用后,成功的 Hatchdoor 写入工具会提交并将保险库更改推送到配置的远程。
```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
```
要求:
- 保险库目录必须是 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 指向真实的保险库:
```bash
VAULT_PATH=/path/to/notes cargo run
```
对于前端开发模式:
```bash
# terminal 1
cargo run
# terminal 2
cd frontend
npm run dev
```
首次运行模型选择也适用于本地开发。Hatchdoor 默认情况下将模型存储在 `./models` 中,因此不需要模型预加载命令。
## 故障排除
### Hatchdoor 拒绝在 `0.0.0.0` 启动
设置 `HATCHDOOR_WEB_BEARER_TOKEN`,绑定到 `127.0.0.1`,或启用 `HATCHDOOR_DEMO_MODE=true` 以获取只读公共演示。
这是故意的。非环回绑定可以将您的保险库公开给网络,因此 Hatchdoor 需要 Web 身份验证,除非演示模式已禁用应用程序的写入表面。
### Docker 启动,但 UI 无法写入
检查容器运行时用户是否可写入挂载的保险库目录。浏览器写入支持依赖于文件系统权限。
### 缓存错误或过时数据
删除生成的 SQLite 缓存并重启:
```bash
rm ./data/cache/hatchdoor-cache.sqlite3
docker compose restart hatchdoor
```
### 应用程序启动时附带启动保险库
Hatchdoor 仅在 `VAULT_PATH` 包含没有 Markdown 文件时才会播种启动笔记。如果您期望现有的保险库,这通常意味着容器挂载了一个空目录,因此请仔细检查 `.env` 中的 `HOST_VAULT_PATH` 是否解析为实际的保险库,而不是拼写错误或过时的 Docker 卷遮蔽挂载。
有关 Hatchdoor 创建的笔记完整列表,请参见 [数据和安全模型](#数据和安全模型)。
### MCP 返回 `401` 或 `403`
检查:
- `HATCHDOOR_MCP_ENABLED=true`
- `HATCHDOOR_MCP_BEARER_TOKEN` 已设置
- 客户端发送 `Authorization: Bearer <token>`
- 浏览器源的 MCP 请求来自 `HATCHDOOR_MCP_ALLOWED_ORIGINS` 中的允许来源
### Git 同步未推送
检查:
- 保险库是 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` | 图数据 |
| `GET` | `/api/diagnostics` | 检查层和噪音排除诊断 |
| `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` | Streamable 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.4.0
docker push battermanz/hatchdoor:2.4.0
docker push battermanz/hatchdoor:latest
```
## 项目文档
- [文档索引](docs/README.md):架构、协作、路线图、研究、维护和历史记录。
- [产品路线图](docs/roadmap/product-roadmap.md):草案总体产品方向和工作流。
- [设计系统](docs/design/design-system.html):视觉令牌、组件模式、布局规则和交互状态。
- [语义搜索策略](docs/adr/semantic-search-strategy.md):关于仅限运行时路径的纯语义搜索的决策记录。
## 许可证
Hatchdoor 仅根据 GNU Affero 通用公共许可证 v3.0 许可。参见 [LICENSE](LICENSE)。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器