Loomkeep
by scupro
README.md
# Loomkeep
**讓人類與 AI Agent 協同組織、檢索與維護長期知識。**
Loomkeep 是一個可自部署的版本化個人知識庫,同時提供 Web 控制台和 MCP 介面,供人類與 AI Agent 共享和維護知識。文件、階段總結、研究筆記與結構化任務均儲存在自己的 Cloudflare 帳戶中,支援跨會話查詢和持續協作。
## 功能
- **知識導航**:透過目錄概覽、Markdown 大綱、路徑及檢索定位資料;跨會話恢復只是其中一種使用方式。
- **通用內容與任務**:Markdown 文件可附加標籤(如 `checkpoint` 表示階段快照);結構化 TODO 保留獨立的狀態與優先順序。
- **多種檢索方式**:支援關鍵詞、語義和混合搜尋,以及標籤、關聯記錄和指定目錄範圍內的查詢。
- **版本歷史**:保留記錄修改歷史,支援差異檢視、衝突保護和恢復舊版本。
- **協作與審計**:追蹤 Agent 的修改,避免不同用戶端無意覆蓋彼此的工作。
- **備份與恢復**:提供知識庫快照匯出和恢復前檢查,便於遷移與備份。
- **安全連線**:使用 OAuth 授權 MCP 用戶端,可分別授予讀取與寫入權限。
**Web 管理控制台**:可透過瀏覽器登入、瀏覽目錄、編輯 Markdown 與結構化任務、檢視版本歷史和活動、搜尋知識庫及管理會話。提供亮色/暗色模式、行動裝置佈局,以及 Tiptap 視覺化編輯與 Markdown 原始碼編輯。與 MCP 用戶端共享相同的內容和版本歷史。前端以 Astryx Neutral 為設計系統,基礎控制元件優先使用 Astryx;Markdown 編輯器與知識庫業務檢視按需組合實現。
## 部署到 Cloudflare
需要 Cloudflare 帳戶,以及 **Workers、D1、KV、Vectorize 和 Workers AI**。本地構建需要 Node.js 24 與 pnpm 11。
### 1. 建立資源
安裝依賴並登入 Cloudflare:
```bash
pnpm install
pnpm exec wrangler login
```
在自己的帳戶中建立資源:
```bash
pnpm exec wrangler kv namespace create OAUTH_KV
pnpm exec wrangler d1 create loomkeep
pnpm exec wrangler vectorize create loomkeep --dimensions=1024 --metric=cosine
```
儲存命令返回的 **KV Namespace ID** 和 **D1 Database ID**。如果資源已存在,直接使用現有資源,不要重複建立。專案會透過 Wrangler 配置繫結 Workers AI。
> **Vectorize 沒有面板入口。** Cloudflare Dashboard 目前只能檢視索引,建立索引必須透過 Wrangler 或 REST API。這一步只做一次,之後的部署不需要再碰 CLI。若手邊沒有 CLI,可在面板建立一支具備 `Vectorize:Edit` 權限的 API Token,再呼叫 REST API:
>
> ```bash
> curl -X POST "https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/vectorize/v2/indexes" \
> -H "Authorization: Bearer <API_TOKEN>" \
> -H "Content-Type: application/json" \
> -d '{"name":"loomkeep","config":{"dimensions":1024,"metric":"cosine"}}'
> ```
>
> 維度必須是 1024(對應 `@cf/baai/bge-m3`),且建立後不可變更。
### 2. 配置自動部署
在 Cloudflare Dashboard 中將 GitHub 倉庫連線至 **Workers Builds**,使用以下設定:
| 設定 | 值 |
| --- | --- |
| Worker 名稱 | `loomkeep` |
| 根目錄 | `/` |
| 生產分支 | `main` |
| Build command | `pnpm check && pnpm test` |
| Deploy command | `pnpm deploy` |
在 **Build Variables and Secrets** 中填寫資源標識:
| 變數 | 值 |
| --- | --- |
| `LOOMKEEP_KV_ID` | 第一步得到的 KV Namespace ID |
| `LOOMKEEP_D1_ID` | 第一步得到的 D1 Database ID |
這兩個值是 Cloudflare 資源 ID,**不是登入金鑰**。
Worker 建立後,在其 **Settings → Variables and Secrets** 中新增執行時 **Secret**:
- `MCP_AUTH_SECRET`:用於批准 MCP 用戶端授權,也用於 Web 管理 API 登入。請使用高強度隨機值,妥善保管。
不要把金鑰放進 GitHub 倉庫、Build Variables 或公開配置檔案。連線倉庫後,對 `main` 分支的提交會觸發構建和部署。若需要自定義域名,可在 Worker 中配置 Custom Domain,並按需將 `MCP_BASE_URL` 設為公共站點的 Origin(不包含 `/mcp`)。
#### 面板部署的實際限制
Workers Builds 自動建立的 API Token 只有 `Workers Scripts`、`Workers KV Storage`、`Workers R2 Storage` 的編輯權限,**不含 D1**。而 `pnpm deploy` 會執行 `wrangler d1 migrations apply --remote`,因此用預設 Token 會在遷移這一步失敗。兩種可行的做法:
1. **改用自訂 API Token**(建議):面板建立一支含 `Workers Scripts:Edit`、`D1:Edit` 的 Token,在 Builds 設定中選用它。若部署階段回報找不到 Vectorize 索引,再補 `Vectorize:Edit`。
2. **把遷移移出面板**:Deploy command 改成 `npx wrangler deploy --config wrangler.deploy.jsonc`,遷移在本機執行一次:
```bash
LOOMKEEP_KV_ID=<KV_ID> LOOMKEEP_D1_ID=<D1_ID> node scripts/predeploy-check.mjs
pnpm exec wrangler d1 migrations apply DB --remote --config wrangler.deploy.jsonc
```
換句話說:**完全只用面板、一次 CLI 都不碰是做不到的**——Vectorize 索引的建立與 D1 遷移都缺少面板入口。面板可以負責「建置+部署」,但前置資源與資料庫結構仍需要一次 CLI 或 REST API 呼叫。
不想手動處理這些的話,直接用下一節的 GitHub Actions 流程:它會自動建立索引、套用遷移並部署,且不必在面板另設 Token。
### 3. CI 與自動部署(GitHub Actions)
倉庫內建兩個 workflow,**任何憑證都不會進入版本控制**——全部透過 `${{ secrets.* }}` 注入:
| Workflow | 觸發 | 內容 |
| --- | --- | --- |
| `ci.yml` | PR、手動 | `pnpm install --frozen-lockfile` → `check` → `test` → `build:web` |
| `deploy.yml` | push `main`、手動 | `gate`(檢查憑證)→ `verify`(同 CI)→ `deploy`(建索引、遷移、部署、健康檢查) |
`gate` 只是確認憑證是否齊全。**未設定時只留一則 notice 並跳過部署,不會讓 `main` 每次提交都失敗**;`verify` 仍會照常跑完,main 的型別與測試防線不受影響。
在 **Settings → Secrets and variables → Actions** 設定:
| 名稱 | 類型 | 用途 |
| --- | --- | --- |
| `CLOUDFLARE_API_TOKEN` | Secret | 部署用 API Token |
| `CLOUDFLARE_ACCOUNT_ID` | Secret 或 Variable | 帳號 ID |
| `LOOMKEEP_KV_ID` | Secret 或 Variable | 第一步的 KV Namespace ID |
| `LOOMKEEP_D1_ID` | Secret 或 Variable | 第一步的 D1 Database ID |
| `MCP_AUTH_SECRET` | Secret(選用) | 若設定,部署後自動同步為 Worker secret |
| `CLOUDFLARE_WORKERS_SUBDOMAIN` | Secret 或 Variable(選用) | 用於部署後 `/health` 檢查;未設定則跳過 |
API Token 需要的權限:`Workers Scripts:Edit`、`Workers KV Storage:Edit`、`D1:Edit`、`Vectorize:Edit`(workflow 會用 REST API 自動建立向量索引,因為面板沒有建立入口)。KV 權限是給部署時驗證綁定用;Token 請只授予這個帳號,不要使用 Global API Key。
不要用 `wrangler login` 產生的憑證,也不要把 token 寫進 `wrangler.jsonc`、`.dev.vars` 或任何被提交的檔案。`wrangler.deploy.jsonc` 由 `scripts/predeploy-check.mjs` 在 CI 執行時即時產生,已在 `.gitignore` 內。
### 4. 連線 MCP 用戶端
部署完成後,在支援 Streamable HTTP MCP 和 OAuth 的用戶端中新增:
```text
https://<你的 Worker 域名>/mcp
```
首次連線會開啟 OAuth 授權頁面。使用上面設定的 `MCP_AUTH_SECRET` 授權用戶端,並選擇所需的讀取或寫入權限。
連線後,你可以直接告訴 Agent:
> 先瀏覽 Loomkeep 中的相關目錄,利用知識概覽和文件大綱定位已有資料,按需閱讀和總結;在我授權維護時,再更新相關文件或任務。
Loomkeep 不會自動儲存每條對話;需要由用戶端根據你的要求呼叫工具進行讀取或儲存。
## 本地開發
```bash
pnpm install
cp .dev.vars.example .dev.vars
# 在 .dev.vars 中填寫本地測試用 MCP_AUTH_SECRET
pnpm db:local
pnpm dev
```
本地 MCP 地址為 `http://localhost:8787/mcp`。如需開發網頁,在另一個終端執行 `pnpm dev:web`,開啟 `http://localhost:5173`;它會將 API 請求代理到本地 Worker。執行 `pnpm check`、`pnpm test` 和 `pnpm build:web` 驗證更改。
如果要從本地手動部署,請先透過環境變數配置 `LOOMKEEP_KV_ID` 和 `LOOMKEEP_D1_ID`,再執行 `pnpm deploy`。部署指令碼會執行所需的 D1 遷移。不要提交 `.dev.vars` 或本地生成的部署配置。
## 資料與安全
- Loomkeep 預設面向單一所有者;獲得授權的用戶端可按權限存取同一個知識庫。
- **單一金鑰是刻意設計。** 本專案不做多用戶、角色或兩步驟驗證:`MCP_AUTH_SECRET` 同時是 MCP OAuth 授權密碼、Web 控制台登入密碼,也是瀏覽器工作階段 Token 的簽章金鑰。一個人使用的知識庫不需要帳號體系,代價是金鑰等同全庫;請使用 32 字元以上的隨機值,並在懷疑外洩時更換(更換會登出所有裝置與已授權的用戶端)。
- **已知取捨**:Web 登入有 Cap.js 工作量證明與每 IP 限流(15 次/15 分鐘);但 OAuth 同意頁(`/authorize`)目前只做常數時間比對,沒有速率限制。若部署在公開網路上,請依賴高熵金鑰,或在 Worker 前面加上 Cloudflare Access。
- **圖片來源白名單**:預覽與編輯器只允許 `shared/image-policy.ts` 清單內的網域載入圖片。`_headers` 的 CSP `img-src` 由同一份清單在建置時產生,因此清單外的圖片連瀏覽器都不會發出請求(不是只靠前端隱藏)。新增網域後必須重新建置並部署。
- 修改會保留版本歷史;如果記錄已被其他用戶端更新,舊版本上的編輯會被拒絕。
- 語義搜尋索引非同步更新,因此剛儲存的記錄可能需要稍後才能透過語義搜尋找到;精確查詢可使用關鍵詞或路徑。
- 備份可能包含全部歷史內容和敏感資料,請安全儲存。快照恢復預設先檢查資料;大型資料庫仍建議配合 Cloudflare D1 的備份機制。
- Web 控制台入口為 `https://<你的 Worker 域名>/login`,使用與 MCP OAuth 授權相同的 `MCP_AUTH_SECRET` 登入。先完成 Cap.js 驗證,成功後使用可撤銷的瀏覽器會話,後續操作無需重複輸入金鑰。
## License
MIT.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues