Files
mnote/design/07-ai/process/7-phase7-ai-kernel-projection-plan-v4.md
T

27 KiB
Raw Blame History

7 [process] mnote Kernel Phase 7 CLI-First 外置 Agent 统一执行面方案 v4

更新时间:2026-05-09

上位依据:

  • /mnt/Data1T/mnote/ARCHITECTURE.md
  • /mnt/Data1T/mnote/design/01-05-current-priority-overview.md
  • /mnt/Data1T/mnote/design/01-tree-first-graph-kernel/process/1-tree-first-graph-kernel-v1.md
  • /mnt/Data1T/mnote/design/03-rust-web/process/3-rust-web-long-term-architecture-v1.md
  • /mnt/Data1T/mnote/design/04-tree-domain/done/4-6-tree-command-protocol-cutover-stage2-v1.md
  • /mnt/Data1T/mnote/design/05-editor-mainline/process/5-5-page-aggregate-single-truth-alignment-v1.md
  • /mnt/Data1T/mnote/design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-v1.md
  • /mnt/Data1T/mnote/design/07-ai/done/7-1-phase7-document-ai-minimum-loop-checklist-v1.md
  • /mnt/Data1T/mnote/design/old/07-ai/process/7-phase7-ai-kernel-projection-plan-v2.md
  • /mnt/Data1T/mnote/design/old/07-ai/process/7-phase7-ai-kernel-projection-plan-v3.md

本稿与前稿的关系:

  • v2 的价值仍然成立:它记录了文档页 AI 最小闭环已经真实完成
  • v3 把 CLI 抬到了重要位置,但仍保留了“产品内 AI 主链”和“CLI 外置层”双中心
  • 本稿进一步收口,明确长期只保留一个执行方向:CLI-first

当前判断修正:

  • 文档页 AI 面板不再被视为独立 AI 编排主线
  • openai-agents-python 不再被视为长期默认主编排,而是一个可插拔外置 agent
  • Hermes、Codex、后续其他 agent,应统一通过 mnote-cli 接入
  • 3000 上的页面内 AI host 已属于 Rust mnote-web 主壳;/api/ai-agent/run 只保留 CLI host / adapter 口径
  • 文档页 AI 上下文读取已优先消费 Rust page aggregate snapshot,旧 TS builder / 旧 sidecar 只保留 fallback / 对照语义

1. 文档目的

这份稿只回答一个问题:

mnote 的长期 AI 执行面,到底要不要收口成一个唯一方向。

当前答案是:

要。长期只保留一个 AI 执行方向:Rust kernel + mnote-cli

这里的关键不是“要不要有 AI UI”,而是:

  • UI 可以存在
  • 外置 agent 可以很多
  • 但执行面只能有一个

一句话收口:

mnote 的长期主线不是“内置 AI + CLI 两套长期并存”,而是“CLI 作为唯一 agent 执行面,Web 面板只是其中一个客户端”。


2. 为什么要改成 CLI-first

当前如果继续保留两套长期方向:

  1. 产品内一套 AI 编排
  2. 外置 agent 一套 CLI / 脚本 / Hermes / Codex 编排

那么后面一定会出现这些重复维护成本:

  • 两套工具注册表
  • 两套上下文装配逻辑
  • 两套 session / trace / audit 语义
  • 两套能力开关和权限边界
  • 两套“哪些命令是真执行、哪些只是兼容层”的判断

这不是“体验和平台分层”,而是“长期双轨维护”。

如果改成 CLI-first

  • Web AI 面板调用 CLI
  • Hermes 调用 CLI
  • Codex 调用 CLI
  • 批处理脚本调用 CLI
  • 定时任务调用 CLI

那么系统只维护:

  1. 一个真执行方向:mnote-cli
  2. 多个调用方:UI / agent / script / job

这才是真正减少长期维护成本。


3. 当前完成情况如何解释

3.1 7-1 已完成,但不代表它必须成为长期方向

当前文档页 AI 最小闭环已经完成,这个事实不变:

  • Rust mnote.page_aggregate.v1 snapshot 优先的页面上下文读取
  • 标题改名与正文改写
  • openai-agents-python sidecar
  • Hermes fallback / 对照链

