38 KiB
状态补充(2026-07-03):本稿冻结为 opencode runtime / 官方 opencode WebUI iframe fallback 参考;Page AI 产品主线为 OpenHub / native agent + LightRAG + Turso/libSQL。官方 iframe 仅在 OpenHub AI 面板不可用、调试 opencode 原生行为或做回归对照时启用,不再作为默认产品路径。此前指向
7-68-openhub-weknora-mnote-deep-fusion-v1.md的 WeKnora 默认 provider 口径已标记 stale。
7-65 [process] Page AI opencode WebUI embed v1
创建时间:2026-06-23
当前状态:
FROZEN / 官方 opencode iframe fallback,OpenHub + LightRAG + MNote 深度融合为主线Owner:07-ai / Page AI / opencode WebUI embed
替代方案:
design/old/07-ai/process/7-62-recycle-page-ai-board-first-full-rewrite-v1.mddesign/old/07-ai/process/7-63-recycle-page-ai-board-first-productization-v1.mddesign/old/07-ai/process/7-64-recycle-codexmobile-embed-page-ai-v1.md上位依据:
design/07-ai/process/7-18-local-first-agent-file-editing-control-plane-v1.mddesign/07-ai/done/7-38-page-ai-sidebar-runtime-owner-split-v1.mddesign/07-ai/done/7-40-page-ai-context-envelope-and-run-receipt-v1.mddesign/07-ai/done/7-50-lightrag-knowledge-rag-provider-v1.md
1. 核心结论
废弃 MNote Page AI 自研 provider 接入与 Board-first 产品壳后,本稿曾把 opencode 官方 runtime + 官方 WebUI 作为主线;当前该方案已降级为 fallback,默认产品主线为 OpenHub / native agent + LightRAG + Turso/libSQL。
fallback MNote Page AI = MNote 宿主壳 + opencode 官方 WebUI iframe + MNote 打开/刷新/上下文集成
主线 Page AI = MNote 宿主壳 + OpenHub AI 面板 + OpenHub FastAPI/Redis/opencode client + LightRAG
opencode = agent runtime / HTTP server / OpenAPI / SSE / SDK / opencodego provider
MNote 不再直接维护 Reasonix / ZCode / Hermes / Chat-only / Board worker 作为页面 AI provider。它们可以继续存在于历史、调试或外部工作流边界,但不进入 Page AI 主路径。官方 opencode WebUI iframe 也不再进入默认产品主路径,只作为 fallback。
选择 opencode 的原因:
opencode web官方提供本地 WebUI,不需要 MNote 自研完整聊天前端。opencode serve官方提供 headless HTTP server 和 OpenAPI,适合 MNote 做轻量 adapter。@opencode-ai/sdk覆盖 session、message、diff、permission、event,足够承接上下文注入与回写 receipt。- opencode 原生支持 SSE、权限审批、文件 diff、MCP、ACP、session export/import。
- 本机已有
opencode和 opencodego 订阅链路,provider/runtime/UI 属于同一生态,少一层兼容债。
2. 明确废弃
2.1 Page AI 主路径不再接入
- Reasonix native session / Reasonix desktop bridge。
- ZCode worker / Board worker selector。
- Hermes profile / Hermes Web control surface。
- Chat-only remote conversation。
- Agent Board run/workflow 作为默认 Page AI 后端。
- CodexMobile iframe 作为默认 Page AI 后端。
这些能力不删除历史代码,不立刻清理工具层,只从 Page AI 新主路径退出。
2.2 仍可保留的边界
mnote.doc.*、mnote.block.*等工具可继续作为 fallback/compat 边界;默认知识库工具走 LightRAG + provider-neutralmnote.knowledge_rag.*facade。- Agent Board 仍可作为外部 workflow/QA/review 系统,不再作为 Page AI 默认聊天后端。
- CodexMobile 可保留为备选 spike 或体验对照,不作为当前实现目标。
3. 新系统边界
3.1 MNote 只做四件事
- 上下文:当前页、选区、页面标题、真实
.md路径、workspaceId、allowed roots、LightRAG 引用;WeKnora 只作为历史设计、参考实现或备用 provider 边界。 - 授权:把 MNote local-first 文件权限转换为 opencode permission / external_directory / working directory。
- 嵌入:第一版通过 MNote 同源受登录态保护反代嵌入 opencode 官方 WebUI;
npm run dev:hot默认拉起opencode serve --hostname=127.0.0.1 --port 4096。 - 回执:监听 opencode event/diff,触发 MNote watcher 刷新,记录 Page AI session binding。
3.2 opencode 负责完整 agent runtime
- 聊天 UI。
- 流式事件。
- session 管理与恢复。
- provider/model 调用。
- tool call 展示。
- permission ask/allow/deny。
- 文件读写、patch、diff。
- MCP / ACP / agent 配置。
3.3 集成形态:不是新的 Leptos island
当前 MNote 文档编辑器已经是 leptos_tiptap_island,但 Page AI 不应该再做一个重前端 island。Page AI 更像 VSCode 里的 Cline:
VSCode workbench host + Cline webview/extension
MNote web shell host + opencode WebUI iframe/bridge
因此第一版形态是 mnote-web sidebar host runtime:
- 继续使用
rust/crates/mnote-web/browser/sidebar-page-ai-runtime.js作为宿主入口,但把它瘦身成 opencode host。 - iframe 内尽量保留 opencode 官方 UI,包括消息、tool、permission、diff/session 页面。
- iframe 外只放 MNote 必要宿主控件:当前页 context bar、打开变更、刷新当前页、授权状态、运行状态。
- 不新建 Leptos island,不引入 React/Vue 到 MNote 主壳,不重写 opencode 消息 UI。
如果后续必须深度定制 opencode UI,也优先 fork opencode WebUI 的少量页面,而不是在 MNote 里复刻一套聊天前端。
4. 集成拓扑
MNote Rust SSR :3000
└─ Page AI sidebar
├─ MNote host chrome
│ [当前页] [选区] [可写目录] [知识库引用]
│ [打开变更] [刷新当前页] [在主编辑区打开]
└─ iframe http://127.0.0.1:4096/<project>/session
↓ first MVP direct localhost iframe
opencode web :4096
├─ 官方 WebUI
├─ 官方 HTTP server / OpenAPI
├─ SSE /event
├─ session/message/diff/permission APIs
└─ opencodego / configured providers
第一版优先 iframe 官方 WebUI,不 fork、不精简、不重写样式。实测 opencode WebUI 使用根路径 /assets、/session、/global/health 等资源/API,子路径 /page-ai/opencode/ iframe 会产生 root path 错位;因此 MVP 采用 MNote 同源根路径反代 /<base64-project>/session/<sessionId>,让 iframe 内 location.pathname 与 opencode 官方 WebUI 预期保持一致,同时通过 MNote 登录态保护反代入口。/api/page-ai/opencode/* 负责 session binding、context 注入、status、diff/receipt adapter。只有 iframe/adapter 实测无法满足产品嵌入时,才考虑 fork WebUI。
4.1 MNote host chrome
Page AI 抽屉由 MNote 控制尺寸、开关、上下文和跨应用动作,opencode 只负责 AI 交互主体。
宿主控件最小集:
- 当前页 pill:标题、相对路径、读写状态。
- 选区 pill:有选区才展示,点击可重新注入上下文。
- 变更 pill:来自 opencode diff/event,点击用 MNote 打开对应文件。
- 刷新按钮:调用
window.__mnoteDocumentPaneRuntime.refreshPrimaryDocument()。 - 打开按钮:调用
window.__mnoteDocumentPaneRuntime.openResourceInActiveTab()。
这些控件由 MNote 渲染,避免修改 opencode 官方页面结构。
4.2 MNote 打开 opencode 变更
opencode WebUI 里的 diff / changed file 默认按 opencode 自己的 UI 打开。MNote 需要额外提供宿主打开能力:
opencode diff/event
→ MNote adapter 归一化 changed files
→ Page AI host chrome 显示 changed file chips
→ 用户点击 chip
→ window.__mnoteDocumentPaneRuntime.openResourceInActiveTab({ path })
第一版不强行改 opencode diff 内部点击行为;先在 iframe 外给 MNote-native changed file chips。这样即使 opencode DOM 改版,MNote 打开变更仍可用。
4.3 可选 bridge:只做宿主动作,不接管 UI
如果需要让 opencode 官方 UI 内部的文件链接也能用 MNote 打开,可在同源反代 HTML 中注入一个很小的 bridge 脚本:
opencode iframe click(file/diff link)
→ postMessage({ type: 'mnote:open-file', path })
→ parent MNote host 调用 openResourceInActiveTab
bridge 只允许三类消息:
mnote:open-filemnote:refresh-filemnote:session-ready
不通过 bridge 解析模型事件、不重绘消息、不替换 permission UI。DOM 选择器脆弱时立即退回 host chrome chips。
5. 最小实现
Phase A:runtime spike
- 运行
opencode --version、opencode web --help、opencode serve --help;当前版本已升级到1.17.9。 - 卸载 oh-my-openagent / oh-my-opencode 默认插件:
opencode.json中plugin已为空,oh-my-openagent.jsonc已移除并备份。 - 启动/复用
opencode serve --hostname=127.0.0.1 --port=4096,/global/health返回 healthy。 - 验证 WebUI 可打开、可进入
/mnt/Data1T/mnoteproject session、可真实回复。 - 验证 opencodego/OmniRoute 模型可用:iframe 内真实回复
OPENCODE_MNOTE_IFRAME_OK_*。 - 验证当前工作目录指向 MNote workspace:
/session返回directory=/mnt/Data1T/mnote。 - 验证编辑一个
.md文件后,/session/:id/diff能返回文件 diff:opencode-smoke-test.md返回modifieddiff。 /eventSSE 只做了接口可达性探索,尚未接入持续事件消费。
Phase B:MNote iframe embed
- Rust 新增
/page-ai/opencode/{*path}反向代理到127.0.0.1:4096,并新增/api/page-ai/opencode/status、/api/page-ai/opencode/diff。 - 只允许已登录 MNote session 访问反代/API;未登录请求返回
401 page_ai_opencode_unauthorized。 - Page AI sidebar 精简为:MNote host chrome + iframe + basic status。
- 尽量不改 opencode WebUI,保留官方页面布局、消息样式、tool/diff/permission UI。
- iframe 容器与 host chrome 由
sidebar-page-ai-runtime.js+page-ai.css承载,不新增 Page AI Leptos island。 - WebUI 默认 iframe 使用 MNote 同源
/<base64-project>/session反代;避免局域网浏览器访问自身127.0.0.1:4096,同时保留 opencode 官方 URL 形态。
Phase B2:MNote-native changed files
- 建立 opencode sessionId ↔ MNote host 状态的持久 binding:
/api/page-ai/opencode/session创建/复用 session,并落 SQLite/control-plane,按用户/session/workspace 区分。 - 通过
/api/page-ai/opencode/events代理 opencode/event,收到 session/message/diff/file 事件后触发有界 refresh。 - 通过
/session/:id/diff生成 changed file chips。 - chip 点击走
window.__mnoteDocumentPaneRuntime.openResourceInActiveTab()。 - 当前页刷新按钮已走
refreshPrimaryDocument({ reason: 'page-ai-opencode-host' });changed files 命中当前页时由 event/diff refresh 链路自动触发刷新。
Phase C:context 注入
优先不修改 opencode WebUI,通过官方 API/SDK 注入上下文:
MNote open Page AI
→ create or resume opencode session
→ session.prompt(noReply=true, parts=[MNote context envelope])
→ iframe 打开对应 session
上下文 envelope 内容:
- 当前页标题。
- 当前页真实 Markdown 路径。
- selection 文本。
- allowed roots 与读写权限。
- LightRAG 引用摘要;WeKnora 引用只作为备用 provider / 历史参考。
- 当前任务约束:优先编辑 primaryTarget,禁止越权修改。
当前状态:done for MVP。host chrome 已展示当前页、真实 Markdown path(可定位时)、selection、allowed roots/writable 状态;打开 Page AI 时会调用 /api/page-ai/opencode/session,用 noReply=true 向 opencode session 注入 MNote context envelope,并把 iframe 打到绑定 session URL。2026-06-24 已按 opencode-chat 参考改回官方 WebUI iframe 主路径,MNote-native timeline 仅保留为 debug/receipt 边界。
Phase D:writeback / receipt
- 监听 opencode
/event或 SDKevent.subscribe():当前通过/api/page-ai/opencode/events代理/event,EventSource 收到相关事件后触发有界 refresh。 - [partial] prompt / event 后通过绑定 session 的
/session/:id/diff刷新 changed files;仍需继续核对 opencode 各类 file/diff event payload。 - changed files 命中当前页时调用
refreshPrimaryDocument({ reason: 'page-ai-opencode-event' });手动刷新按钮保留。 - 保存 MNote pageId ↔ opencode sessionId binding:当前已落 SQLite/control-plane,按用户/session/workspace 区分;浏览器刷新后可恢复同一 binding。
- Page AI context bar 显示最近一次 changed files / runtime / error 摘要。
Phase E:可选 WebUI bridge
- 只有 host chrome chips 体验不足时,才在反代层注入
mnote-opencode-bridge.js。 - bridge 只把 opencode UI 内部文件点击转成
postMessage。 - bridge 不解析/修改 opencode 消息流、tool UI、permission UI。
- selector 失效时不阻塞主流程,回退 host chrome chips。
6. 安全与权限
- opencode 只监听
127.0.0.1;MVP iframe 直连本机地址,同源反代/API 仍必须受 MNote 登录态保护。 - 生产/长期运行必须设置
OPENCODE_SERVER_PASSWORD,或改为完整同源反代 + MNote 反代层隔离。 - opencode working directory 优先指向当前 workspace root。
- MNote allowed roots 映射到 opencode permission:
- 当前 workspace root:允许读,写按用户授权。
- 当前页文件:允许读写。
- workspace 外路径:默认 deny,必要时显式
external_directory。
- 不使用
--dangerously-skip-permissions作为默认路径。
7. 验收标准
7.1 UI
- Page AI 面板内显示 opencode 官方 WebUI。
- 官方消息流、tool 卡片、permission 交互、diff/session UI 尽量原样保留。
- MNote 只在 iframe 外展示 host chrome,不重做 opencode UI。
- opencode 产生的 changed files 可以用 MNote 主编辑区或资源 tab 打开。
7.2 Runtime
- 可创建/恢复 opencode session。
- 可用 opencodego 模型完成真实回复。
- 流式回复浏览器可见。
- 权限审批走 opencode 原生机制。
- 文件修改后 MNote 当前页面能刷新。
7.3 代码收敛
sidebar-page-ai-runtime.js不再承载 Reasonix/ZCode/Hermes/Board provider 状态机。- 不新增 MNote 自研聊天 message store。
- 不 fork opencode WebUI,除非 spike 证明 iframe 方案不可用。
- 不新增 Page AI Leptos island;Page AI 是 mnote-web sidebar host runtime。
8. 与旧方案对比
| 方案 | 优点 | 主要问题 | 当前结论 |
|---|---|---|---|
| Board-first | 可接多 worker/workflow | MNote 仍要维护产品壳和 Board adapter,聊天体验不成熟 | 废弃为主路径 |
| CodexMobile embed | Codex 体验强,贴近现有 Codex 体系 | 需要 fork/精简/修 bug,维护派生产品 | 备胎/对照 |
| opencode WebUI embed | 官方 runtime + 官方 WebUI + 官方 API,维护成本低 | opencode 能力可能不如 Codex 先进,嵌入细节需实测 | 当前主路径 |
9. 非目标
- 不重写 opencode WebUI。
- 不把 opencode WebUI 拆成 MNote 原生组件。
- 不同时接入 Reasonix/ZCode/Hermes/CodexMobile 多后端。
- 不把 Agent Board 控制台嵌入 Page AI。
- 不在第一版实现完整 MNote SSO 到 opencode;先由 MNote 反代保护。
10. 退出条件
只有出现以下任一情况,才重新启用 CodexMobile 或自研 UI 方案:
- opencode WebUI 无法稳定 iframe/反代嵌入。
- opencode session 无法通过 API 定位并打开指定 session。
- opencode 无法可靠编辑 MNote workspace 文件。
- opencode permission/diff/event 无法满足 MNote 最小安全闭环。
- opencodego/provider 链路在真实使用中明显不稳定且短期不可修。
9. 2026-06-24 iframe 主路径验证记录
opencode --version:1.17.9。opencode serve --hostname=127.0.0.1 --port 4096 --print-logs:真实可启动;官方 WebUI URLhttp://127.0.0.1:4096/L21udC9EYXRhMVQvbW5vdGU/session可显示Build anything。npm run dev:hot:真实拉起mnote-web :3000和opencode :4096。- 浏览器 smoke:登录
mnote.e2e@example.com后打开 Page AI,iframe URL 为http://127.0.0.1:3000/L21udC9EYXRhMVQvbW5vdGU/session,显示官方 opencode WebUI;截图/tmp/mnote-page-ai-opencode-iframe.png。 - [partial] 发送真实消息:官方 WebUI 可输入并进入
Thinking/Stop运行态;截图/tmp/mnote-page-ai-opencode-send.png。本轮未等待到最终回复,不能声明 provider 回复完成。 - binding 持久化 smoke:浏览器 reload 后仍恢复同一 session
ses_106555512ffe5wDz9eMlP4v2i2。 - 静态检查:
node --check rust/crates/mnote-web/browser/sidebar-page-ai-runtime.js。 - Rust 检查:
cd rust && cargo check -p mnote-web。
剩余 gap:
- 在同源反代层补最小
postMessagebridge:open-file / refresh-file / insert-text,不接管消息流。 - [partial] 更完整核对 opencode
/event的 file/diff payload:已递归解析常见 changed/diff/file payload 并由 event 触发有界 refresh;仍需真实编辑文件后补最终证据。 - 若要局域网访问,继续确认所有 opencode WebUI root-level API 路由都已被 MNote 登录态反代覆盖,避免直接暴露 4096。
10. 2026-06-25 bridge / receipt 补充记录
- HTML 反代注入极小 bridge:只处理
insert-text / open-file / refresh-file / session-ready,不接管 opencode 消息流、tool UI、permission UI。 - MNote host chrome 新增“插入当前页上下文”按钮,通过
postMessage把当前页标题、路径、选区、allowed roots 插入 opencode 官方输入框。 - 浏览器 smoke:
/tmp/mnote-page-ai-opencode-bridge-final.png,验证 iframe 内window.__mnoteOpencodeBridgeInstalled === true,点击 host 按钮后官方输入框出现MNote 当前页上下文标题:主页。 - postMessage smoke:模拟 iframe 发
open-file / refresh-file,确认 MNote host 调用openResourceInActiveTab()与refreshPrimaryDocument();输出见tmp/mnote-opencode-postmessage-smoke.cjs运行结果。 - event receipt 强化:
pageAiOpencodeNormalizeChangedFiles()改为递归收集changedFiles / files / diff / changes / edited / created / deleted / data / properties,事件到达时先更新 chips,再做有界 projection refresh。 - 静态检查:
node --check rust/crates/mnote-web/browser/sidebar-page-ai-runtime.js。 - Rust 检查:
cd rust && cargo check -p mnote-web。
剩余 gap:
- 让 opencode 真实修改一个测试 Markdown 文件,等待
/event+/session/:id/diff产出 changed file chips,再截图验证 chip 点击打开 MNote 主编辑区。 - 若 opencode 官方 WebUI 后续 CSP 变化,需要把 inline bridge 改成 nonce/hash 或外部小脚本。
11. 2026-06-25 opencode 用户隔离与工作目录结论
11.1 当前结论
- Page AI 工作目录应简化为“当前用户打开的根文件夹”:MNote 当前只能打开一个大的本地根目录,
rootUri对应的真实目录就是 opencodedirectory/ project directory。 - 切换根文件夹应视为新的 opencode session 边界:同一用户同一根目录内可按页面恢复 binding;根目录变化时默认新建 session,不把旧 session 带到新根目录。
- MNote 自身 binding 已按
user_id + workspace_id + mnote_session_id + provider隔离;mnote_session_id内包含 workspace/page/directory,因此同一用户跨根目录不会复用同一 binding。 - [partial] opencode 自身默认实例没有 MNote 用户概念;如果所有 MNote 用户共用一个
opencode serve,opencode 的 session、permission、credential、account、skill、MCP、snapshot、tool-output 会共用同一套本机状态。
11.2 opencode 1.17.9 真实机制证据
本机 spike 使用临时环境启动:
HOME=/tmp/.../home \
XDG_CONFIG_HOME=/tmp/.../config \
XDG_DATA_HOME=/tmp/.../data \
XDG_CACHE_HOME=/tmp/.../cache \
XDG_STATE_HOME=/tmp/.../state \
opencode serve --port 4197 --hostname 127.0.0.1 --print-logs
观察结果:
- 配置读取路径变为
$XDG_CONFIG_HOME/opencode/{config.json,opencode.json,opencode.jsonc}。 - 持久数据写入
$XDG_DATA_HOME/opencode/opencode.db。 - 日志写入
$XDG_DATA_HOME/opencode/log/opencode.log。 - 锁写入
$XDG_STATE_HOME/opencode/locks/*。 - 当前全局实例的默认持久库是
/home/lix/.local/share/opencode/opencode.db。 opencode.db内包含session、message、part、permission、credential、account、account_state、project、workspace、event等表;这些表没有 MNote 用户维度。permission只按project_id + action + resource唯一;共用实例会导致不同 MNote 用户在同一 project/directory 下共享 opencode 权限记忆。session表包含directory/project_id/workspace_id/metadata,但不包含 MNoteuser_id;共用实例不能作为安全隔离边界。- opencode 会从当前用户 HOME/配置路径加载 skill/MCP;未隔离时可看到
/home/lix/.claude、/home/lix/.agents、/home/lix/.config/opencode/skill等重复 skill 警告。
11.3 推荐隔离方案
第一版不要试图在单个 opencode server 内实现多用户隔离;改为 MNote 用户/根目录维度的 opencode runtime profile:
MNote user + workspace/rootUri
-> runtime profile id
-> dedicated XDG_CONFIG_HOME / XDG_DATA_HOME / XDG_CACHE_HOME / XDG_STATE_HOME
-> dedicated opencode serve process on 127.0.0.1:dynamic_port
-> MNote 登录态反代 /page-ai/opencode/...
目录建议:
$MNOTE_DATA/users/<user-id>/opencode/<workspace-hash>/config/opencode/opencode.json
$MNOTE_DATA/users/<user-id>/opencode/<workspace-hash>/data/opencode/opencode.db
$MNOTE_DATA/users/<user-id>/opencode/<workspace-hash>/cache/opencode/
$MNOTE_DATA/users/<user-id>/opencode/<workspace-hash>/state/opencode/
配置策略:
- provider/API key 可由 MNote 管理后写入每个 profile 的最小
opencode.json,或在本机单用户 dev 模式从/home/lix/.config/opencode/opencode.json复制 provider/model 白名单。 - skill/MCP 默认不继承宿主 HOME 的全部内容;只显式安装 MNote 允许的 skill/MCP,例如
codegraph、mempalace、后续 MNote MCP。 - opencode 原生 permission 继续保留,但存储在该 profile 的独立
opencode.db中。 - MNote 的 allowed roots 仍作为上下文与反代边界;opencode 的工作目录固定为当前打开根目录。
11.4 session 策略
- 同一
user_id + workspace_id/rootUri + pageAbsolutePath:优先恢复 MNote control-plane binding 指向的 opencode session。 rootUri变化:默认新建 session;旧 binding 保留但不跨根目录复用。pageAbsolutePath变化:默认新建或按页面 binding 恢复,不把旧页面上下文继续注入到新页面。- opencode 原生 session 恢复只作为 profile 内部能力;MNote 是否恢复以 control-plane binding 为准。
- 跨浏览器恢复依赖 SQLite control-plane binding + per-user opencode data profile,不依赖
sessionStorage。
11.5 后续实现项
- 新增 opencode runtime profile manager:按 MNote user/rootUri 分配 XDG 目录、端口、启动/健康检查、生命周期。
dev:hot继续可一键启动,但默认只启动 dev 单用户 profile;多用户 profile 由后端按需拉起。- 反代不再只读
MNOTE_OPENCODE_BASE_URL全局值,需按当前登录用户和 rootUri 解析到对应 profile base URL。 - session binding metadata 写入
runtimeProfileId、rootUri、projectDirectory、opencodeDataDir,方便审计和恢复。 - 增加最小测试:两个不同 MNote 用户同一 Markdown 根目录下创建 session,不共享 opencode
opencode.db、permission、session list。
11.6 官方/社区多用户实现调研补充
本轮先核验豆包给出的项目名,再补充搜索到的真实社区线索。结论:没有发现可直接嵌入 MNote 的官方/社区“单 opencode 进程多 MNote 用户强隔离”实现;官方当前也把多用户 Web/serve 部署视为待增强能力。
豆包列表验真:
| 项目 | 验真结果 | 对 MNote 的价值 |
|---|---|---|
anomalyco/opencode-orchestrator |
未找到公开仓库;真实相近项目是 agnusdei1207/opencode-orchestrator |
后者是 opencode 多 agent 编排插件,不是多用户 runtime 隔离层 |
pRizz/opencode-cloud / gitea.com/pRizz/opencode-cloud |
真实存在 | Docker/container 级隔离参考;安全强但本地 MNote 开销偏大 |
oc-ext/ocx |
未找到公开仓库 | 暂不可作为依据 |
daytonaio/daytona-opencode-plugin |
未找到公开仓库 | 暂不可作为依据 |
anomalyco/openwork |
未找到公开仓库 | 暂不可作为依据 |
lucentia/opencode-svip-proxy |
未找到公开仓库 | 暂不可作为依据 |
kwickramasekara/opencode-chat |
真实存在 | VSCode WebView 嵌入参考:启动/复用 opencode serve、固定端口保留 localStorage、WebView proxy、剪贴板/键盘 bridge;不是多用户隔离实现 |
额外发现:
| 项目/线索 | 结论 |
|---|---|
官方 anomalyco/opencode issue #20067 |
open:请求 opencode web 支持 multi-user auth 与 per-user provider credentials;issue 描述确认共享 Web 实例会共享身份、session、provider credentials |
官方 anomalyco/opencode issue #5784 |
closed:请求多租户 serve 下 MCP auth/config;说明多租户 MCP/资源隔离是社区真实痛点,但不是已可用的完整 MNote 用户隔离方案 |
官方 SECURITY.md |
明确 opencode 不提供安全 sandbox;server mode 只支持 OPENCODE_SERVER_PASSWORD Basic Auth;需要真隔离时建议 Docker/VM |
millerjes37/opencode-multiplexer |
真实存在,是 opencode fork 的 multi-client server 支持;文档承认“知道 sessionID 即可交互”的 session hijacking 风险,session ownership 仍是 future enhancement;不适合作 MNote 多用户隔离底座 |
joeyism/opencode-multiplexer |
真实存在,是多 session/多项目终端 dashboard,不是 Web 多用户隔离 |
对当前方案的修正:
- 不应引入豆包描述的“单进程多租户 opencode”作为近期主路径;目前没有可靠公开实现,官方也还在 issue 层面。
- 也不应一开始上 Docker/container;它解决安全隔离但会显著增加本地笔记软件的启动、资源和运维成本。
- 近期最稳妥路线是 单 opencode 进程 + 单 MNote 当前用户/当前根目录 profile,先满足本机单用户和局域网同一登录用户;等 MNote 真正进入多用户同时在线场景,再升级为按需 profile manager。
- 若要减少端口/生命周期复杂度,可先采用
opencode-chat的轻量做法:固定一个 dev/local 端口、优先复用已存活 server、MNote 反代统一入口;不要提前实现多实例调度。 - 多用户隔离仍必须作为设计约束保留:不能把共享 opencode
opencode.db声称为安全隔离,只能标为单用户/dev 模式。
更新后的分阶段建议:
- Phase MVP-local:一个 MNote 登录用户 + 一个当前根目录 + 一个 opencode server;工作目录固定为
rootUri;MNote control-plane 做跨浏览器 session binding。 - Phase shared-device:为每个 MNote 用户准备独立 XDG profile,但不常驻多进程;登录/打开 Page AI 时按需启动,空闲回收。
- Phase SaaS/团队:再评估
opencode-cloud/Docker 或等待官方 multi-user auth/per-user credentials 落地;不要自己 fork 官方 opencode 做单进程多租户。
11.7 OpenHub 对照结论
xcl1989/OpenHub 是目前找到的最接近“opencode 多用户平台”的社区实现,README 明确主张:一个 opencode serve (:4096),后端按用户 workspace 通过 ?directory= 路由到不同目录,并在应用 SQLite 中维护 users、sessions、messages、permissions、skills、tools 等业务层权限。
可复用点:
- 单 opencode server + per-user workspace:后端调用
/session、/session/{id}/prompt_async、/global/event时统一带directory=<user workspace>。 - 应用层 session ownership:OpenHub 自己用 SQLite 记录
conversation_sessions/ messages / user_id,不把 opencode 原生 session 列表直接暴露给所有用户。 - 应用层权限面板:模型权限、工具权限、skill 权限都在业务 DB 中维护,再同步/注入到用户 workspace。
- per-user
.opencode目录:README 架构图显示每个 workspace 下有独立.opencode/skills、.opencode/tools。 - 单进程运维简单:固定
OPENCODE_BASE_URL=http://127.0.0.1:4096,Basic Auth 保护后端到 opencode 的内部访问。
关键风险:
- OpenHub 不是 opencode 原生多租户;它仍依赖一个全局 opencode server 和全局 opencode 数据库/credential/account 状态。
- 隔离主要靠
directory与 OpenHub 后端不暴露跨用户 session;如果绕过 OpenHub 直接访问 opencode,或知道别人的 session id,仍要依赖外层鉴权/反代拦截。 - provider credentials 是 opencode server 全局配置;OpenHub 的用户模型/工具权限是应用层控制,不等于 opencode 内核 per-user credentials。
- 它自研了聊天前端、消息库、知识/记忆/任务系统;这不符合 MNote 当前“尽量保留 opencode 官方 WebUI,不复刻消息 UI”的边界。
对 MNote 的启发:
- OpenHub 证明“单 opencode serve +
?directory=按用户工作区隔离”在产品上可跑,比一开始做多进程 profile manager 更轻。 - MNote MVP 可以采用 OpenHub 的轻量隔离思路:固定一个本机 opencode server,所有请求由 MNote 登录态反代,MNote 后端只允许当前用户的
rootUri作为directory,并用 control-plane binding 限制 session ownership。 - 但必须把这种模式标为 应用层隔离 / 单机可信 opencode 后端,不能标为强安全多租户。强隔离仍需后续 XDG profile 或 Docker。
更新后的推荐:
- 立即采用 OpenHub-lite:单
opencode serve、固定端口、MNote 反代、directory=rootUri、control-plane session ownership。 - 不复刻 OpenHub UI:仍保留 opencode 官方 WebUI iframe;MNote 只做 host chrome、context、open/refresh、changed files。
- 补安全闸:所有
/api/page-ai/opencode/*和 iframe 反代必须校验当前登录用户、rootUri、session binding;不允许前端任意传 directory 打开非当前 root。 - 后续 shared-device 再升级:当确实有多 MNote 用户同时使用同一机器时,再做 per-user XDG profile manager。
11.8 OpenHub 融合可行性评估
用户新判断:OpenHub 的前端、消息库、权限、记忆、文件、任务等功能与 MNote Page AI 长期目标高度重合,应评估是否直接融合,减少 MNote 自研量。
结论:可融合,但不建议整套 OpenHub 作为 MNote 新后端;推荐抽取 OpenHub Page-AI 子系统,形成 MNote 内的 OpenHub-lite。
可最大化复用的部分:
- React/AntD 聊天前端:
SmartQueryPage.jsx、ChatInput、AssistantMessage、ToolCall、QuestionForm、HistoryDrawer、DiffViewer、FileManager、GitTimeMachine等,可作为 Page AI 的 micro frontend,而不是继续维护当前简陋 host UI。 - 消息库模型:
conversation_sessions、conversation_messages、图片、turn、opencode message id、归档、retry、last-turn delete 等,适合迁移到 MNote control-plane,替代sessionStorage和当前临时 binding。 - opencode 单进程接入模式:后端按用户 workspace/rootUri 调
/session、/session/{id}/prompt_async、/global/event并带directory=,适合 MNote 当前“一个打开根目录”的简化模型。 - 应用层权限面板:模型权限、工具权限、skill 权限、usage 统计可以映射到 MNote 用户体系;短期先只做 Page AI 所需的模型/工具/skill 白名单。
- 任务/团队/记忆模块:Smart Entity、Team、Memory、Scheduler 与 MNote 长期 agent 目标相关,但第一阶段只作为后续模块,不应阻塞 Page AI MVP。
不建议直接搬入的部分:
- OpenHub 自带登录、用户管理、admin 页,与 MNote control-plane auth 重叠;应替换成 MNote 登录态。
- OpenHub FastAPI 后端与 MNote Rust SSR/control-plane 双后端并存会增加部署复杂度;此判断已被
7-68覆盖,当前第一阶段保留 OpenHub FastAPI/Redis/opencode client。 - OpenHub 自研知识库/记忆/任务会与 MNote WeKnora、workspace、tree/file resource、control-plane 产生事实源冲突;旧 LightRAG 仅作为 legacy/fallback 参考。
- OpenHub 不是 opencode 内核级强隔离,仍需 MNote 反代和 session ownership 限制。
推荐融合路线:
-
Phase 1:iframe micro frontend spike
- 直接运行 OpenHub 前端的 Page-AI/Chat 子集,嵌入 MNote sidebar。
- 后端 API 不直接用 OpenHub FastAPI,而是由 MNote 提供兼容
/api/query/stream、/api/sessions/*、/api/files/*的最小 Rust adapter。 - 目标是快速验证 UI/消息体验是否明显优于 opencode 官方 iframe。
-
Phase 2:消息库迁移
- 在 MNote control-plane 增加 OpenHub-like
page_ai_sessions/page_ai_messages/page_ai_message_parts/page_ai_turns。 - 将 opencode session id、message id、tool calls、diff、reasoning、attachments、rootUri、pageAbsolutePath 统一持久化。
- 替代当前临时 Page AI binding;支持跨浏览器、跨会话恢复。
- 在 MNote control-plane 增加 OpenHub-like
-
Phase 3:UI 组件裁剪融合
- 从 OpenHub 前端抽出 Chat shell、消息列表、工具调用、历史抽屉、Diff/File/GitTimeMachine 组件。
- 去掉 Login/Admin/Knowledge/SmartEntity/Team 等非 Page AI 首屏模块。
- 适配 MNote host chrome、当前页 context、changed file chip、MNote open/refresh。
-
Phase 4:高级能力选择性引入
- FileManager 映射 MNote resource/file tree。
- GitTimeMachine 映射 MNote changed files / snapshot / restore 设计。
- Memory/Skill/Tool permission 映射 MNote 用户权限和未来 MNote MCP。
- Smart Entity/Team 作为 Page AI 后续 agent team,不进入当前 MVP。
技术判断:
- 如果目标是“尽快有成熟 Page AI UI”,OpenHub 前端比 opencode 官方 iframe 更适合深度定制,因为它已经是普通 React/AntD 应用,消息、工具、历史、文件、diff 都在前端组件内。
- 如果目标是“最少维护债”,opencode 官方 iframe 仍最省事,但 MNote 与页面/文件/权限/历史的融合会受 iframe 限制。
- 当前更适合改为 OpenHub UI + MNote Rust adapter + opencode runtime:UI 和消息体验复用 OpenHub,用户/文件/权限/工作区真相仍归 MNote,agent runtime 仍归 opencode。
新的建议:
- 把
7-65当前 iframe 方案降级为 runtime spike 与 fallback。 - 新增或接续设计
7-67-openhub-page-ai-fusion-v1,目标是用 OpenHub Chat 子系统替代当前 Page AI UI。 - 第一阶段只做 Chat/Session/Message/Diff/File open 五件事,不引入 OpenHub 登录/admin/知识库/team。
11.9 OpenHub 知识库实现与 WeKnora 对照
2026-07-03 口径回正:Page AI 要做深度融合;当前默认知识库主线为 LightRAG + OpenHub tool facade,WeKnora 仅保留为历史设计、参考实现或备用 provider。因此本节只作为当时 OpenHub 自带知识库能力对照记录。
源码核验结论:OpenHub 自带知识库是轻量 SQLite 文本知识库,不是完整 RAG/知识库底座;适合复用 UI、API 形状和 prompt 注入链路,不建议替代 WeKnora。
OpenHub 知识库真实实现:
- 数据表只有
knowledge_bases与knowledge_sources:字段包括scope=enterprise/user、owner_id、title、source_type、content、tags、统计字段;没有 chunk 表、embedding 表、向量库、图谱或 citation 表。 - 上传解析支持
.md/.txt/.pdf/.docx/.xlsx/.csv:PDF 走 PyMuPDF 文本抽取,DOCX 走 python-docx 段落抽取,表格转文本行;没有 OCR、版面恢复、图片解析或复杂文档结构保真。 chunker.py存在 Markdown/文本/表格切块逻辑,但当前知识库主链没有把 chunk 持久化到 DB,检索与注入仍围绕整份knowledge_sources.content。- 检索分两层:DB 层用
LIKE关键字筛出候选;服务层再对候选全文做 CJK/英文 token 的 BM25 + TF-IDF 重排;没有 embedding、semantic search、rerank model、hybrid vector search。 - 注入方式是 prompt stuffing:小型个人知识库全量或近似全量注入,大型个人知识库取 2 条结果,企业知识库最多取 1 条结果,每条截取相关片段,总上下文默认限制约 1200 字符。
- opencode 集成点是在发送用户问题前构造
<context>...</context>,并提示模型如果上下文不足就调用knowledge_knowledge_search工具继续查。 - 前端
KnowledgeManager.jsx和 admin 企业知识库 UI 可直接参考:列表、搜索、上传、添加、编辑、删除、统计、企业只读提示这些产品能力与 MNote 需要高度重合。
与 WeKnora 的关系:
- WeKnora 应继续作为 MNote 长期知识库底座候选:负责文档解析、索引、检索、召回、引用、权限过滤与跨文档问答。
- OpenHub 知识库不应替代 WeKnora;它更像“用户短记忆/轻量知识片段/企业公告文本”的 fallback。
- 当前融合方式是 OpenHub AI 面板 + MNote Rust 知识库 adapter + LightRAG provider:OpenHub 负责 Page AI 对话与工具事件承载,真正的 ingestion/search/citation 由 MNote 通过 provider-neutral facade 调 LightRAG。
- OpenHub 的
knowledge_sourcesschema 可以作为 MNote control-plane 的 source registry 参考,但需要增加workspace_id/root_uri/resource_id/source_uri/provider_doc_id/index_status/permission_scope/citation_locator等 MNote 字段。 - OpenHub 的 prompt 注入链路可以短期复用为 Page AI context block,但 WeKnora 命中结果必须带 citation/open-reference 映射,不能只塞纯文本。
对 7-67 深度融合设计的影响:
- Page AI 主 UI 继续选 OpenHub Chat 子系统,而不是官方 opencode iframe。
- Knowledge 模块第一阶段只迁移 UI 与 API contract,不迁移其 SQLite 文本检索为长期底座。
- MNote Rust adapter 提供 OpenHub-compatible
/api/knowledge/*,内部走 WeKnora 或本地 fallback。 - 保留 OpenHub 轻量知识库作为“未配置 LightRAG 时的 local fallback / 用户手工短知识”,但不能称为默认知识库主线。
- 新设计稿应明确:
OpenHub UI负责交互,MNote control-plane负责用户与权限,WeKnora负责知识库索引与检索,opencode负责 agent 执行。