From b94505244d3e47c929a3a03a56fec4a8eba1a905 Mon Sep 17 00:00:00 2001 From: Cloudy Date: Tue, 14 Jul 2026 11:51:51 +0800 Subject: [PATCH] docs(integrations): make Raft canonical --- README.md | 2 +- integrations.json | 11 ++++++----- nowledge-mem-codex-plugin/README.md | 2 +- nowledge-mem-codex-plugin/hooks/nmem-stop-save.py | 2 +- .../tests/test_codex_plugin.py | 4 ++-- shared/behavioral-guidance.md | 5 +++-- tests/plugin_e2e/test_key_plugins_e2e.py | 13 ++++++++----- 7 files changed, 22 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index b0d003f6..be944cab 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ Each directory is a standalone integration. Pick the one that matches your tool. | **[Windsurf Trajectory Extractor](https://github.com/jijiamoer/windsurf-trajectory-extractor)** | `git clone https://github.com/jijiamoer/windsurf-trajectory-extractor.git` | Offline protobuf extraction for Windsurf Cascade conversation history. | | **[Cursor Plugin](nowledge-mem-cursor-plugin)** | Link `nowledge-mem-cursor-plugin` into `~/.cursor/plugins/local/nowledge-mem-cursor` | Cursor-native plugin package with session-start context guidance, bundled MCP config, rules, and honest `save-handoff` semantics. | | **[Codex Plugin](nowledge-mem-codex-plugin)** | `codex plugin marketplace add nowledge-co/community --sparse .agents --sparse nowledge-mem-codex-plugin` then `codex plugin add nowledge-mem@nowledge-community`; enable `plugins` and `hooks`, run setup, then trust the hooks when Codex asks | Native startup context and memory routing, bundled MCP retrieval and writes, plus Stop-hook capture of real Codex sessions. Coexists cleanly with Codex local Memory. | -| **Raft (formerly Slock)** | Configure per-worker environment variables in Raft runtime config | Install the child runtime connector, set `NMEM_AGENT_ID=` per worker, and use Mem skills/MCP inside Raft. Raft-managed Codex rollouts are execution traces and are excluded from Codex Thread capture. | +| **Raft** | Configure per-worker environment variables in Raft runtime config | Install the child runtime connector, set `NMEM_AGENT_ID=` per worker, and use Mem skills/MCP inside Raft. Raft-managed Codex rollouts are execution traces and are excluded from Codex Thread capture. | | **Lody** | Configure the child runtime in Lody Agent Config | Runtime launcher setup: install the child runtime connector first; set `NMEM_AGENT_ID=` only when that Agent Config represents a stable role. | | **Multica** | Configure the Multica agent MCP settings and custom environment | Multi-agent orchestrator setup: install the child runtime connector first; for Claude Code agents, save the Mem MCP config on the Multica agent; then set `NMEM_AGENT_ID=` in custom env. | | **Cumora** | Configure the child runtime plus each teammate persona | AI teammate workspace setup: connect Mem at the runtime/daemon boundary, then use a per-persona Context Bundle instruction unless Cumora exposes per-agent runtime environment variables. | diff --git a/integrations.json b/integrations.json index 2dd6cb47..93485dc9 100644 --- a/integrations.json +++ b/integrations.json @@ -11,7 +11,7 @@ "claude-code", "grok", "codex-cli", "cursor", "gemini-cli", "copilot-cli", "openclaw", "hermes", "droid", "alma", "bub", "pi", "opencode", "craft-agent", "workbuddy", "codebuddy", "kimi-code", "kimi-work", "zcode", "mimo-code", "omp", "claude-desktop", "proma", - "slock", "lody", "multica", "cumora", "paseo", "mcp-direct" + "raft", "lody", "multica", "cumora", "paseo", "mcp-direct" ], "doesNotApplyTo": ["browser-extension", "raycast", "antigravity-extractor", "windsurf-extractor"] }, @@ -284,8 +284,9 @@ "slashCommands": [] }, { - "id": "slock", - "name": "Raft (formerly Slock)", + "id": "raft", + "aliases": ["slock"], + "name": "Raft", "category": "orchestrator", "type": "orchestrator", "version": null, @@ -318,12 +319,12 @@ }, "install": { "command": "Connect the AI tool Raft launches, then set NMEM_AGENT_ID= in each Raft agent runtime config.", - "detectionHint": "Running inside a Raft-managed child agent (legacy originator: slock-daemon)", + "detectionHint": "Running inside a Raft-managed child agent (originator: raft-daemon; legacy alias: slock-daemon)", "agentGuide": { "prompt": "Read https://mem.nowledge.co/SKILL.md and follow the Raft path to configure this worker. Connect the AI tool Raft launches first, then set NMEM_AGENT_ID=; add NMEM_SPACE only if this whole worker should override its default space. Use Mem skills or MCP inside Raft. Do not save the managed Codex rollout as the Raft conversation. Verify with nmem status and the Context Bundle or Working Memory check, then summarize what changed.", "promptZh": "读取 https://mem.nowledge.co/SKILL.md,并按 Raft 路径配置这个 worker。先连接 Raft 启动的 AI 工具,再设置 NMEM_AGENT_ID=;只有当整个 worker 需要覆盖默认 Space 时,才添加 NMEM_SPACE。在 Raft 内使用 Mem skills 或 MCP,不要把托管 Codex rollout 当作 Raft 对话保存。用 nmem status 和 Context Bundle 或 Working Memory 检查验证,然后总结你改了什么。" }, - "docsUrl": "/docs/integrations/slock" + "docsUrl": "/docs/integrations/raft" }, "toolNaming": { "convention": "mediated-host", diff --git a/nowledge-mem-codex-plugin/README.md b/nowledge-mem-codex-plugin/README.md index 8310b931..0030a434 100644 --- a/nowledge-mem-codex-plugin/README.md +++ b/nowledge-mem-codex-plugin/README.md @@ -143,7 +143,7 @@ This enables Codex lifecycle hooks, adds the legacy plugin-hook gate only on hos Restart Codex after setup. Codex treats **enabled** and **trusted** as separate hook states: review and trust the three Nowledge Mem hooks when Codex prompts you. This confirmation is deliberately user-owned; the installer never bypasses Codex's hook security boundary. -Raft (formerly Slock) can run a managed Codex worker on the same computer as your normal Codex sessions. The hook reads Codex's structured `session_meta.originator` for each transcript: normal Codex sessions still capture automatically, while `slock-daemon` and `raft-daemon` rollouts are skipped because they contain Raft inbox/control traffic rather than the human-visible conversation. Memory skills and MCP remain available inside the Raft worker. +Raft can run a managed Codex worker on the same computer as your normal Codex sessions. The hook reads Codex's structured `session_meta.originator` for each transcript: normal Codex sessions still capture automatically, while `raft-daemon` rollouts are skipped because they contain Raft inbox/control traffic rather than the human-visible conversation. The legacy `slock-daemon` originator remains supported. Memory skills and MCP remain available inside the Raft worker. To backfill older Codex sessions, preview first: diff --git a/nowledge-mem-codex-plugin/hooks/nmem-stop-save.py b/nowledge-mem-codex-plugin/hooks/nmem-stop-save.py index f76f3955..a223733f 100644 --- a/nowledge-mem-codex-plugin/hooks/nmem-stop-save.py +++ b/nowledge-mem-codex-plugin/hooks/nmem-stop-save.py @@ -31,7 +31,7 @@ "unexpected argument '--json'", ) CODEX_HOOK_SUCCESS_RESPONSE = {"continue": True, "suppressOutput": True} -DELEGATED_CONVERSATION_ORIGINATORS = frozenset({"slock-daemon", "raft-daemon"}) +DELEGATED_CONVERSATION_ORIGINATORS = frozenset({"raft-daemon", "slock-daemon"}) MAX_SESSION_META_BYTES = 256 * 1024 _SCRIPT_DIR = Path(__file__).resolve().parent diff --git a/nowledge-mem-codex-plugin/tests/test_codex_plugin.py b/nowledge-mem-codex-plugin/tests/test_codex_plugin.py index d2398b7d..d86ae0a7 100644 --- a/nowledge-mem-codex-plugin/tests/test_codex_plugin.py +++ b/nowledge-mem-codex-plugin/tests/test_codex_plugin.py @@ -334,7 +334,7 @@ def _write_session_meta(self, originator: str) -> Path: return transcript def test_delegated_conversation_originator_is_session_scoped(self): - for originator in ("slock-daemon", "raft-daemon"): + for originator in ("raft-daemon", "slock-daemon"): transcript = self._write_session_meta(originator) self.assertEqual( self.module._delegated_conversation_originator( @@ -352,7 +352,7 @@ def test_delegated_conversation_originator_is_session_scoped(self): ) def test_main_skips_only_delegated_thread_capture_but_reports_skills(self): - transcript = self._write_session_meta("slock-daemon") + transcript = self._write_session_meta("raft-daemon") hook_payload = json.dumps( { "session_id": "session-1", diff --git a/shared/behavioral-guidance.md b/shared/behavioral-guidance.md index 1b6f7d10..ef7244cb 100644 --- a/shared/behavioral-guidance.md +++ b/shared/behavioral-guidance.md @@ -42,8 +42,9 @@ NMEM_AGENT_ID="reviewer" `NMEM_AGENT_ID` selects a Nowledge AI Identity directly. Add `NMEM_SPACE` only when the whole child process should override that identity's default space. `NMEM_HOST_AGENT_ID` is an advanced external-alias field for integration authors -who need to map an immutable external worker id such as `slock:` onto a -Mem AI Identity. Do not ask normal users to set both identity variables; if +who need to map an immutable external worker ID such as `raft:` onto a +Mem AI Identity. Existing integrations may still provide the legacy +`slock:` alias. Do not ask normal users to set both identity variables; if every child gets the same value, all agents will collapse into one profile. **When to use Context Bundle:** diff --git a/tests/plugin_e2e/test_key_plugins_e2e.py b/tests/plugin_e2e/test_key_plugins_e2e.py index d6b62e28..c652447e 100644 --- a/tests/plugin_e2e/test_key_plugins_e2e.py +++ b/tests/plugin_e2e/test_key_plugins_e2e.py @@ -1043,7 +1043,7 @@ def log_message(self, format: str, *args: Any) -> None: env["NMEM_API_URL"] = f"http://127.0.0.1:{server.server_address[1]}" env["NMEM_SPACE"] = "pi-history-space" env["NMEM_AGENT_ID"] = "PiHistoryAgent" - env["NMEM_HOST_AGENT_ID"] = "slock:PiHistoryAgent" + env["NMEM_HOST_AGENT_ID"] = "raft:PiHistoryAgent" result = _run( ["node", str(script), "--session-dir", str(session_dir), "--json", "--apply"], env=env, @@ -1068,7 +1068,7 @@ def log_message(self, format: str, *args: Any) -> None: assert create_body["metadata"]["analysis"] == "searchable-now-distill-on-demand" assert create_body["metadata"]["sync_reason"] == "history_sync" assert create_body["metadata"]["agent_id"] == "PiHistoryAgent" - assert create_body["metadata"]["host_agent_id"] == "slock:PiHistoryAgent" + assert create_body["metadata"]["host_agent_id"] == "raft:PiHistoryAgent" assert create_body["project"] == "/tmp/pi-history-project" assert create_body["workspace"] == "/tmp/pi-history-project" assert [message["content"] for message in create_body["messages"]] == [ @@ -1160,6 +1160,9 @@ def test_registry_connect_contract_points_agent_prompts_to_universal_skill(): assert "/docs/integrations/" not in guide["promptZh"], entry["id"] by_id = {entry["id"]: entry for entry in integrations} + assert "raft" in integration_ids + assert "slock" not in integration_ids + assert "slock" in by_id["raft"]["aliases"] assert by_id["copilot-cli"]["version"] == "0.1.4" assert by_id["gemini-cli"]["version"] == "0.1.9" assert by_id["cursor"]["version"] == "0.1.6" @@ -1378,7 +1381,7 @@ def test_pi_live_package_install_and_extension_smoke(tmp_path: Path): process.env.NMEM_API_URL = `http://127.0.0.1:${port}`; process.env.NMEM_SPACE = "pi-smoke-space"; process.env.NMEM_AGENT_ID = "PiSmokeAgent"; - process.env.NMEM_HOST_AGENT_ID = "slock:PiSmokeAgent"; + process.env.NMEM_HOST_AGENT_ID = "raft:PiSmokeAgent"; const handlers = new Map(); nowledgeMemPi({ on(event, handler) { handlers.set(event, handler); } }); @@ -1471,7 +1474,7 @@ def test_pi_live_package_install_and_extension_smoke(tmp_path: Path): throw new Error("space not propagated"); } if (create.body.metadata.agent_id !== "PiSmokeAgent") throw new Error("agent_id missing"); - if (create.body.metadata.host_agent_id !== "slock:PiSmokeAgent") { + if (create.body.metadata.host_agent_id !== "raft:PiSmokeAgent") { throw new Error("host_agent_id missing"); } if (create.body.messages.length !== 2) { @@ -1507,7 +1510,7 @@ def test_pi_live_package_install_and_extension_smoke(tmp_path: Path): assert "--agent-id" in context_call, f"context call missing --agent-id: {context_call}" assert "PiSmokeAgent" in context_call, f"context call missing agent id value: {context_call}" assert "--host-agent-id" in context_call, f"context call missing --host-agent-id: {context_call}" - assert "slock:PiSmokeAgent" in context_call, f"context call missing host agent id value: {context_call}" + assert "raft:PiSmokeAgent" in context_call, f"context call missing host agent id value: {context_call}" @pytest.mark.skipif(_skip_live_host("claude"), reason="Claude live E2E not requested")