但这个完成状态只能说明:

我们已经验证过一条可工作的过渡主链。

不能自动推出:

这条链就应该变成长期唯一主线。

所以 v2 记录的工作不是白做,而是:

  • 它证明了产品内写链需求真实存在
  • 它帮助我们冻结了最小工具面和页面语义面
  • 它可以作为 CLI-first 迁移时的行为基线

3.2 mnote-cli 已经足够接近长期入口

当前 mnote-cli 已经不是空壳,已有:

  • page
  • block
  • mindmap
  • search
  • sidebar
  • editor
  • tool

同时还有这些关键参数:

  • --json
  • --execute
  • --session-id
  • --reason
  • --idempotency-key
  • --validate-only
  • --dry-run

这说明真正应该继续投入的,不是再扩一条新的 Web 内 AI 主编排,而是把 CLI 补成稳定统一入口。


4. 新的长期架构边界

4.1 Rust kernel / Rust runtime

负责:

  • 唯一事实源
  • query / command / projection
  • page / tree / graph / artifact 的正式语义
  • 审计、回放、恢复、trace 基线

不负责:

  • 直接承担 agent 编排
  • 直接承担产品聊天壳

4.2 mnote-cli

负责:

  • 唯一长期 agent 执行入口
  • 人类、脚本、外置 agent、Web 面板的统一命令面
  • 统一能力发现、统一参数面、统一输出结构

必须成为:

  • CLI for humans
  • CLI for agents
  • CLI for jobs
  • CLI for UI host

4.3 Web AI 面板

负责:

  • 当前页面里的交互壳
  • 流式展示
  • 输入与审核
  • 把页面上下文转成 CLI 可消费的标准输入
  • 接收 CLI 事件并映射到 UI

不负责:

  • 自己维护独立 agent 编排层
  • 自己维护独立工具注册表
  • 自己定义长期 AI 契约

4.4 外置 agent

包括但不限于:

  • Hermes
  • Codex
  • openai-agents-python
  • 后续任何别的 agent runtime

它们都负责:

  • 决策
  • 推理
  • 工具调用策略
  • 会话层 orchestration

但它们不应再直接拥有产品内部执行面。它们都应该统一调用 mnote-cli


5. openai-agents-python 的新定位

5.1 不再是默认主线

从本稿开始,openai-agents-python 不再被定义为:

  • mnote 的长期默认主编排
  • 产品内文档页 AI 的唯一推荐底座

5.2 改为可插拔外置 agent

它的新定位是:

一个可插拔外置 agent runtime。

也就是说,它和 Hermes、Codex 的区别不再是“谁是产品内主线”,而只是:

  • 不同的 agent 实现
  • 不同的模型接法
  • 不同的 orchestration 风格

是否继续保留它,取决于后续真实效果,而不是当前历史惯性。

5.3 可接受的长期状态

未来允许的状态有三种:

  1. openai-agents-python 继续保留,作为可选外置 agent
  2. openai-agents-python 仅保留在测试 / 回归 / 对照场景
  3. openai-agents-python 完全移除

这三种都不影响长期主架构,只要唯一执行面还是 mnote-cli


6. CLI-first 下的产品口径

6.1 UI 仍然可以有 AI 面板

CLI-first 不等于没有产品内 AI UI。

允许继续有:

  • 文档页 AI 面板
  • mindmap AI 面板
  • OnlyOffice AI 面板

但这些都只是:

CLI 的图形客户端。

并且当前这些客户端默认都挂在 3000 的 Rust mnote-web 主壳里,而不是重新长出第二套产品内执行面。

6.2 页面语义仍然保留

虽然主执行面转到 CLI,但下面这些产品语义仍要保留:

  • model_key
  • profile
  • tool registry
  • page aggregate
  • page.head.updateTitle
  • page.body.save
  • tree.*

区别只在于:

  • 这些不再由 Web 内独立 AI service 主导
  • 而是由 CLI 和 Rust runtime 共同定义

6.3 Web 不应再拥有第二套工具面

