一次状态变化通常跨越两到四层
例如 Agent 输出先改变 External CLI/PTTY 状态,再由 Main 推送事件,Renderer 写入 Zustand,必要时镜像 roster;但 CLI 会话/上下文本身仍由外部 Agent 保存。
状态不是一张表:五层权威
SQLite Phase A 只有两张表
harness.db 位于 Electron userData,开启 WAL。kv 目前主要保存窗口 bounds;command_history 保存用户提交的 prompt。代码注释明确把 agents、message_queue、cost_ledger 标记为未来迁移,不应按 SPEC.md 的理想模型描述为已完成。
文档差异:SPEC.md 写“SQLite: Agents, layouts, command history, goals”,但当前 `db.ts` 明确说明 agents/message_queue 尚未实现。以源码为准。
同一业务域使用多种持久化机制
config.json 保存设置;localStorage 保存 UI/roster 并镜像到 harnessHome/roster.json;Hive registry/tasks/mailboxes/memory 是文件,且 Hive 自身是由单一 committer 管理的 Git repo;外部 CLI 会话保存在各自目录。
- 01内存:PtyManager sessions、timers、liveWorkers、breaker state、Zustand transient fields。
- 02userData:config.json、harness.db、analytics install/version stamps、knowledge store。
- 03harnessHome:roster.json、hive/registry.json、tasks.json、board.md、agents/*、cost-ledger.jsonl。
- 04External CLI:Claude transcripts、per-agent CODEX_HOME、provider sessions 与凭据。
src/main/config.tsL586-L690readConfigwriteConfigpersistConfig配置从 userData/config.json 读取、合并默认值并写回。
src/main/roster.tsL1-L162RosterStorereadwriteroster.json 解决 dev http origin 与 packaged file origin 的 localStorage 隔离。
src/renderer/src/store/store.tsL363-L660persistAgentspersistQueuesrosterMirrorlocalStorage 与 roster mirror 是 additive dual-write。
src/main/hive.tsL2482-L2578atomicWriteJsoncommitHive JSON 原子落盘,并由单一 committer 重试 Git 提交。
Memory Graph 已有 UI;语义 memory 与 Knowledge Graph 仍是可选模块
旧 MEMORY_GRAPH_SPEC.md 自称“未写组件”,但当前源码已有 MemoryGraphPanel 与 client-side topic extraction。语义检索依赖可选 mempalace CLI;企业 Knowledge Graph 是另一套可选本地 store,不要混成 SQLite 内的一张统一图表。
src/renderer/src/components/MemoryGraphPanel.tsxL23-L190MemoryGraphPanel当前 renderer 已有可视化组件。
src/renderer/src/components/memoryGraph/extractTopics.tsextractTopics主题提取在客户端进行,并关注跨 agent 共享知识。
src/main/memory.tsL1-L12MemoryManagermempalaceSemantic memory 缺少 CLI 时静默降级,markdown memory 仍工作。
src/main/knowledge.tsL45-L92KnowledgeManageractivestatusKnowledge Graph 由独立 config 开关和本地 store 管理。
MEMORY_GRAPH_SPEC.mdL1-L8Status旧设计状态已经落后于源码。
为任何新字段先填六格,再决定 schema
字段名、scope、authority、写入者、副本、恢复/删除共同定义状态契约。只写一个 Zustand slice 或 DB column 还没有完成设计。
‘selectedAgentId’可能只是当前窗口选择;‘agentStatus’却是跨进程事实。名字相似,生命周期完全不同。