Compare commits

...
Author SHA1 Message Date
alvinfeiandCursor d9332a7eb2 docs: finalize public runtime and migration contracts
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-22 15:38:20 +08:00
12 changed files with 198 additions and 453 deletions

No files matched your search

+2 -2
View File
@@ -18,7 +18,7 @@ If you run into a problem, please open an Issue with the version, platform,repro
## 发行与平台合同
当前重构验证固定使用开发预览 `hy-memory==2.0.5.dev3`。MemHub 源码版本为 `1.0.4`
源码当前固定使用公开 PyPI 开发预览 `hy-memory==2.0.5.dev3`。MemHub 源码版本为 `1.0.4`
(build 13),GitHub 仓库为
[`Tencent-Hunyuan/Hy-Memory`](https://github.com/Tencent-Hunyuan/Hy-Memory),npm 包名为
`memhub-cli`。当前代码架构见
@@ -114,7 +114,7 @@ MemHub 的 SQLite 数据默认位于 `~/.one-memory`,不在 npm 包或 Runtime
## Hy Memory
当前开发依赖固定为公开 PyPI 开发预览 `hy-memory==2.0.5.dev3`。SDK 配置、权限边界及 search
SDK 依赖固定为公开 PyPI 开发预览 `hy-memory==2.0.5.dev3`。SDK 配置、权限边界及 search
返回格式见 [`MEMORY.md`](MEMORY.md)。HY search 返回的 `content` 已包含 SDK 统一生成的
逻辑时间和演化上下文;调用方不应再次转换时间戳或重复拼接 `When`。
+1 -1
View File
@@ -120,7 +120,7 @@ authorized harness / user action
Hy Memory is the **only** extraction, memory entity, relationship, and semantic-retrieval engine. Product code enters it through `HyMemoryBridge`(共享 Runtime、模型配置、密钥边界),不在业务模块里私自 new 一套绕过门禁的 client。
- Storage backends:仅 SDK config/env(Chroma/FAISS/Qdrant、Kuzu/Neo4j、cache/history sqlite|mysql、coding sqlite 等)。
- Queue:pending `memory_write_jobs` 只表示尚未调用 SDK 的待处理请求,因此没有 SDK raw/memory ID。worker 单次调用 SDK `add()`;SDK 内部完成 raw 写入与 extraction/reconciliation,成功后 MemHub 仅将返回的 raw ID / memory IDs 记作 job/task outcome。`import_raw()` 只用于历史数据的 exact migration,不拆分正常写路径。
- Queue:pending `memory_write_jobs` 只表示尚未调用 SDK 的待处理请求,因此没有 SDK raw/memory ID。worker 单次调用 SDK `add()`;SDK 内部完成 raw 写入与 extraction/reconciliation,成功后 MemHub 仅将返回的 raw ID / memory IDs 记作 job outcome。`import_raw()` 只用于历史数据的 exact migration,不拆分正常写路径。
- Recall:Host Bridge / Core 先做宿主安装凭据与 tool grant,再调 **SDK search/get**。当前产品没有逐 memory 的 A-harness→B-harness 可见性开关,默认允许跨 harness 搜索;未来若增加来源限制,直接透传 SDK `source` / `include_sources` / `exclude_sources`,不在 MemHub 建 memory ACL。
- Context wire:cutover marker 提交前只使用 legacy Context v1;提交后 Host Bridge 只使用 SDK-native Context v2。两种 schema 原样校验、原样返回,不把 SDK item 补造成 v1 的 `revision`、`evidence_ids`、`paths` 或 `adoption`,已选择的 v2 路径失败时也不回退 legacy 权威。
- Ask wire:marker 前保留 Governance Ask v1;marker 后 Web / Host Bridge 只调用 SDK Ask v2。v2 的引用只含 SDK 原生 `memory_id/content/layer/status/source/gmt_created`,生成过程中重复 `get` 校验同一 SDK 快照,不补造 revision、Evidence 或 scopes,SDK 失败不回退 v1。
+4 -3
View File
@@ -106,9 +106,10 @@ Downloader 使用标准 `HTTPS_PROXY`/`https_proxy` 与 `NO_PROXY`/`no_proxy`
- `memhub delete-data`:唯一删除 Memory 的命令;Runtime 必须已停止,并要求 `--yes` 与
`--confirm <精确数据路径>` 两次确认。
默认数据目录是 `~/.one-memory`。Python Core 是唯一业务数据写入者,SQLite 数据不位于
npm package、App 临时目录或受管 Runtime 的版本目录中。Python Core 及其依赖由 Runtime
携带,不会向用户的系统 Python 安装 package。
默认数据目录是 `~/.one-memory`。Python Core 是 MemHub 管理库的唯一写入者;
memory/raw 数据平面只通过 Hy Memory SDK 写入。SQLite 数据不位于 npm package、
App 临时目录或受管 Runtime 的版本目录中。Python Core 及其依赖由 Runtime 携带,
不会向用户的系统 Python 安装 package。
## 代理、镜像和离线来源
@@ -1,61 +0,0 @@
# Memory Event-Time Scheduling Implementation Plan
## Goal
Preserve one user memory timeline across all imported Harnesses without
serializing unrelated work that happened at nearly the same time.
The target scheduler uses final conversation chunks as durable jobs, orders
them by turn event time, and permits cross-Harness concurrency only inside one
fixed ten-minute event-time window.
## Delivery sequence
1. **Turn time**
- Parse native Harness timestamps.
- Parse Cursor `<timestamp>` envelopes before stripping them.
- Mark fallback quality explicitly.
- Derive each chunk's time from its protocol `user` opener.
2. **Durable schema**
- Add `event_at` and `time_quality` to `memory_write_jobs`.
- Backfill existing jobs without changing idempotency identity.
- Persist the active window anchor/end across restarts.
3. **Windowed Drain**
- Anchor at the oldest eligible pending event.
- Admit only `[anchor, anchor + 10 minutes)`.
- Keep one running job per Harness; order globally by `event_at`.
- Use `queue_seq` only to break equal-time ties within one Session.
- Advance only after the current window has no eligible pending/running
work.
4. **First-import gate**
- Import all accepted Harness history and enqueue chunks first.
- Release model processing after all accepted history jobs are terminal.
- Exclude failed and user-disabled sources rather than blocking forever.
5. **Pause/restart**
- Sedimentation off leaves jobs pending and returns unspent attempts.
- Source pause parks that source without blocking others.
- Restart resumes the persisted window, not a newly computed sliding one.
6. **Verification**
- Cross-day Cursor session.
- Exact ten-minute boundary and non-sliding windows.
- Harness/session FIFO under concurrency.
- Manual Memory behind historical backlog.
- First-import zero model calls before gate release.
- Legacy database backfill and restart recovery.
## Non-goals
- No HY Memory SDK change.
- No change to Evidence or Write Job idempotency.
- No live-priority jump across event-time windows.
- No destructive migration of old timestamps; uncertain legacy values remain
explicitly approximate.
The normative behavior is documented in
[`contracts/memory-event-time-scheduling-v1.md`](contracts/memory-event-time-scheduling-v1.md).
+1 -1
View File
@@ -249,7 +249,7 @@ jq --arg id "$TASK_ID" 'select(.task_id == $id)' "$LOG"
- 有 `core.ready`,没有 `import.finished`:来源未授权、未开启同步,或来源读取失败。
- `import.finished` 正常,没有 `memory_scheduler.tasks_queued`:导入内容尚未形成完整会话,或未进入处理窗口。
- 有 `memory_task.started`,没有 `hy.ingest_completed`:重点查模型配置、余额、网络、超时和 `hy.ingest_failed`。
- 有 `hy.ingest_completed`,但 `memory_task.finished` 失败:重点查最终治理写入和对应 `error_code`。
- 有 `hy.ingest_completed`,但 `memory_task.finished` 失败:重点查 SDK 结果确认、写入队列终态和对应 `error_code`。
- `pending_count` 长时间完全不下降:查看是否反复出现同一个错误码,或任务都在
`waiting_for_model`。
- 导入数量持续增加、沉淀任务完全没有出现:这是异常,不应解释为“对话没有记忆价值”。
+1 -1
View File
@@ -52,7 +52,7 @@ host-bridge、desktop 和 cli。单文件 4 MiB,保留 3 份轮转;额外清
- `memory_task.finished`:最终 `result_count`、剩余 `pending_count` 和 `attempt`。
其中 `memory_task.finished` 是产品侧判断沉淀是否持续推进的最终事件;不能只用
`hy.ingest.completed` 代替,因为后者早于 Governance 写入。
`hy.ingest.completed` 代替,因为后者早于 SDK 结果确认和写入队列终态。
## 验收
@@ -1,109 +1,69 @@
# HC-06/10/11 Host Context Transport v1
# Host Context Transport v1
Implementation scope: Host Bridge, Broker, MCP, CLI and managed Skill v10 only.
Core aggregation/authorization adapters/routes remain owned by the main integration
task. This slice consumes its frozen `context_models.py` contract and the identical
`packages/contracts/src/context.ts` snapshot. No second context backend, event
store, model processing policy or cross-session monitor is introduced.
Status: legacy compatibility protocol used before SDK data-plane cutover.
Post-cutover hosts use SDK-native Context v2 at
`POST /api/v2/context/search`. A v2 response is never converted into v1 by
inventing revisions, Evidence IDs, paths, or adoption state.
## Implemented behavior
## Transport
- `om_context` sends one request through authenticated Broker `/context` to
`POST /api/v1/context/search`. Legacy tools preserve their endpoints and shapes.
- Request validation matches query/kinds/raw_source_ids/limit/character_budget/
timeout_ms. Identity, arbitrary scopes and workspace fields are rejected.
- Existing om_recall/om_conversations rights are composed, not replaced by a
universal om_context grant. At least one requested lane must be authorized.
Raw requires all-apps plus source grants; memory requires an existing memory
scope. Explicit unauthorized raw sources reject before calling Core.
- Broker captures installation identity/revision and re-authenticates before
releasing results. Revoke, rotation and narrowing invalidate the whole release.
A missing grant store fails closed for this new endpoint.
- Client and Broker validate bounded response shape, counts, text usage and
requested selection. Paths and partial zero-hit results remain intact; no
inferred adoption. Unrecognized payloads never become model-visible content.
- Old Broker/Core 404/405/501 becomes context_upgrade_required. No fallback to
two legacy reads. Failure messages exclude provider error bodies/credentials.
- MCP notifications/cancelled abort the matching active context HTTP call only.
Client cancellation/deadline covers credential/discovery waits and transport;
late credential resolution cannot dispatch a new request. Client disconnection
aborts Broker's Core transport; Core owns cancellation of its actual read work.
- Existing recall executable adds `--context` as its first option. It accepts
repeated --kind/--raw-source plus shared budgets, supports JSON or provenance-
preserving text, and reads the installed private credential file.
- CLI unavailable/denied is exit 4, runtime upgrade is exit 5; ordinary empty or
partial receipts remain machine-readable with their actual lane states.
- Skill v10 prefers the new capability when exposed; CLI documents explicit
context mode. Legacy invocation remains for memory-only queries/self-checks,
not as an automatic retry path. Loading a Skill is not retrieval.
- Generated CLI commands retain the credential-file path, and self-check parses
generated escaped paths without shell evaluation. Existing journaled upgrade
and modified-Skill protection stay in place; v9 upgrade coverage is added.
- `om_context` sends an authenticated Broker `/context` request to
`POST /api/v1/context/search`.
- Request validation covers `query`, `kinds`, `raw_source_ids`, `limit`,
`character_budget`, and `timeout_ms`. Caller-supplied identity, arbitrary
scopes, and workspace fields are rejected.
- Existing `om_recall` and `om_conversations` rights are composed rather than
replaced by a universal context grant. At least one requested lane must be
authorized.
- Raw access requires `all-apps` plus source grants. Memory access requires an
existing memory scope. Explicit unauthorized raw sources are rejected before
Core is called.
- Broker captures installation identity and revision, then re-authenticates
before releasing results. Revocation, credential rotation, or scope
narrowing invalidates the release.
## Verification and scope
## Response and failure semantics
Tests use temporary POSIX installation stores and real local HTTP servers with
controlled Core responses. Native Node child processes execute the built
`dist/mcp.cjs` and `dist/recall-cli.cjs` bundles, using real temporary credential
files. This is protocol integration, not a real user host/model acceptance.
- Client and Broker validate response shape, item count, character usage, and
requested lane selection before content becomes model-visible.
- Paths and partial zero-hit results remain intact; adoption is never inferred.
- Unknown payloads and unauthorized returned lanes fail closed.
- A v1 Core returning 404, 405, or 501 maps to
`context_upgrade_required`; the Broker does not retry by combining separate
legacy reads.
- Failure messages do not include provider bodies, credentials, private paths,
or source content.
- MCP cancellation aborts only the matching active request. Deadlines include
credential discovery and transport, and a late result is never released
after cancellation.
- Raw anchors must refer to messages present in the item. Message IDs are
unique, and grounded/empty/unavailable states must agree with item presence.
Initial new integration tests: 35 failures before implementation. Additional
cancel/response-bound tests exposed 5 failures; a generated-path test independently
failed before its fix. MCP cancellation was strengthened to distinguish explicit
cancellation from a later timeout rather than accepting either as evidence.
## CLI and managed host assets
Run from packages/host-bridge after building:
- The recall executable accepts `--context`, repeated `--kind` and
`--raw-source`, shared budgets, and JSON or provenance-preserving text.
- Unavailable or denied requests exit with code 4; runtime upgrade requirements
exit with code 5. Empty and partial receipts remain machine-readable.
- Managed Skills prefer the context capability when exposed. Legacy invocation
remains available for memory-only compatibility and self-checks, not as an
automatic retry path.
- Generated commands retain the private credential-file path without shell
evaluation. Journaled upgrade and user-modified asset protections remain in
force.
```sh
node node_modules/tsup/dist/cli-default.js
node node_modules/typescript/lib/tsc.js --noEmit --pretty false
node node_modules/vitest/vitest.mjs run --exclude src/host-guidance.test.ts --reporter=dot
```
## Verification requirements
The exclusion is an earlier uncommitted diagnostic-feature red-test draft outside
this slice. It is not staged or delivered in this commit. Legacy expected-failure
and skipped tests remain reported separately. Final counts belong in STATUS and
the integration handoff after the final run, not inferred from intermediate runs.
Tests must cover:
Final 2026-09-19 verification: 548 passed, 1 expected failure, 1 skipped across
44 passed files and 1 skipped file (8.83s). This includes 47 context integration
tests and v9 managed-Skill upgrade coverage. TypeScript, tsup, 18-file Biome and
diff whitespace checks passed. The Core implementation is not part of this
test run. No native host conversation, private data or real model was exercised.
- authenticated routing and strict request/response validation;
- lane and source authorization before Core invocation;
- revocation, credential rotation, and installation-revision races;
- character, item-count, metadata, and timeout budgets;
- client and Broker cancellation without late dispatch or release;
- generated command escaping and managed-Skill upgrades;
- fixed safe errors that do not expose upstream bodies or credentials.
## Integration notes
### Defensive follow-up, 2026-09-19
Main review identified a release-boundary gap: request kinds default to both
lanes, so validating only request selection was insufficient defense against
a faulty Core returning raw content to a memory-only installation. Broker now
checks each returned item's lane and raw source against its captured trusted
identity, in addition to its existing installation-revision release recheck.
Memory content-level scope filtering remains Core's responsibility; the wire
memory item does not carry authority and cannot establish its own scope.
Raw anchors must occur in the item's messages, message IDs must be unique, and
grounded/empty/unavailable states must agree with whether items exist. Partial
zero-hit responses remain valid. Invalid upstream responses release only the
fixed context_unavailable error, not the unauthorized body.
CLI workspace guidance is now explicitly legacy-only; context rejects that
field. Skill version is 11, with an added v10 journaled upgrade regression.
New tests first produced 10 failures and 3 positive controls. Final follow-up
regression: 565 passed, 1 expected failure, 1 skipped in 9.64s; context integration
contains 60 cases. TypeScript, tsup, seven-file Biome and diff checks passed.
The same earlier uncommitted host-guidance draft is excluded. No real host or
Core/model acceptance is claimed by this defensive transport test suite.
- Main already owns the same context.ts type file; retain one copy and the
`.js` type export when merging. Main's Core route is a runtime dependency.
- No Core files, source permissions, model settings or private user data changed.
- No active host configuration or daily installed App was replaced. A source
commit does not update previously loaded tools/Skills: rebuild the product,
apply the managed upgrade and validate a new host session separately.
- Cross-session CS research, earlier recall diagnostics and host-version health
drafts are deliberately excluded; this is not completion of all HC requirements.
- No real Core service/model or native WorkBuddy/Codex conversation was started by
these tests. Native host adoption, real provenance/quality and full product
packaging remain main-integration acceptance tasks.
Protocol tests use synthetic data and local test servers. Native-host adoption,
real model quality, and packaged-product acceptance require separate release
validation.
@@ -28,7 +28,7 @@ Time selection is:
All chunks produced from one oversized turn share its opener time. Their
existing `queue_seq` order is preserved. Timestamps are scheduling metadata,
not part of the evidence or write idempotency identity.
not part of the raw record or write idempotency identity.
### Cursor
@@ -72,9 +72,9 @@ restart cannot silently widen or slide the window.
During onboarding, all accepted Harness history jobs first:
1. import Evidence inside the shared history cutoff;
1. scan source records inside the shared history cutoff;
2. form complete-turn chunks;
3. submit durable write jobs.
3. submit self-contained durable write jobs to the SDK write path.
The drain does not claim model work until every accepted history job is
terminal. A failed Harness is recorded and excluded; it does not block all
@@ -99,22 +99,22 @@ batch are not held.
## Immutable job input and branches
Every new `memory_write_jobs.payload_json` stores the complete immutable
Evidence records used by the write, not only references to another table.
Execution and unknown reconciliation use that snapshot. Terminal jobs retain
it as audit data.
messages and source metadata used by the write, not references to another
table. Execution and unknown reconciliation use that snapshot. Successful
terminal jobs retain IDs and outcome while their input body is reaped.
When a Harness rewinds and continues from an earlier point, already stored
Evidence and jobs are not deleted. Shared unchanged messages deduplicate;
SDK raw records and jobs are not deleted. Shared unchanged messages deduplicate;
changed or new branch records append new jobs. A later revision of a reused
host message id receives a new write id while the earlier job keeps its
original content.
host message ID receives a new write ID while the earlier terminal receipt
remains unchanged.
## Upgrade compatibility
Legacy jobs are assigned:
1. the latest `role=user` Evidence time linked to the job;
2. otherwise the earliest linked Evidence time;
1. the latest `role=user` legacy source-record time linked to the job;
2. otherwise the earliest linked source-record time;
3. otherwise the original job creation time.
They are marked `approximate` and retain `queue_seq` as a deterministic
+96 -258
View File
@@ -1,299 +1,137 @@
# MemHub Runtime 统一架构与实施合同
# MemHub Runtime Unification Contract
更新:2026-10-12。关联 D02、D06、D07、D08、D26、D40、RT-D41、D56。
Updated: 2026-10-22.
> 状态说明(2026-10-16):本文保留历史 `One Memory` / `one-memory` 合同名称。
> 对外产品名是 MemHub,记忆 SDK/引擎是 Hy Memory。本文中的跨平台目标不是当前支持
> 矩阵;Windows 不支持,其他平台是否受支持以对应 GitHub Release manifest 和
> 原生平台验收回执为准。当前发行合同以
> [`../INSTALLATION.md`](../INSTALLATION.md) 为准。
MemHub has one Runtime implementation, one data home, and one service identity
per installation. The macOS App, CLI, and Web UI are clients of that Runtime;
they do not own separate memory engines or databases.
## 目标
Platform support and release artifacts are defined by
[`../INSTALLATION.md`](../INSTALLATION.md).
One Memory 对外提供两种主要安装入口:
- macOS 图形 App;
- 设计目标中的跨平台 `one-memory` 兼容 CLI;当前公开入口和平台范围以安装文档为准。
二者不是两套产品。无论从哪个入口安装,最终都必须使用同一个 MemHub
Runtime、同一份用户数据、同一套权限语义,以及由 Hy Memory SDK 负责的
memory 数据面。
产品不变量是“一次安装、一个 Runtime、一份数据、多种客户端”。
## 分层
### Kernel / Core
Python/FastAPI Core 是 MemHub 管理面,负责来源授权、模型配置、异步写入队列、
SDK bridge、检索/问答 API 与 Runtime 协作。Memory/raw/vector/graph/coding
数据面由 Hy Memory SDK 管理。Core 不负责安装桌面窗口、修改宿主配置或注册操作系统服务。
## Components
### Runtime
Runtime 是可常驻的完整本地服务,由以下部分组成:
The long-running Node Runtime owns:
- SQLite,作为 MemHub 管理面数据库,由 Core 独占写入;
- Core;
- Host Gateway,包括 Recall Broker、Hook 通知和宿主授权校验;
- Runtime discovery、本地认证、版本与健康状态;
- Web Console 静态资源;
- 日志、升级、回滚和服务生命周期控制。
- one Python Core child;
- one loopback Recall Broker / Host Gateway sidecar;
- Runtime, Core, Broker, token, and lock receipts under the data home;
- Core restart supervision while Runtime remains alive;
- the packaged Web UI and local control surface.
Runtime 可以由图形 App 或 CLI 安装,但安装来源不得改变其数据合同和行为。
### Core
### CLI
Python/FastAPI Core is the MemHub management plane. It owns source grants,
model profiles, the durable SDK-call queue, configuration, diagnostics, and
Runtime coordination.
`one-memory` 是 Runtime 的命令行安装器、控制器和客户端。最终公开命令至少覆盖
`install/start/stop/restart/status/doctor/ui/logs/upgrade/uninstall`,并复用同一套来源、
模型和宿主授权合同。内部 Kernel 入口后续明确为 `one-memory-core`;迁移期间无参数
`one-memory` 继续兼容直接启动 Core。
Memory entities, raw conversations, vectors, graph data, coding memory, and SDK
cache/history belong to the Hy Memory SDK data plane. Core reaches that plane
through `HyMemoryBridge`; no product module may write SDK private stores or
maintain a second memory authority.
### Desktop
### Desktop and CLI
Electron 只提供图形安装、原生窗口、目录选择、系统展示偏好和 Runtime 客户端能力。
它不得拥有第二份数据库或第二套宿主授权语义。Desktop 启动时先发现并连接已有
Runtime;只有不存在可验证实例时才启动或安装 Runtime。关闭窗口默认不停止独立
Runtime。
Electron provides native windows, directory selection, display preferences,
and managed installation. It discovers and attaches to the Runtime.
### Web Console
The `memhub` CLI installs, starts, stops, upgrades, diagnoses, and removes the
same Runtime. `one-memory` remains a compatibility command where required by
existing installations.
React UI 保持一套。Electron 与浏览器分别通过受约束的 Control Client 使用同一
Runtime 合同。浏览器不得长期持有裸 Core token;正式独立 Web Console 采用一次性
本地登录换取 HttpOnly、SameSite=Strict 的 loopback session。
Closing the UI does not stop a service-managed Runtime.
## 安装等效定义
## Data home
“App 与 CLI 等效”表示:
1. 同平台、同架构、同版本消费同一个 Runtime artifact;
2. 使用同一 One Memory Home、数据库 schema 和迁移;
3. 使用同一 Core API、Host Gateway 和授权合同;
4. 同一数据目录最多一个写入 Runtime;
5. App 能连接 CLI 已启动的 Runtime,CLI 也能管理 App 安装的 Runtime;
6. 来源、模型、宿主三类授权仍然独立;
7. 升级、撤权、删除和回滚结果不因安装入口不同而变化。
等效不表示每个平台可用宿主完全相同。macOS、Linux、Windows 必须按真实支持矩阵
展示来源和宿主能力;fixture 或跨平台分支测试不能替代真机结论。
## One Memory Home
默认逻辑位置保持 `~/.one-memory`,可由 `ONE_MEMORY_DATA_DIR` 覆盖。它是数据实例,
不是某个 App 版本的私有目录。正式目录合同逐步收敛为:
The default data home is `~/.one-memory`, overridable with
`ONE_MEMORY_DATA_DIR`.
```text
One Memory Home/
data/ # one-memory.sqlite3、HY 数据与派生索引
migrations/ # SQLite schema 升级回执与备份索引
runtime.json # 无秘密的运行实例发现回执
runtime-token # 当前实例短生命周期本地凭据
host-permissions/ # 宿主安装身份和授权
integrations/ # Broker discovery
one-memory.sqlite3 # MemHub management database
config.json # desired user settings
hy-memory/ # SDK-owned data-plane stores
backups/ # verified migration bundles
runtime.json # non-secret discovery receipt
runtime-token # owner-only local credential
host-permissions/ # host installation identity and grants
integrations/ # Broker discovery
logs/
```
MemHub SQLite 是管理面权威,保存任务调度、cursor、配置、权限、审计和必要的
`memory_id` 引用,不保存 memory 实体或原始对话正文。Memory、raw、向量、图和
coding stores 由 Hy Memory SDK 管理。Adapter 可只读宿主自身文件,写入目标是 SDK。
Runtime 负责数据目录单写、管理库 schema 升级、WAL、备份恢复、磁盘预算和卸载保留
数据。MemHub 管理库不并行维护 MySQL 双写;SDK 自身可选 backend 不受此限制。
MemHub SQLite stores management state and necessary SDK IDs, not memory bodies
or raw conversation authority. SDK backend selection is controlled only by SDK
configuration and environment variables.
`runtime.json` 不得包含 token。`runtime-token` 必须是 owner-only,实例退出时删除;
Windows 在正式支持前必须实现并真机验证用户 SID/DACL,不能靠忽略 POSIX mode 过关。
## Runtime discovery and authentication
## Runtime discovery v1
Discovery receipts contain no secrets and identify the service, instance, PID,
loopback host, port, and start time. A client may attach only when:
当前第一批先把 Core 的 receipt 升级为可供可信本地客户端连接的最小合同。POSIX
平台同时发布 owner-only token;Windows 在 SID/DACL 实现和真机验证前不发布 attach
token,因此本批 Windows 仍只能使用启动方直接持有的凭据,不能声称 CLI/App attach:
- receipt schema and service identity are recognized;
- the host is exact loopback and the port is valid;
- the owning process is alive;
- the owner-only token is readable;
- health reports the same service and instance ID.
```json
{
"schema_version": 1,
"service": "one-memory-core",
"instance_id": "...",
"pid": 1234,
"parent_pid": null,
"host": "127.0.0.1",
"port": 8765,
"started_at": "..."
}
```
If a live process cannot be verified, the client fails closed. It must not kill
the process, claim the data home, overwrite receipts, or fall back to anonymous
access.
连接方必须同时满足:receipt schema/service 正确、host 是精确 loopback、端口有效、
PID 仍存活、owner-only token 可读、health 的 service 与 instance ID 匹配。任一失败都
不得把任意 loopback 服务当作 One Memory。若进程仍活但身份无法验证,必须显式失败,
不能杀进程、接管数据目录或退回匿名访问。
Browser access uses a constrained loopback session. It does not expose a
general-purpose Core bearer token.
## 第一批开发范围
## Service ownership
真实链路:
One service owner is recorded as `app` or `cli`.
```text
CLI/终端启动 Core
-> Core 锁定 One Memory Home
-> 写 runtime-token 和 runtime.json
-> Desktop 读取并验证 receipt/token/health
-> Desktop attach 同一 Core
-> Desktop 退出
-> 独立 Core 继续运行
```
- macOS uses one user LaunchAgent for both App- and CLI-managed installs.
- Linux uses a systemd user service where supported.
- Windows is not supported until its service lifecycle and SID/DACL security
are implemented and validated on native hardware.
本批改变:
App deletion removes only an App-owned enable marker. CLI-owned services remain
under CLI control. Runtime uninstall and data deletion are separate,
explicitly confirmed operations.
- 记录统一 Runtime 分层和后续实施路线;
- Core 发布无秘密 discovery receipt 与 owner-only 短生命周期 token;
- Desktop 在 spawn 前尝试连接同一数据目录的可验证 Core;
- Desktop 只停止自己启动的 Core。
## Installation and upgrade
本批不改变:
All installers consume the same immutable Runtime artifact and release
manifest for a platform, architecture, version, and commit. Installation:
- HY、Governance、Evidence、数据库 schema 和来源权限;
- Host Gateway 仍在 Electron 内的现状;
- 日常安装包、真实宿主配置和用户资料;
- Linux/systemd、macOS LaunchAgent、Windows 用户服务;
- Runtime 托管 Web Console 和浏览器 session;
- 发布、签名、自动更新和公开下载。
1. validates the manifest and every file hash;
2. stages a complete version directory;
3. atomically switches the managed `current` pointer;
4. installs the managed CLI link and user service;
5. starts the Runtime and verifies Runtime/Core/Broker identity;
6. rolls back files and pointers created by the failed transaction.
## 第一批失败测试与完成标准
Upgrade installs a new immutable version and switches only after validation.
Health-check failure restores the previous version. Binary rollback is not data
rollback; post-cutover data compatibility follows
[`sdk-data-plane-migration-v1.md`](sdk-data-plane-migration-v1.md).
1. Core receipt 不含 schema/service 或 token 文件权限不安全时测试失败。
2. Desktop 面对健康且实例匹配的独立 Core 时若仍 spawn,测试失败。
3. receipt 指向非 loopback、死 PID、缺 token 或 health 实例不匹配时不得 attach。
4. Desktop attach 后调用 stop 不得向独立 Core 发信号。
5. Desktop 自己启动的 Core 仍须在退出时优雅停止并保持原孤儿恢复行为。
6. Core runtime、Desktop supervisor 定向测试、类型和格式检查通过。
## Single-writer and lifecycle rules
本批只能标记为 `implemented` / 自动合同 `verified`。没有实际 CLI 进程与打包 App 的
同库联测时不能标记 `accepted`,更不能称跨平台一键安装完成。
- One data home has at most one Runtime and one Core writer.
- Runtime owns Core/Broker startup and shutdown ordering.
- Electron and CLI attach only after identity validation.
- A client stops only a Runtime it is authorized to control.
- Uninstall removes managed services, Runtime versions, and links but preserves
user data by default.
- `memhub delete-data` requires the Runtime to be stopped and exact-path
confirmation.
## 后续阶段
## Acceptance
### R2:Runtime Supervisor
A supported release verifies:
把 Recall Broker、HostPermissions、来源变化通知和 runtime discovery 从 Electron 移到
独立 Runtime Supervisor。App 退出后宿主召回和持续同步仍可用。
R2前两切片已经建立 `packages/runtime-control`:统一解析无秘密receipt、校验owner-only
token、验证独立进程和受保护identity,并承载Core启动、attach、孤儿恢复和停止语义。
Desktop只保留App资源路径与数据目录选择并消费该包;Host Gateway和宿主权限仍未迁出
Electron。
R2第三切片增加不依赖Electron的`RuntimeSupervisor`组合器,顺序启动或attach Core后再
启动sidecar,sidecar失败时释放本次Core所有权,停止时统一收口两者。Desktop已用它
组合现有Recall Broker。Broker进程目前仍和Electron同进程,故这一步是可迁移的生命周期
边界,不是后台常驻已完成。
R2第四切片已把HostPermissions、同步Hook资产校验与来源变化处理器迁入
`packages/runtime-control`,Desktop原路径只保留兼容re-export,以维持既有IPC测试和调用
边界。权限receipt、安装事务、确认指纹、撤权和Hook回滚语义不变;Windows仍因缺少
SID/DACL实现而明确拒绝宿主授权控制。
R2第五切片增加`RecallBrokerSupervisor`:若同一Runtime实例已有存活且health匹配的Broker,
客户端只attach且退出不停止它;缺失、stopped或死PID才创建新Broker;活着但属于其他
instance或无法验证时失败关闭,不能覆盖discovery或启动第二个Broker。Desktop已通过
`RuntimeSupervisor`组合该层。
R2第六切片增加内部`one-memory-runtime`前台入口和外层`runtime-service.json`/租约。该
进程取得One Memory Home单实例租约后,依次构造HostPermissions、启动Core与Broker并
发布外层身份;SIGINT/SIGTERM时清理Core receipt/token、外层receipt与租约,Broker留下
明确stopped回执。Desktop只在外层PID、Core parent PID、instance和port一致且两进程存活
时attach parent-owned Core;普通另一Desktop子进程仍不接管。该入口尚未注册系统服务。
R2第七切片把`packages/runtime-control/dist`加入Desktop正式资源清单,并让Desktop build
先构建Host Bridge与Runtime Control。安装包因此将同时携带同版本Core、Host Bridge、Web
和`runtime/runtime.cjs`;当前Desktop启动逻辑仍以内嵌模式运行,未在未定义安装/升级/
卸载事务前擅自注册或切换后台服务。
R2第八切片使打包Desktop默认执行共享launcher:先验证现有外层Runtime,缺失时以
Electron Node模式detached启动同包`runtime/runtime.cjs`,等待外层receipt、Core token和
identity全部成立后再进入原Desktop attach流程。退出Desktop只detach,不停止外部Runtime。
开发模式及显式`ONE_MEMORY_DESKTOP_RUNTIME_MODE=embedded`保留旧的进程内组合模式,作为
开发与故障回退;这仍不是登录自启或操作系统服务安装。
### R3:完整 CLI 与服务管理
实现统一命令,增加 macOS LaunchAgent、Linux systemd user service、无 systemd 的
前台模式和 Windows 当前用户登录启动方式。停止/卸载与删除数据必须分开确认。
R3第一切片已实现只读`service-plan`:根据明确的platform、home和install root生成macOS
LaunchAgent或Linux systemd user service的文件内容、目标路径和参数数组,不写文件也不
执行命令。macOS缺uid时blocked;Windows在SID/DACL和当前用户启动机制真机验证前始终
blocked。后续apply必须消费同一plan并进行原子写入、预览确认、失败回滚和当前状态复核。
R3第二切片已建立`apps/cli`,产出公开`one-memory`命令并直接复用Runtime Control的
serve/status/doctor/service-plan;Python包新增`one-memory-core`正式Kernel入口,旧Python
`one-memory`暂时兼容。发行时只应把Node CLI暴露为用户命令,避免两个实现争用命令名。
R3第三切片增加公开CLI的start/stop/restart。start只启动显式安装布局中的Runtime entry,
并等待外层receipt、Core token和identity全部验证;stop在相同验证完成后仅向外层Runtime
PID发送SIGTERM,并等待父进程及外层/Core receipt、token清理;身份不匹配时不发信号。
restart严格串行stop与start,避免旧Core尚在退出时抢同一数据目录。
R3第四切片把公开`cli/one-memory.cjs`加入Desktop的正式extraResources,并让Desktop build
先构建Host Bridge、Runtime Control和CLI。产物哈希清单必须同时覆盖CLI、Runtime、Core、
Host Bridge和Web;这保证Mac App携带的命令行入口与其后台Runtime来自同一源码构建,
但尚未自动把CLI链接到PATH。
R3第五切片增加CLI发行目录构建器:从已经构建的CLI、Node、Runtime、Core、Host Bridge
和Web资源组装固定目录,完整列出SHA-256 manifest,并使用stage目录后原子替换目标。
缺任一关键文件或存在越界符号链接时失败且保留旧发行目录。该构建器不下载artifact,
也不安装到用户目录。
R3第六切片增加共享的本地发行安装事务和公开CLI `install`。默认只输出经manifest、目标
平台/架构、完整文件集合和逐文件SHA-256核验后的plan;只有显式`--yes`才复制到
`versions/<version-platform-arch>`并原子切换`current`。版本/arch字符、源与安装根重叠、
越界链接、被调用方修改的plan、已有非托管current、同版本不同内容都会拒绝。现阶段不
下载artifact、不删除旧版本、不写PATH或服务文件。
R3第七切片增加`service-install`两阶段操作:默认只展示`planUserService`,显式`--yes`
后才要求当前平台一致、Runtime/Core/Host Bridge/Hook关键文件齐全、服务目录安全且目标
文件不存在,再以0600写入并按参数数组调用服务管理器。失败时只删除本次新建的文件,
不猜测并禁用可能早已存在的同名服务;潜在管理器残留由doctor后续报告。已有服务升级
与卸载另行实现。
R3第八切片增加`service-uninstall`两阶段操作:默认只预览,显式`--yes`后先逐字核对现有
服务文件与当前plan,完全一致才执行bootout/disable并删除;用户修改或其他工具创建的
同名文件一律拒绝。卸载服务不删除`versions/current`或One Memory Home,数据删除必须是
另一条明确操作。
R3第九切片将首次`install`组合成单一事务:同一预览同时返回发行目录和用户服务计划;
显式`--yes`后先安装版本并切换current,再首次注册服务。服务步骤失败时仅在current仍
指向本次版本的前提下恢复旧指针,并删除本次新建的版本目录。apply再次验证源manifest
与计划,拒绝调用方篡改、源/目标重叠、路径逃逸和非托管current。当前不支持覆盖已有
服务文件,也不自动清理旧版本或数据。
R3第十切片把受管CLI入口加入同一事务:POSIX默认`~/.local/bin/one-memory`指向
`<install-root>/current/bin/one-memory`,可用`--bin-dir`覆盖。普通文件、指向其他目标的
链接和不安全目录都拒绝覆盖;已正确链接时幂等。服务注册失败按逆序删除本次新建链接、
恢复旧current和本次版本。Windows PATH安装仍blocked。
R3第十一切片修正发行目录POSIX launcher:命令从PATH符号链接调用时逐层解析自身真实
位置,再执行同一发行目录`bin/node`与`bin/one-memory.cjs`。真实临时符号链接执行测试
必须产生bundled Node路径,不能只凭exit 0判断成功。
R3第十二切片使发行目录中的公开CLI可自定位安装源,并提供平台默认安装根:macOS为
`~/Library/Application Support/One Memory`,Linux为`~/.local/share/one-memory`,Windows
为`LOCALAPPDATA/One Memory`或用户目录回退。显式source/install-root/home仍可用于隔离和
企业部署;Windows apply继续受既有ACL门禁阻止。
R3第十三切片增加`upgrade`两阶段事务:要求现有CLI入口仍精确指向受管current、服务
文件与当前plan逐字一致,才安装并切换新版本后执行服务restart。restart失败时恢复旧
current、删除本次新版本并尽力重新启动旧版本;不重写服务文件、不删除数据或旧版本。
### R4:独立 Web Console
由 Runtime 提供同源 Web 静态资源和本地 session;补 Browser Control Client,使 CLI
安装后可通过 `one-memory ui` 使用完整界面。
### R5:Desktop 薄壳
Desktop 只做 discover -> verify -> attach;缺 Runtime 时走共享安装器。App 与 CLI 使用
相同 release manifest 和 Runtime artifact hash。
### R6:跨平台发行与真机验收
分别构建 macOS arm64/x64、Linux x64/arm64、Windows x64;完成权限存储、来源读取、
服务生命周期、升级回滚和宿主调用真机矩阵。Docker 是 Linux/NAS/CVM 的额外部署形态,
不能取代桌面用户级 CLI 安装验收。
- App and CLI attach to the same data home and Runtime;
- duplicate Runtime/Core startup is rejected;
- receipts, tokens, and loopback identity fail closed when invalid;
- Runtime survives UI exit and restarts Core when appropriate;
- install and upgrade rollback preserve the prior working version;
- uninstall preserves data and delete-data requires separate confirmation;
- artifacts and service behavior pass native-platform acceptance.
@@ -28,7 +28,8 @@ After the cutover marker is committed:
dropped before the normal App window is revealed;
- startup must not fall back to legacy authority because an SDK read failed.
The marker, not table existence, selects the authority.
The surviving `memory_authority_state` singleton, not legacy table existence,
selects the authority.
### Fresh install
@@ -62,9 +63,9 @@ the same SDK SQL table families (`memory_operations_v2`, `pipeline_logs_v2`,
by inspected schema/store capabilities, not one branch per historical SDK pin.
The old SDK version is informational only and is not a migration discriminator.
The migration Runtime itself must expose the required APIs (currently the
`2.0.5.dev3` development preview); old data is not rejected merely because an
earlier App wrote it.
The migration Runtime itself must expose the required APIs. Its exact SDK
version is defined by the release lockfiles; old data is not rejected merely
because an earlier App wrote it.
## 3. Legacy-state classification
@@ -91,7 +92,7 @@ An unclassified item blocks cutover.
## 4. User edits, deletion and supersession
The target product has no MemHub revision history or Undo.
The current product has no MemHub revision history or Undo.
- The latest non-deleted user correction is imported as the current SDK body.
- Historical `governed_memory_versions` remain in the compatibility backup, but
@@ -141,22 +142,26 @@ The bundle is published only after an isolated restore verifies hashes, counts
and SDK reads. A remote backend without a supported snapshot/export mechanism
blocks migration; SQLite-only backup is not reported as success.
## 7. Durable migration ledger
## 7. Authority state and migration ledger
The MemHub management database owns operational migration tables:
The MemHub management database owns:
- `memory_authority_state`: the surviving singleton authority and migration ID;
- `sdk_data_plane_migrations`: one run, source/target fingerprints, bundle,
phase, cutover state and reconciliation digest;
- `sdk_data_plane_migration_items`: source identity/revision/hash, target SDK
identity/hash, deterministic operation key, state, attempts and error code;
- `memory_id_aliases`: historical ID to canonical SDK ID for call-events,
task receipts and links.
- `memory_id_aliases`: temporary historical ID to canonical SDK ID mapping for
call-events, write-job receipts, and links;
- `raw_id_aliases`: legacy Evidence ID/item index to canonical SDK raw ID.
- `sdk_data_plane_cutover`: the singleton authority marker and immutable
- `sdk_data_plane_cutover`: a temporary detailed cutover receipt containing
SDK/backend/bundle/reconciliation fingerprints.
Progress is committed only after SDK verification. Retrying an item uses the
same deterministic SDK operation key and must not create another memory.
Before cleanup, every surviving reference is rewritten to its canonical SDK
ID. Alias, item-ledger, and detailed cutover tables are then dropped; the
authority singleton and verified bundle remain.
## 8. Queue and unknown outcomes
@@ -174,14 +179,15 @@ Queue rows and leases remain MemHub management state.
- `memory_write_jobs.hy_invoked=1`, `state=unknown`, or any non-terminal SDK
outcome must use `get_write_outcome(request_id)`.
- `running`/`unknown` is not absence and must not be replayed.
- confirmed SDK IDs become task receipts; Governance publication is not part of
- confirmed SDK IDs become write-job outcomes/receipts; Governance publication is not part of
completion after cutover.
## 9. Call events and session delivery
- Matter was an unpublished placeholder. Its rows are not migrated and every
`matter*` table is deleted during cleanup.
- Historical IDs remain resolvable through `memory_id_aliases`.
- Before cleanup, historical IDs resolve through `memory_id_aliases`; surviving
records are rewritten to canonical SDK IDs before that table is dropped.
- `call_events` remains metadata-only; reference titles/content resolve through
SDK APIs.
- Evidence-based session inbox/outbox is disabled at cutover unless replaced by
@@ -213,8 +219,9 @@ Cutover requires:
- deterministic full-ID get verification;
- a verified full migration bundle.
The final transaction writes an immutable marker with migration ID, SDK/store
version, namespace/backend fingerprint, bundle ID, digest and completion time.
The final transaction writes the detailed cutover receipt and changes
`memory_authority_state` to SDK authority. Cleanup may remove the detailed
receipt after bundle verification; the authority singleton remains.
After that transaction, legacy memory/raw writes are rejected.
@@ -5,9 +5,9 @@ After cutover, Host Bridge uses SDK-native Context v2. The two schemas are
validated and returned independently; SDK data is never fabricated into v1
revision or Evidence fields.
## Frozen Integration Surface
## V1 compatibility surface
- New `POST /api/v1/context/search`; proposed host tool `om_context` consumes it.
- `POST /api/v1/context/search`; the host tool `om_context` consumes it.
Existing recall/conversations tools retain their permission and response shape.
- Pydantic source of truth: `context_models.py`. Request has query, kinds,
**raw_source_ids**, total limit, character_budget and timeout_ms. The renamed
+1 -1
View File
@@ -64,7 +64,7 @@ Core 会:
3. 停止 claim Job 表中尚未开始的 Job;这些 Job 保持原状态,等待下次打开;
4. 不再通过 Adapter 扫描新 Session;
5. 已经 running 的少量 Job允许执行完,不强杀;
6. Harness Hook/Plugin 后续即使继续调用 Capture,Core 也会因为同步关闭而拒绝入库;
6. Harness Hook/Plugin 后续即使继续调用 Capture,Core 也会因为同步关闭而拒绝进入 SDK 写入路径;
7. 已经生成的 Memory 不删除,仍可被 Search 和 Recall 使用。
关闭同步开关不会卸载 MCP、Skill、Hook 或 Plugin,也不会撤销 Harness 查询记忆的 Credential。那些属于“一键插入应用”开关。