当前过渡工具面:

  • doc_get
  • doc_find
  • doc_insert_blocks
  • doc_replace_range
  • slash_run

如果继续保留,后续也应通过 CLI 暴露,而不是继续作为 Web 内 service 的私有 tool surface。


7. CLI 必须补齐的能力

CLI-first 成立的前提,不是“已有命令很多”,而是这些能力必须补齐。

7.1 能力发现

至少要能稳定输出:

  • 当前有哪些 command / query / job
  • 每个能力属于哪个 scope
  • 哪些可读,哪些可写
  • 哪些是 plan-only
  • 哪些是真执行

建议提供:

  • mnote-cli capabilities --json

7.2 标准上下文输入

CLI 需要能接住标准化页面上下文,而不是让每个 agent 自己拼:

  • documentId
  • blocks
  • pageOptions
  • editorRuntimePageOptions
  • subtree
  • outline
  • evidence

也就是说,页面上下文装配逻辑要从 Web 内 agent service 迁到 CLI 兼容输入协议。

7.3 标准事件输出

如果 Web 面板要流式显示,CLI 需要输出标准事件流,例如:

  • assistant_message
  • tool_call
  • tool_result
  • completion
  • error

否则 UI 最后还是会倒逼出第二套 Web 内编排逻辑。

7.4 标准 session / trace / audit

CLI 必须把这些变成一等能力:

  • session_id
  • trace_id
  • request_id
  • actor_id
  • actor_type
  • reason
  • idempotency_key

7.5 权限与 scope

CLI 要能明确限制:

  • 当前只能改当前页
  • 当前允许跨页还是不允许
  • 当前允许树命令还是只允许页面命令
  • 当前是只读、写入还是后台 job

8. 顺序执行 checklist

本节是后续实施时的主 checklist。执行时从上到下推进,完成一项后把对应 - [ ] 改成 - [x],并在该项下补充实际命令输出摘要或截图路径。

8.1 冻结 CLI 基座

  • 确认 mnote-cli 顶层命令存在。

    • 命令:
      cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --help
      
    • 通过标准:输出包含 pageblockmindmapsearchsidebareditortool
  • 确认 agent 必需的全局参数存在。

    • 命令:
      cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --help
      
    • 通过标准:输出包含 --json--execute--session-id--reason--idempotency-key--validate-only--dry-run
  • 确认 mnote-cli 当前单测全通过。

    • 命令:
      cargo test --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli
      
    • 通过标准:所有 mnote-cli 测试通过;当前基线应覆盖 CLI JSON contract、tool registry、page/save/sidebar 等最小面。

8.2 冻结页面命令面

  • 验证页面读取命令。

    • 命令:
      cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --json page get --page-id page_demo --workspace-id ws_demo
      
    • 通过标准:输出包含 domain: pageaction: getcontext.requestIdcontext.traceId,并且 operation.transport.functionName 指向页面查询。
  • 验证页面标题更新命令。

    • 命令:
      cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --json page title --page-id page_demo --workspace-id ws_demo --title "新标题"
      
    • 通过标准:输出包含 domain: pageaction: titleoperation.kind: command,并且写入仍通过 Rust runtime / transport 计划表达。
  • 验证页面正文保存命令。

    • 命令:
      cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --json page save --page-id page_demo --workspace-id ws_demo --content-json '[{"id":"block_1"}]'
      
    • 通过标准:输出包含 domain: pageaction: saveoperation.kind: command,并且能看到正文写回 payload。

