# 12-2 [process] 本地 vaultd + Agent Token 读密路径(不依赖 mnote-web)v1 > 创建时间:2026-07-23 > 状态:`PROCESS`(**P0 L-Access 已落地**;**P1a–P1d 已落地**:web AI list/get/resolve/login/session → core;`mnote-vault serve` UDS + CLI sock→内嵌 fallback;**login/session 不依赖 mnote-web**) > Owner:`12-vault` > 建议 repo 落点:`design/12-vault/process/12-2-vaultd-local-token-agent-read-path-v1.md` > > 上位依据: > - `design/12-vault/process/12-1-password-vault-dedicated-crud-workbench-v1.md`(vault 系统空间、AI 密码本策略、文件真源) > - `/home/lix/.agent-infra/vault-policy.md`(多 agent 唯一策略 SSOT) > - `skills/mnote-vault` / `$mnote-vault` > - `design/07-ai/process/7-18-local-first-agent-file-editing-control-plane-v1.md`(禁裸读敏感路径) > - `ARCHITECTURE.md` local-first 原则 > > 触发证据: > - Paseo session `21242fc0-db03-454c-a1e5-723688351ee7`:取密依赖 mnote-web 存活 + `auth-e2e` cookie,步骤膨胀、失败面大。 > - 用户目标:**读库本质是本地文件**;解密/受控读取只需轻量常驻服务,**不**应绑庞大 mnote-web;agent 内部保存 **token** 做授权取密。 --- ## 1. Overview ### 1.1 一句话 > **文件是库;`mnote-vaultd` 是受控读密网关(及未来 master key 匣);agent 只持 capability token,不持 master key,也不依赖 mnote-web 进程。** ### 1.2 与 12-1 的关系 | 维度 | 12-1(已落地主线) | 12-2(本文) | |------|-------------------|--------------| | 真源 | `{workspaceRoot}/.mnote/vault/**` 结构化文件 | **不变** | | 人用 UI | `/vault` + mnote-web `/api/vault/*` | **保留**;不作为 agent 读密必经 | | AI 策略 | 单 AI 本 + 单 resolve 通道 + 禁扫 vault 文件 | **策略不变**;**transport 换** | | Agent 通道 | HTTP → mnote-web(需 cookie / auth-e2e) | UDS/loopback → **vaultd**(Bearer token) | | 常驻进程 | 整站 mnote-web | 可选 **极小 vaultd** | 12-1 P1「多 agent 唯一策略」中的语义(只读 AI 本、`resolve` 唯一取密、禁通用 file)**冻结保留**。 本文只改 **谁持进程、用什么凭证、是否依赖 3000**。 ### 1.3 现状诚实声明(实现前必读) 当前实现(2026-07): - 条目为 workspace 下 **结构化 Markdown + frontmatter**(`mnote.kind: credential`)。 - `cipher-book.json` 是 **片段占位符展开**(如 `[A]` → 共享串),**不是** 磁盘 AES 整库加密。 - 尚无「用户 master password → 内存 master key → 密文 at rest」完整链路。 - 「解密」在产品语言上 = **load 文件 + cipher 展开 + nested secret 解析 + 策略门闩**。 因此 12-2 分两层能力,**禁止混称**: | 层 | 名称 | P0 是否必须 | 说明 | |----|------|-------------|------| | **L-Access** | 受控读密网关 | **是** | token 鉴权、只暴露 list/get/resolve、审计、不依赖 mnote-web | | **L-Crypto** | 真·at-rest 加密 | **P2 可选** | master key 仅驻 vaultd 内存;token **永不**等于 master key | P0 交付 **L-Access** 即可消除「3000 挂了就不能取密」。 L-Crypto 在文件格式与迁移就绪后再做,不阻塞 agent 读路径瘦身。 --- ## 2. Goals / Non-Goals ### 2.1 Goals 1. Agent 读密(list / get / resolve / login 所需密钥字段)**不依赖 mnote-web 运行**。 2. 常驻面缩小为 **`mnote-vaultd`**(或等价 one-shot CLI 内嵌同一 core,见 §5.4),不跑 SSR/Sidebar/文档编辑。 3. Agent **内部保存 vault_token**;每次调用带 token;**禁止**把 master password / master key 写入 agent 配置。 4. 保持 12-1 策略:仅 AI 密码本 actor;禁通用工具扫 `.mnote/vault/**`;resolve 审计不落明文到日志。 5. CLI / Pi 工具 / skill 语义对齐:稳态 **1~2 次调用**完成取密(已知 id 时仅 `resolve`)。 6. mnote-web UI 与 human CRUD **可继续用现网路径**;演进期可与 vaultd 并行,终态共享 `mnote-vault-core`。 ### 2.2 Non-Goals(本设计不承诺) - 不重做 `/vault` 工作台 UI。 - 不把 vault 变成 graph / `tree.*` 节点。 - 不要求远程多机共享 vaultd(本机 local-first;跨机另案)。 - 不在 P0 强制引入 at-rest 加密迁移(L-Crypto = P2)。 - 不取消「禁扫 vault 文件」策略(即便未来密文 at rest,仍禁止 agent 把 vault 目录当通用笔记读)。 - 不把 Cloudflare 过人机验证自动化为无人值守(仍 human → `session` 回写)。 --- ## 3. 问题根因(为何要拆) ```text 今天 Agent 取密关键路径: skill/policy → mnote-vault-cli auth-e2e # 需要 mnote-web + 用户 auth API → list / resolve HTTP # 需要 3000 存活 + cookie → (可选)login / session 失败面: - web 未启动 / 崩溃 / 端口占用 - cookie eval / FORCE_COLOR / 环境变量污染 - agent 探索路径、读 policy、猜 URL → 工具次数爆炸 ``` 根因归类: | 误绑定 | 正确归属 | |--------|----------| | 读本地文件 → 需要 Web 服务器 | 读文件 → 本地 IO + 可选小网关 | | Agent 身份 → mnote-web session cookie | Agent 身份 → vault capability token | | 解密权 → 与 SSR 同进程 | 解密/受控 resolve → vaultd(或 CLI 内嵌 core) | --- ## 4. 目标架构 ### 4.1 分层图 ```text ┌──────────────────────────────────────────────────────────────┐ │ Agent runtime(Grok / Codex / Hermes / Pi / Paseo) │ │ - 持有 vault_token(env / 0600 文件 / 可选 keyring) │ │ - 薄客户端:CLI 或 Pi tool → 只打 vaultd │ │ - 禁止:通用 file 扫 .mnote/vault/** │ └────────────────────────────┬─────────────────────────────────┘ │ Authorization: Bearer │ 优先 Unix Domain Socket ▼ ┌──────────────────────────────────────────────────────────────┐ │ mnote-vaultd(常驻 · 小 · 本机) │ │ - 校验 token(iss/aud/exp/scope/actor) │ │ - 解析 vault root(workspace / AI actor root) │ │ - load index / credential md + cipher expand + nested secret │ │ - L-Crypto 时:内存持 master key;lock 清空 │ │ - 审计 jsonl(无 plaintext value) │ │ - 不托管:SSR、树、Page AI、control-plane 全站逻辑 │ └────────────────────────────┬─────────────────────────────────┘ │ 受控读写 FS ▼ ┌──────────────────────────────────────────────────────────────┐ │ 本地文件真源(SSOT,与 12-1 相同) │ │ {workspaceRoot}/.mnote/vault/ │ │ vault-index.json │ │ credentials|*.md(条目) │ │ cipher-book.json │ │ audit.jsonl │ │ AI 本:MNOTE_AI_VAULT_ACTOR 对应 root(实现沿用 12-1) │ └──────────────────────────────────────────────────────────────┘ 旁路(可选,非读密阻塞路径): mnote-web /vault UI、human CRUD、共享到 AI 本 Chrome 扩展保存到 vault(人用 human token,见 12-3;**禁止**复用本设计 agent token) 登录态落盘:sessions/{credId}/{accountId}.json(12-3 §5.6);login/session CLI 读该路径,fallback frontmatter loginSession vault-login-helper resolve 后外站登录 / session 回写 ``` ### 4.2 两类密钥(禁止混用) | 名称 | 持有者 | 用途 | 落盘? | |------|--------|------|--------| | **Master key**(L-Crypto) | 仅 vaultd 内存 | 解密 at-rest 密文包 | 否(仅 unlock 后内存) | | **Vault token**(capability) | Agent 配置 / runtime | 向 vaultd 证明「谁、何 scope、何 actor」 | 可:`~/.config/mnote/vault-tokens/*.token`,`0600` | **硬规则:** 1. Token **不能**派生或编码 master key。 2. 泄露 token ⇒ 在 vaultd 存活且已 unlock 时可 resolve;**不能**离线解密磁盘(L-Crypto 后更强)。 3. 泄露 master password ⇒ 可 unlock 整库;**不得**写入任何 agent skill / env 默认模板。 ### 4.3 Token 声明(逻辑 schema) ```json { "v": 1, "iss": "mnote-vaultd", "aud": "local-vaultd", "sub": "agent:paseo", "actor": "mnote-e2e", "scope": ["list", "get", "resolve", "login", "session"], "workspace": "optional-stable-id-or-path-hash", "iat": 0, "exp": 0, "jti": "uuid" } ``` - 序列化:紧凑 JSON + **HMAC-SHA256**(本机 secret)或 ed25519(若未来多签发方)。 - 传输:`Authorization: Bearer `(类 JWT 即可,不必上完整 OIDC)。 - P0 默认 scope:`list` + `get` + `resolve`;`login`/`session` 可同 token 或分 token。 - `actor` **必须**等于 AI 密码本 actor(默认 `mnote-e2e`,env `MNOTE_AI_VAULT_ACTOR` 可覆盖签发时固化进 token)。 ### 4.4 Bootstrap(token 从哪来) ```text 一次(人或安装脚本): 1. 启动 vaultd(或 CLI doctor) 2. (L-Crypto)用户 unlock → master key 入内存 3. vaultd issue-token \ --agent paseo \ --actor mnote-e2e \ --scope list,get,resolve,login,session \ --ttl 90d 4. 写入 ~/.config/mnote/vault-tokens/default.token(0600) 5. 各 agent skill / env:MNOTE_VAULT_TOKEN_FILE 或 MNOTE_VAULT_TOKEN 日常 agent: 读 token → 调 resolve → 用完 value(不写聊天、不写无关日志) ``` 轮换:`revoke jti` + 重新 issue;vaultd 维护 deny jti 集合(内存 + 可选小文件)。 --- ## 5. `mnote-vaultd` 规格 ### 5.1 进程与监听 | 项 | P0 决定 | |----|---------| | 二进制名 | `mnote-vaultd`(或 `mnote vault-daemon` 子命令) | | 默认传输 | **Unix Domain Socket**:`$XDG_RUNTIME_DIR/mnote-vaultd.sock`(回退 `/tmp/mnote-vaultd-$UID.sock`) | | TCP 备选 | `127.0.0.1:17300`,**默认关**;仅显式 `--listen-tcp` | | 权限 | sock `0600`、属主当前用户;拒绝非本 uid(若 OS 支持 peer cred) | | 启动 | user systemd / 登录脚本 / 首次 CLI 自动拉起(见 §5.4) | | 资源 | 目标:常驻 RSS 远小于 mnote-web;无浏览器、无 leptos SSR | ### 5.2 API 表面(JSON over HTTP/1.1 on UDS,或 length-prefixed JSON) 与现 Pi / CLI 语义对齐,路径前缀建议 `/v1/`: | 方法 | 路径 | scope | 解密/展开 | 说明 | |------|------|-------|-----------|------| | GET | `/v1/health` | 无 token 也可 | 否 | `ok`, `unlocked`, `version`, `actorDefault` | | GET | `/v1/items` | `list` | 否* | L0 列表;同现 `list_ai` | | GET | `/v1/items/{id}` | `get` | 否* | 元数据 + 掩码;无 password 明文 | | POST | `/v1/items/{id}/resolve` | `resolve` | **是** | body: `field`, `accountId?`, `secretId?` | | POST | `/v1/items/{id}/login` | `login` | 内部 resolve | 可 P1 仍代理或旁路 helper | | POST | `/v1/items/{id}/session` | `session` | 写 session | 人机回写 | | POST | `/v1/lock` | admin | — | 清 master key(L-Crypto) | | POST | `/v1/unlock` | admin | — | 本机交互/钥匙环;**不**给 agent 默认 scope | | POST | `/v1/tokens/issue` | admin | — | 签发 agent token | | POST | `/v1/tokens/revoke` | admin | — | 吊销 jti | \* list/get:若未来元数据也加密,仅解密标题等非 secret 字段;password 永不出现在 list/get。 **错误码(稳定字符串,CLI/skill 可分支):** | code | HTTP | 含义 | Agent 动作 | |------|------|------|------------| | `vaultd_unavailable` | — | sock 连不上 | 尝试 autostart 或提示用户起服务 | | `vault_token_missing` | 401 | 无 Bearer | 检查 token 文件 / env | | `vault_token_invalid` | 401 | 签名/格式错 | 重新 issue | | `vault_token_expired` | 401 | exp | 轮换 token | | `vault_scope_denied` | 403 | scope 不足 | 重新签发含所需 scope | | `vault_actor_mismatch` | 403 | token.actor ≠ AI 本 | 用正确 actor token | | `vault_locked` | 423 | L-Crypto 未 unlock | 提示用户 `unlock`(**不是**启动 mnote-web) | | `vault_item_not_found` | 404 | id 不存在 / 非 AI 本 | list 再选 | | `vault_resolve_field_invalid` | 400 | 字段不合法 | 对齐 schema | | `vault_resolve_ai_only` | 403 | 试图 resolve 用户本 | 策略拒绝(与 12-1 一致) | ### 5.3 与文件布局(概念,兼容 12-1) ```text {workspaceRoot}/.mnote/vault/ # SSOT,vaultd 与 mnote-web 共享读 vault-index.json … credential markdown … cipher-book.json audit.jsonl # 可继续追加;vaultd 写 agent 通道审计 ~/.config/mnote/ vaultd.toml # 可选:root 覆盖、ttl 默认、tcp 开关 vault-tokens/ default.token # agent 用,0600 vaultd-hmac.key # 签发 secret,0600;仅 vaultd/admin CLI 读 $XDG_RUNTIME_DIR/mnote-vaultd.sock ``` **Workspace root 解析顺序(P0):** 1. 请求头 / CLI 显式 `--workspace` 2. env `MNOTE_VAULT_WORKSPACE` 3. `vaultd.toml` 默认 4. 与现 mnote-web 一致的「当前 dev workspace」约定(实现时对齐 `vault.rs` AI root 解析,避免双根) AI actor root:继续 `MNOTE_AI_VAULT_ACTOR`;token 内 `actor` 必须匹配。 ### 5.4 无常驻时的退化(仍不依赖 mnote-web) 若用户不愿常驻 daemon: ```text mnote-vault-cli resolve --id X → 若 sock 可达:走 vaultd → 若不可达:CLI 内嵌 mnote-vault-core(同代码)+ 本机 token 校验 校验密钥来自 ~/.config/mnote/vaultd-hmac.key(用户可读则等同本机信任) ``` **注意:** 内嵌模式仍 **禁止** 无 token 裸读;仍 **禁止** agent 用通用 Read 打开 vault 文件。 Autostart:CLI 可 `spawn` 一次 vaultd(user 级),避免每个 agent 拉起全站 3000。 ### 5.5 login / session 边界 | 能力 | 建议 owner | 依赖 | |------|------------|------| | resolve 密码字段 | **vaultd 必含** | 仅本地文件 | | list/get | **vaultd 必含** | 仅本地文件 | | 外站 login playbook | vaultd 插件 **或** `vault-login-helper` | 网络 + 可选浏览器 | | Cloudflare session 回写 | 同 login helper | 人 + chrome-bridge | P0 最小闭环:**health + list + get + resolve**。 login/session 可 P0.5 从现 mnote-web 逻辑迁出或短期仍调 web(但 **resolve 不得回退依赖 web**)。 --- ## 6. Agent 侧合同 ### 6.1 环境变量 | 变量 | 含义 | |------|------| | `MNOTE_VAULT_TOKEN` | 直接 token 字符串(会话级优先) | | `MNOTE_VAULT_TOKEN_FILE` | 默认 `~/.config/mnote/vault-tokens/default.token` | | `MNOTE_VAULT_SOCK` | 覆盖 UDS 路径 | | `MNOTE_VAULT_WORKSPACE` | workspace root | | `MNOTE_AI_VAULT_ACTOR` | 与签发 token 一致(文档提示;以 token.actor 为准) | | ~~`MNOTE_BASE_URL` + `MNOTE_COOKIE`~~ | **读密路径废弃**;仅 human/web 调试保留 | ### 6.2 CLI 稳态(目标) ```bash # 一次安装(人) mnote-vault doctor # sock / token / unlock 状态 mnote-vault unlock # 仅 L-Crypto mnote-vault issue-token … # 写入 token 文件 # Agent 每次取密(已知 id) mnote-vault resolve --id --field password [--account-id …] [--raw] # 未知 id mnote-vault list mnote-vault resolve --id --field password ``` **删除读密对 `auth-e2e` 的依赖。** `auth-e2e` 可留作「测 mnote-web UI」工具,**不得**再出现在 `$mnote-vault` skill 稳态步骤。 ### 6.3 Skill / policy 修订点(实现阶段同步,本文先钉文案) `/home/lix/.agent-infra/vault-policy.md` 与 `$mnote-vault` 将改为: 1. 读密:**token + vaultd/CLI**,不经 mnote-web。 2. 仍禁扫 `.mnote/vault/**`。 3. 登录仍优先 `login`;CF 仍 human + `session`。 4. 故障树:`vault_locked` → 用户 unlock;`vaultd_unavailable` → 起 vaultd / CLI 内嵌;**不要**默认 `desktop:hot`。 ### 6.4 Pi tools | 现名 | 后端切换 | |------|----------| | `mnote.vault.list\|get\|resolve\|login\|session` | 默认连 vaultd;失败策略见 §5.4 | | 鉴权 | Bearer token,不再注入 web cookie | ### 6.5 安全行为(agent) - 聊天 / transcript:只写 `transcriptHint`,不写 password / cookieHeader。 - resolve value 仅用于当前工具链下一步(登录、填表),不回显用户除非用户明确要求。 - 禁止把 token 贴进公开 issue / 截图。 --- ## 7. mnote-web 关系与迁移阶段 ### 7.1 阶段 | 阶段 | 内容 | 退出标准 | |------|------|----------| | **A 现状** | Agent → mnote-web cookie → 文件 | — | | **B 并行(P0)** | 抽出 `mnote-vault-core`;`vaultd` + CLI token 路径;web 仍可直读文件 | **不启 3000 可 resolve** smoke 绿 | | **C 收口(P1)** | web `/api/vault/ai/*` 改为调 core 或代理 vaultd;skill 去 auth-e2e | 双路径一致;旧 cookie AI 路径标 deprecated | | **D 可选(P2)** | L-Crypto at-rest;web unlock UI 只负责把 key 交给 vaultd | 磁盘密文;无 key 不可读 | ### 7.2 代码落点(建议) | crate / 路径 | 职责 | |--------------|------| | `rust/crates/mnote-vault-core`(新) | index/load/parse、cipher expand、nested secret resolve、audit append、(P2)encrypt | | `rust/crates/mnote-vaultd`(新)或 `mnote-vault` bin | UDS 服务、token 校验、issue/revoke | | `mnote-web` `vault_store` | 逐步 thin wrapper → core;UI 路由保留 | | `scripts/mnote-vault-cli.js` | 默认 sock+token;保留 `--via-web` 仅调试 | **禁止:** 在 vaultd 内重新实现第二套 frontmatter schema。 ### 7.3 兼容 - 文件 schema(`mnote.vault.credential.v1` 等)**不**为 12-2 破坏性变更。 - 现有 AI 本条目无需迁移即可被 vaultd list/resolve(L-Access)。 - L-Crypto 若上:单独 migration 设计 + 双读窗口,不在本文展开实现细节,只保留扩展点。 --- ## 8. 威胁模型(摘要) | 威胁 | 缓解 | |------|------| | Agent prompt 注入要求 dump 全库 | 按条 resolve;list 无密;rate limit;审计 | | Token 文件被同机其他用户读 | `0600` + UDS peer cred | | Token 被复制到另一台机器 | `aud=local-vaultd` + 可选绑定 machine-id;无 hmac key 则签失败 | | 磁盘被盗 | P0:OS 磁盘加密依赖;P2:vault at-rest | | 恶意进程连 sock | 无有效 token 拒绝;sock 权限 | | 日志泄漏 | audit 不写 value;CLI 默认 JSON 管道、skill 禁回显 | | mnote-web RCE | 读密不依赖 web 后,攻击面与 key 分离(P2 更明显) | | 用户把 vault 目录加进 agent 工作区 | 策略 + Pi allowlist deny;文档披露(12-1 已有) | --- ## 9. 验收标准(设计完成 → 实现门闩) ### 9.1 P0 必须 - [x] **mnote-web 未运行**时,持有效 token 可 `list` + `resolve` 成功(AI 本已有条目)。 - [x] 无 token / 坏 token → 明确错误码,不回退匿名读文件。 - [x] resolve 响应含 value;audit 无 value(沿用 store audit)。 - [x] CLI 稳态文档与 skill:**无** `auth-e2e` 作为读密前置。 - [ ] 通用 file 工具读 vault 路径仍 deny(web 与 Pi 侧回归,既有策略)。 - [x] 单元测试:token 校验、scope;store 原有 20 测。 - [x] 集成 smoke:`cargo run -p mnote-vault -- …` 不启 3000(2026-07-23 本机绿)。 ### 9.2 P1 - [x] login/session 不依赖 web(core + CLI + UDS;外站 HTTP 仅 api_first 出站,resolve 仍本地)。 - [x] mnote-web AI list/get/resolve/login/session thin-wrap 同一 core(2026-07-23)。 - [ ] policy / skill / Paseo appendSystemPrompt 全文切换(skill 已更新 login/session 本地路径;Paseo 段可再对齐)。 ### 9.3 P2(L-Crypto) - [ ] unlock 前 resolve → `vault_locked`。 - [ ] master key 仅内存;lock 后不可 resolve。 - [ ] token 无法离线解密 credential 文件。 --- ## 10. 实现 Checklist(批准设计后执行;本文件阶段只列不写代码) ### PR-1 — core 抽出 - [x] 新建 `mnote-vault-core`,从 `vault_store` 搬迁:load index、load credential、cipher expand、`resolve_record_secret_field`、AI actor root 解析。 - [x] mnote-web AI 路径 thin-wrap core(list/get/resolve/login/session);CRUD/workbench 仍可双路径。 ### PR-2 — vaultd + token - [x] token issue/verify(HMAC + 文件格式 `mnv1.*`)。 - [x] UDS server:health/list/get/resolve/**login/session**(`mnote-vault serve`)。 - [x] audit 写入(resolve/login/session 经 store)。 - [x] CLI 默认 local-core + token(`mnote-vault` bin;sock 优先 fallback 内嵌)。 ### PR-3 — agent 面 - [x] 更新 `vault-policy.md`、`$mnote-vault`(读密去 auth-e2e;login/session 本地 CLI)。 - [ ] Pi tool 仍进程内 thin-wrap core(不强制走 sock;可后置切 UDS)。 - [x] smoke:不启 3000 → resolve / session+login reuse。 - [x] TESTING_REFERENCE 增补 vault-local 段落(含 session/login)。 ### PR-4 — login 迁出 - [x] login/session 进 core + CLI + UDS(api_first 出站 HTTP 在 core;human_required 仍人 + session 回写)。 - [x] skill 表述:login/session 可本地、不依赖 mnote-web。 ### PR-5 — L-Crypto(另设计修订) - [ ] 密文格式、unlock UI、迁移工具。 --- ## 11. 待决问题(实现前钉死;默认推荐已标) | # | 问题 | 推荐默认 | |---|------|----------| | D1 | UDS vs TCP | **UDS 默认**;TCP 显式开 | | D2 | Token 算法 | **HMAC-SHA256** 本机 secret | | D3 | 无 daemon 时 CLI 内嵌 | **允许**,同 token 校验 | | D4 | login 是否进 P0 vaultd | **P0 不含**;P0 只 resolve 闭环 | | D5 | web 是否立刻代理 vaultd | **P1**;P0 双路径并行 | | D6 | AI root 与多 workspace | P0 单默认 workspace + env 覆盖 | | D7 | L-Crypto 时间表 | **不进 P0**;扩展点保留 | | D8 | token TTL | 默认 90d;可 issue 无 exp 仅 dev | 若用户否定推荐,在本文修订表追加一行后再开 PR-1。 --- ## 12. 修订记录 | 日期 | 说明 | |------|------| | 2026-07-23 | v1 初稿:本地文件 SSOT + vaultd + agent token;与 12-1 AI 策略对齐;L-Access P0 / L-Crypto P2;验收与 PR 切片 | | 2026-07-23 | P0 落地:`mnote-vault-core` + `mnote-vault` CLI(issue-token/list/get/resolve);无 web smoke 绿;UDS vaultd / web 共 core 留 P1 | | 2026-07-23 | P1d:login/session → core + CLI/UDS;web thin-wrap;session 回写 + login reuse 不依赖 mnote-web | | 2026-07-24 | 交叉 12-3:登录态演进为 `sessions/{credId}/{accountId}.json`;CLI 语义不变,读序优先 session 文件 | --- ## 13. 批准栏(实现启动条件) - [x] 用户确认 §2 Goals / Non-Goals(2026-07-23「先按12-2实现」) - [x] 用户确认 §11 默认决策(含 D3 内嵌 CLI) - [x] P0:**core + CLI 内嵌 resolve**;login / UDS / web thin-wrap 后置 P0 交付物:`rust/crates/mnote-vault-core`、`rust/crates/mnote-vault`(bin `mnote-vault`)。