8.3 冻结块命令面

  • 验证块插入命令。

    • 命令:
      cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --json block insert --page-id page_demo --workspace-id ws_demo --block-type paragraph --content "hello"
      
    • 通过标准:输出包含 domain: blockaction: insertoperation.kind: commandoperation.name: insert_block
  • 验证块 patch 命令。

    • 命令:
      cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --json block patch --page-id page_demo --workspace-id ws_demo --block-id block_demo --snapshot-json '{"id":"block_demo","type":"paragraph","text":"updated"}'
      
    • 通过标准:输出包含 domain: blockaction: patchoperation.kind: commandoperation.name: blocks.patch
  • 第 1 步:固定块写链仍然存在的入口证据。

    • 结果:/api/ai-agent/run 已不再直接恢复 slash_run / doc_insert_blocks / doc_replace_rangeDocumentAiAgentPanel.runtime.tsx 也已不再声明 Web 内独立 agent owner。
    • 验证命令:
      rg -n "doc_insert_blocks|doc_replace_range|slash_run|startHermesRun|startDocumentAiOrchestratorRun|runCodexBridge" \
        /mnt/Data1T/mnote/wolai-frontend/src/app/api/ai-agent/run/route.ts \
        /mnt/Data1T/mnote/wolai-frontend/src/components/editor/DocumentAiAgentPanel.runtime.tsx
      
  • 第 2 步:把块写链收口为 mnote-cli host / adapter。

    • 结果:/api/ai-agent/run 已收口为薄 host route,块写链不再由 Web 私有 service 直接拥有。
    • 依赖检查:DocumentAiAgentPanel.runtime.tsx/api/ai-agent/run/route.ts 的 contract 说明已同步改成 mnote-cli
  • 第 3 步:补块写链回归测试。

    • 结果:pnpm vitest run src/components/editor/DocumentAiAgentPanel.runtime.test.tsxpnpm vitest run src/app/api/ai-agent/run/route.test.ts 通过。
    • 验证命令:
      pnpm vitest run /mnt/Data1T/mnote/wolai-frontend/src/components/editor/DocumentAiAgentPanel.runtime.test.tsx
      pnpm vitest run /mnt/Data1T/mnote/wolai-frontend/src/app/api/ai-agent/run/route.test.ts
      
    • 通过标准:测试明确约束块写链不再暴露 Web 私有 tool surface,并且 route 只保留 CLI host / adapter 语义。

8.4 冻结搜索与侧栏投影

  • 验证文档搜索命令。

    • 命令:
      cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --json search documents --workspace-id ws_demo --query "Hermes"
      
    • 通过标准:输出包含 domain: searchaction: documents,并且查询计划可由 Web host 消费。
  • 验证块搜索命令。

    • 命令:
      cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --json search blocks --page-id page_demo --query "Hermes"
      
    • 通过标准:输出包含 domain: searchaction: blocksoperation.name: search_blocks
  • 验证侧栏数据集命令。

    • 命令:
      cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --json sidebar dataset --workspace-id ws_demo
      
    • 通过标准:输出包含 domain: sidebaraction: datasetoperation.name: sidebar.dataset.list

8.5 冻结 tool runtime 与安全模式

  • 验证 tool run 的只读 explain-plan。

    • 命令:
      cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --json --validate-only --dry-run --session-id ai-checklist-smoke --reason phase7-cli-first --idempotency-key phase7-cli-first-001 tool run --tool-name doc_get --kind query --mode explain-plan --args-json '{"pageId":"page_demo"}'
      
    • 通过标准:输出包含 domain: toolaction: runcontext.sessionId: ai-checklist-smokecontext.idempotencyKey: phase7-cli-first-001context.validateOnly: truecontext.dryRun: true
  • 验证 tool registry 会拒绝未知工具。

    • 命令:
      cargo test --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli tool_run_rejects_unknown_tool
      
    • 通过标准:测试通过,未知 tool 不会绕过 registry 进入执行链。
  • 确认 --reason 进入后续 audit / trace 输出规划。

    • 当前状态:CLI 参数面已接住 --reason,并已在标准 JSON 输出的 context.reason 中展开。
    • 通过标准:cargo test --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli output_context_keeps_reason_for_audit_trace 通过,断言 reason 出现在标准 audit / trace 输出上下文里。

8.6 将 Web AI 面板降为 CLI host

  • 检查 Rust Web checklist 的 Phase 5 口径。

    • 文件:/mnt/Data1T/mnote/design/03-rust-web/process/3-1-rust-web-long-term-checklist-v2.md
    • 通过标准:AI 面板只能写成 mnote-cli host/client 收口,不得写成 Hermes 或 openai-agents-python 长期主编排。
    • 已核对:该文件明确写入“长期执行面应收口到 mnote-cliWeb 只作为 CLI host / clientopenai-agents-python / Hermes / Codex 只作为可插拔外置 agent”。
  • 检查 legacy Next retirement gate 的 AI route 口径。

    • 文件:/mnt/Data1T/mnote/design/03-rust-web/done/3-11-rust-web-legacy-next-retirement-gates-v1.md
    • 通过标准:/api/ai-agent/run 只能写成 CLI host / adapter 兼容层,结构化写入必须经 Rust runtime。
    • 已核对:该文件明确写入 /api/ai-agent/run 长期应降为 mnote-cli host / adapter,结构化写入必须经 Rust runtime,外置 agent 不得拥有第二执行面。
  • 检查 Wolai-aline E27 的 AI 编辑口径。

    • 文件:/mnt/Data1T/mnote/design/05-editor-mainline/process/5-9-wolai-aline-continuous-checklist-v1.md
    • 通过标准:E27 只能把 openai-agents-python sidecar / Hermes fallback 当作过渡基线,不得写成长期主线。
    • 已核对:E27 明确写入 /api/ai-agent/run 后续应收口为 mnote-cli 唯一长期 agent 执行面上的 host / adapterHermesCodexopenai-agents-python 仅为可插拔外置 agent;当前 sidecar / fallback 只保留为过渡行为基线。

8.7 外置 agent 接入顺序

  • 第 1 步:冻结 Codex 接入方式。

    • 结果:/api/ai-agent/run 已不再按 provider=codex 直入独立 bridge,统一走 mnote-cli host。
    • 验证命令:
      rg -n "provider === \"codex\"|runCodexBridge" /mnt/Data1T/mnote/wolai-frontend/src/app/api/ai-agent/run/route.ts
      
  • 第 2 步:冻结 Hermes 接入方式。

    • 结果:/api/ai-agent/run 已不再直接调用 startHermesRun / streamHermesRunEventsHermes 不再是长期主链入口。
    • 验证命令:
      rg -n "startHermesRun|streamHermesRunEvents|/api/hermes/bridge" /mnt/Data1T/mnote/wolai-frontend/src/app/api/ai-agent/run/route.ts
      
  • 第 3 步:冻结 openai-agents-python 接入方式。

    • 结果:DocumentAiAgentPanel.runtime.tsx 已不再声明 bridgeOwner: "openai-agents-python"provider=online 也不再直连 orchestrator。
    • 验证命令:
      rg -n "bridgeOwner: \"openai-agents-python\"|startDocumentAiOrchestratorRun|/api/v1/ai-agent/document/run" /mnt/Data1T/mnote/wolai-frontend/src/components/editor/DocumentAiAgentPanel.runtime.tsx /mnt/Data1T/mnote/wolai-frontend/src/app/api/ai-agent/run/route.ts
      
  • 第 4 步:统一复核外置 agent 只剩 CLI host / adapter 口径。

    • 结果:已通过全局复核,/api/ai-agent/run 与面板 contract 都只保留 mnote-cli host / adapter 口径。
    • 验证命令:
      rg -n "provider === \"codex\"|runCodexBridge|startHermesRun|streamHermesRunEvents|bridgeOwner: \"openai-agents-python\"|startDocumentAiOrchestratorRun|/api/v1/ai-agent/document/run" \
        /mnt/Data1T/mnote/wolai-frontend/src/app/api/ai-agent/run/route.ts \
        /mnt/Data1T/mnote/wolai-frontend/src/components/editor/DocumentAiAgentPanel.runtime.tsx
      

8.8 完成判定

  • mnote-cli 的最小命令面在仓库内可复跑。

    • 已验证:cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --helpcargo test --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli 可复跑。
  • --json--execute--validate-only--dry-run 的输出语义稳定。

    • 已验证:--help 暴露这些全局参数;tool run --validate-only --dry-run --json 输出包含 context.validateOnly: truecontext.dryRun: truecontext.reasoncontext.sessionIdcontext.idempotencyKey
  • page / block / search / sidebar / tool 都能用 CLI 直接验证。

    • 已验证:8.2 到 8.5 已分别覆盖 page get/title/saveblock insert/patchsearch documents/blockssidebar datasettool run
  • 第 1 步:确认 Web AI 面板的 contract 已收口为 mnote-cli host / client。

    • 结果:面板 contract 已改为 bridgeOwner: "mnote-cli"runtimeRole: "mnote_cli_host_client"
    • 验证命令:
      rg -n "bridgeOwner: \"openai-agents-python\"|startDocumentAiOrchestratorRun|startHermesRun|runCodexBridge" /mnt/Data1T/mnote/wolai-frontend/src/components/editor/DocumentAiAgentPanel.runtime.tsx /mnt/Data1T/mnote/wolai-frontend/src/app/api/ai-agent/run/route.ts
      
  • 第 2 步:确认三类外置 agent 都只作为可插拔 runtime。

    • 结果:route.ts 已收口为统一 host route,不再按 provider 分叉到三套执行实现。
    • 验证命令:
      rg -n "provider === \"codex\"|runCodexBridge|startHermesRun|startDocumentAiOrchestratorRun|bridgeOwner: \"openai-agents-python\"" /mnt/Data1T/mnote/wolai-frontend/src/app/api/ai-agent/run/route.ts /mnt/Data1T/mnote/wolai-frontend/src/components/editor/DocumentAiAgentPanel.runtime.tsx
      
  • 第 3 步:补完成判定的最终回归。

    • 结果:cargo test --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-clipnpm vitest run src/components/editor/DocumentAiAgentPanel.runtime.test.tsxpnpm vitest run src/app/api/ai-agent/run/route.test.ts 均通过。
    • 验证命令:
      cargo test --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli
      pnpm vitest run /mnt/Data1T/mnote/wolai-frontend/src/components/editor/DocumentAiAgentPanel.runtime.test.tsx
      pnpm vitest run /mnt/Data1T/mnote/wolai-frontend/src/app/api/ai-agent/run/route.test.ts
      
  • 结构化写入仍然只能回到 Rust runtime / Rust kernel。

    • 已核对:本稿 4.1、6.2、6.3 明确 Rust kernel / Rust runtime 负责事实源、query / command / projection 与结构化写入语义;3-11 与 Wolai-aline E27 均要求结构化写入经 Rust runtime 或 Rust tool / page.body.save

8.9 当前测试账号写入验收

  • 确认当前测试账号默认允许 CLI 新建与编辑页面。

    • 命令:
      cd /mnt/Data1T/mnote/wolai-frontend && pnpm vitest run src/lib/server/mnote-cli-agent-host.test.ts
      
    • 通过标准:mnote-cli host 默认下发 MNOTE_CLI_ALLOW_CREATE_PAGE=1MNOTE_CLI_ALLOW_EDIT=1,并把当前 Web 用户身份透传给 CLI 子进程。
  • 确认当前测试账号的真实 workspace。

    • 当前测试账号:
      • userId: a4b72c17-49e3-46d3-8456-24a0a7044d64
      • email: dev@mnote.local
      • name: 开发用户
    • 当前真实 workspace
      • workspaceId: ws_req_1778035004501_15
      • workspaceName: 开发用户 的空间
      • 首个页面:tree_1778036320856_1 / 新页面
    • 通过标准:/api/sidebar?workspaceId=ws_req_1778035004501_15 返回的 documents 至少包含 tree_1778036320856_1
  • 确认旧的 CLI 直连 Convex identity 不能作为长期用户写入面。

    • 事实:曾经写入 tree_1777430834634_3 / anonymous 的空间 的页面不会出现在当前测试账号的 ws_req_1778035004501_15
    • 结论:CLI 不能长期依赖伪造 DEV_USER_ID 直连 Convex 来代表用户写入;需要由 Web host / mnote-web 持有当前会话、当前 workspace 与 capability 后再执行写入。
  • 确认 CLI host 会把当前页面 workspaceId 传入 CLI 输入。

    • 命令:
      cd /mnt/Data1T/mnote/wolai-frontend && pnpm vitest run src/lib/server/mnote-cli-agent-host.test.ts
      
    • 通过标准:--args-json 包含 workspaceId: "ws_req_1778035004501_15",避免 agent 在缺省 workspace 或错误 workspace 下创建页面。
  • 用当前浏览器会话创建当前账号可见页面。

    • 执行动作:在已登录测试账号的浏览器会话中调用 /api/tree/commands 创建:
      • CLI 可见测试 A 1778057564
      • CLI 可见测试 B 1778057564
    • 通过标准:创建响应的 result.workspaceId 必须是 ws_req_1778035004501_15
    • 当前验证结果:
      • tree_1778048047020_3 / CLI 可见测试 A 1778057564
      • tree_1778048047047_4 / CLI 可见测试 B 1778057564
  • 用当前浏览器会话读取 sidebar 确认可见。

    • 命令等价动作:
      await fetch('/api/sidebar?workspaceId=ws_req_1778035004501_15', { credentials: 'include' })
      
    • 通过标准:返回的 documentskernelSidebarProjection.itemskernelSidebarTree 都包含 CLI 可见测试 A 1778057564CLI 可见测试 B 1778057564
    • 当前验证结果:已在浏览器会话 API 返回中看到上述两个页面;同一返回还显示早先创建的 cli_visible_ws_req_a_17780471cli_visible_ws_req_b_17780471
  • 后续权限收口:补“禁止/允许 CLI 编辑、允许 CLI 新建页面”的 capability 开关。

    • 目标:默认测试账号允许 CLI 新建与编辑;后续真实用户可在设置中关闭关键页面的 CLI 编辑或新建权限。
    • 通过标准:CLI 写操作必须能读到当前用户、当前 workspace、当前页面 capability;未授权时返回明确拒绝,不得 fallback 到 anonymous / dev identity 写入。
  • 确认 Web host 会把当前会话用户透传给 mnote-cli 作为默认执行身份。

    • 命令:
      cd /mnt/Data1T/mnote/wolai-frontend && pnpm vitest run src/lib/server/mnote-cli-agent-host.test.ts src/app/api/ai-agent/run/route.test.ts
      
    • 通过标准:spawn("cargo", ...) 的环境变量包含 DEV_USER_IDDEV_USER_EMAILDEV_USER_NAME,并默认下发 MNOTE_CLI_ALLOW_CREATE_PAGE=1MNOTE_CLI_ALLOW_EDIT=1

9. 迁移策略

阶段 0:口径冻结

先冻结新的长期判断:

  • CLI 是唯一长期执行面
  • Web 面板只是 CLI 客户端
  • openai-agents-python 是可插拔外置 agent
  • Hermes / Codex / 后续 agent 都统一走 CLI

阶段 1CLI 能力补齐

优先补:

  • capability manifest
  • 标准 JSON 输出
  • 事件流输出
  • 标准上下文输入
  • 标准 trace / session 参数

阶段 2Web 面板降为 CLI host

把当前文档页 AI 面板从:

  • “调用内置 sidecar 主编排”

改成:

  • “调用 CLI host / CLI adapter”

阶段 3:外置 agent 接入统一化

统一支持:

  • Hermes -> mnote-cli
  • Codex -> mnote-cli
  • openai-agents-python -> mnote-cli

阶段 4:裁剪过渡层

当 CLI-first 成熟后,逐步评估:

  • 是否保留 openai-agents-python
  • 是否保留当前 Web 内 sidecar
  • 是否完全移除旧过渡桥接

10. 非目标

本稿不做:

  • 再造一套新的 agent 平台
  • 让 Web 直接失去 AI UI
  • 把所有 UX 都退回终端
  • 让 Hermes 或 openai-agents-python 重新变成产品内部唯一中心

11. 完成判定

满足下面几项时,才算 CLI-first 真正成立:

  • mnote-cli 是唯一长期 agent 执行入口
  • Web AI 面板只是 CLI host,不再持有独立主编排
  • Hermes / Codex / openai-agents-python 都通过 CLI 接入
  • Rust kernel 仍然是唯一事实源
  • 是否保留 openai-agents-python 不影响整体架构

一句话收口:

mnote 的长期 AI 方向应当收口成“Rust kernel 负责真相,mnote-cli 负责唯一执行面,外置 agent 全部可插拔,Web 只做交互壳”。