# Shared Memory [中文](README.md) | English A **cross-session, cross-app, cross-platform memory layer** (packaged as a DeepSeek Harness plugin today) that gives every session — and every other AI app — one shared memory: the user's messages, long-term preferences, ongoing projects, and "what I'm working on right now". - Shape: **Harness Host plugin** + **zero-dependency MCP stdio bridge** + **reusable agent skill** - Storage: `~/.dsh/shared-memory/` - Package / loader row: `@local/shared-memory` / `shared-memory` - Version: 1.6.2 · License: MIT > The Chinese name is now **AI 跨平台记忆增强 1.0**; the English name stays **Shared Memory**. Internal identifiers (package, skill id, store path) are unchanged for compatibility. > **Not just a skill.** An agent skill is only the client-side adapter that teaches WorkBuddy (or any skill-aware agent) to call the plugin's local HTTP API. The memory service itself is the Harness plugin; other apps connect through the MCP bridge or HTTP. ## Architecture ```mermaid flowchart LR subgraph Apps["Other AI apps"] WB[WorkBuddy
skill + curl] CUR[Cursor
MCP stdio] CDX[ChatGPT Codex
MCP stdio] CL[Claude Desktop / Code
MCP stdio] end subgraph DSH["DeepSeek Harness process"] EV[Session events
session/event] PLUG[Shared Memory plugin
SharedMemoryStore] PROMPT[systemPrompt digest
order 700, per step] TOOLS[memory_* tools] HTTP[HTTP API
/dsh-memory] MCP[MCP bridge
mcp-server.mjs] end STORE[(~/.dsh/shared-memory
memories.jsonl · focus.json · activity.json)] EV --> PLUG PLUG <--> STORE PLUG --> PROMPT TOOLS --> PLUG WB --> HTTP CUR --> MCP CDX --> MCP CL --> MCP MCP --> HTTP HTTP <--> PLUG PROMPT --> LLM[Model request] ``` A hand-drawn version lives at [docs/assets/architecture.svg](docs/assets/architecture.svg). ## Demo ```text $ node ~/.dsh/shared-memory/mcp-server.mjs # MCP initialize -> tools/call memory_status Shared memory service is running (dsh-shared-memory v1.1.0) Address: http://127.0.0.1:57545/dsh-memory (source: runtime.json) Store: /Users/you/.dsh/shared-memory Stats: 34 memories / 18 captured messages / 3 sessions / focus: yes # tools/call memory_search { "q": "plugin" } Query "plugin": 3 matches, showing 3 - [project · 12 minutes ago] The shared-memory plugin now has a two-tier storage... - [note · 1 hour ago] First install failed because output.schema used the wrong... - [profile · 2 hours ago] User prefers concise answers and Chinese... ``` ## Repository layout ``` ├── index.js # Host plugin: capture / store / tools / prompt digest / HTTP API ├── cordis.patch.yml # bundle row + default config ├── mcp/server.mjs # zero-dependency MCP stdio bridge (copied to ~/.dsh/shared-memory/) ├── ui/index.html # browser viewer/editor (/dsh-memory/ui) ├── skills/shared-memory/ # reusable agent skill (WorkBuddy and friends) ├── docs/API.md # frozen HTTP / storage / MCP contract ├── docs/CONNECT-APPS.md # per-app setup guides ├── docs/HOW-IT-WORKS.md # design and data-flow notes ├── test/host-smoke.mjs # host-half integration test ├── test/mcp-smoke.mjs # MCP protocol smoke test (35 assertions) ├── locale/en.json · zh.json └── icon.svg ``` ## Two ways to run | Mode | Needs Harness | Capabilities | Best for | |---|---|---|---| | **Harness plugin** (default) | ✅ | auto-capture session messages, prompt digest, model tools, HTTP, MCP | day-to-day use inside DeepSeek Harness | | **Standalone hub** `standalone/server.mjs` | ❌ | storage / search / focus / HTTP / MCP (no auto-capture, no prompt digest) | Windows, Linux, servers, machines without Harness | Both use the same store (`~/.dsh/shared-memory/` by default) and the same `runtime.json`, so MCP client configs do not change. > ⚠️ Run only one of them per store directory — they share the single-writer assumption. ### Install into other AI apps ```bash npm run install-apps # detect Cursor / Claude Desktop / ChatGPT (Codex) / Claude Code / WorkBuddy (MCP + skill) and write configs npm run autostart # optional: open DSH at login so the memory service stays online ``` Running apps need one full `Cmd+Q` restart to pick up MCP config (app limitation). `npm run autostart:uninstall` removes the login item. ## Quick start (standalone hub, cross-platform) Requires Node.js ≥ 18, nothing else. ```bash git clone https://github.com/shadyyoung/dsh-shared-memory.git cd dsh-shared-memory node standalone/server.mjs # http://127.0.0.1:7400/dsh-memory ``` ## Install Prerequisites: DeepSeek Harness Desktop (Cordis plugin system, `plugin_manager`), Node.js ≥ 18. 1. Clone the repo: ```bash git clone https://github.com/shadyyoung/dsh-shared-memory.git ``` 2. Install the bundle with an absolute path: ``` plugin_manager: install_bundle target=/absolute/path/to/dsh-shared-memory ``` After installation, `Tool.listTools` should list `memory_remember`, `memory_search`, `memory_forget`, `memory_current`. 3. Connect other AI apps: see [docs/CONNECT-APPS.md](docs/CONNECT-APPS.md). The MCP bridge is `~/.dsh/shared-memory/mcp-server.mjs` and is materialized by the plugin on activation. 4. Optional: copy the skill into any skill-aware agent, e.g. WorkBuddy: ```bash mkdir -p ~/.workbuddy/skills/shared-memory cp skills/shared-memory/SKILL.md ~/.workbuddy/skills/shared-memory/ ``` ## What it does | Capability | Detail | |---|---| | Capture user messages | Listens to `session/event` `user/message` and writes a **short-term raw-message cache** (30-day retention by default; subagent/composed messages skipped) | | Current focus | One structured "what is the user doing now" document, updated automatically from substantive messages or explicitly by any app | | Session activity | Latest user/assistant message, message count, cwd and title per root session — visible across sessions | | Prompt digest | Injects `## Shared Memory` (≤1200 chars), fenced with ``, plus a **BM25 relevance** "related memories" section for the current topic | | Search | In-memory **BM25 inverted index** (CJK bigrams + latin words, tags indexed); `sort=relevance|newest` | | Model tools | `memory_remember` / `memory_search` / `memory_forget` / `memory_update` / `memory_restore` / `memory_current` | | Viewer / editor UI | `/dsh-memory/ui`: browse, search, edit, trash/restore, edit history, focus editor, **backup/restore**, JSONL export | | Automatic backup | Full gzipped snapshot every 24h to `~/.dsh/shared-memory-backups/` (keeps 14); manual backup + one-click restore | | Auto extraction | Pulls durable facts from user messages into a **pending inbox** (rules mode by default, free; `llm` mode optional) | | Import history | ChatGPT / Claude `conversations.json`, jsonl, txt/md → raw messages + candidate memories | | PII redaction | `sk-*`, `ghp_*`, `AKIA*`, Bearer, `password=`, ID numbers → `[reducted]` on write | | Doctor | `npm run doctor`: checks DSH service, MCP bridge, Cursor, Codex, Claude Desktop, WorkBuddy | | HTTP API | `http://127.0.0.1:/dsh-memory` (port from `runtime.json`) | | MCP bridge | `~/.dsh/shared-memory/mcp-server.mjs`, zero dependencies, stdio JSON-RPC | ## Two-tier memory | Tier | Kind | Retention | Purpose | |---|---|---|---| | Raw cache | `message` | 30 days (`messageRetentionDays`), max 3000 | recall recent exact words | | Durable | `profile / preference / goal / project / task / note` | forever (until `memory_forget`) | identity, preferences, decisions, projects, tasks, focus | Why: storage is cheap (a few thousand records ≈ ~1 MB), but prompt noise is not. Long-term memories are only what the model judged worth keeping. ## Storage format ``` ~/.dsh/shared-memory/ ├── memories.jsonl # one JSON record per line (single writer: the Harness process) ├── focus.json # current focus + next steps ├── activity.json # per-session recent activity ├── runtime.json # API base / port / token, used by the MCP bridge for discovery ├── mcp-server.mjs # MCP bridge ├── digest.md # human-readable snapshot └── token # only when apiToken is configured ``` Record: `{ id, kind, text, tags, source:{app,sessionId,cwd,title}, createdAt }`. ## Configuration Edit [cordis.patch.yml](cordis.patch.yml) and re-enable the bundle. | Field | Default | Description | |---|---|---| | `storeDir` | `~/.dsh/shared-memory` | storage directory | | `captureUserMessages` | `true` | capture root-session user messages (short-term cache) | | `messageRetentionDays` | `30` | raw-message retention; 0 = forever | | `promptDigest` | `true` | inject the digest into the system prompt | | `maxDigestChars` | `1200` | digest size cap | | `maxStoredMessages` | `3000` | raw-message count cap | | `maxActivitySessions` | `200` | session activity entries kept | | `apiEnabled` | `true` | register HTTP routes | | `apiPath` | `/dsh-memory` | route prefix | | `apiToken` | `""` | when set, `/api/*` requires `Authorization: Bearer ` | | `autoFocusMinutes` | `90` | auto-focus refresh interval; 0 disables | | `writeHumanDigest` | `true` | maintain `digest.md` | | `trashRetentionDays` | `30` | trash retention; 0 = keep forever | | `maxRevisions` | `20` | edit-history versions kept per memory; 0 = none | | `maxRelevantMemories` | `4` | related-memory lines in the digest; 0 = off | | `backupDir` | `~/.dsh/shared-memory-backups` | backup directory (outside the store by default; point it at iCloud/Dropbox if you like) | | `backupKeep` | `14` | number of backups kept | | `autoBackupHours` | `24` | automatic backup interval in hours; 0 = off | | `autoExtract` | `rules` | `off` / `rules` (free) / `llm` (model extraction) | | `extractModel` | empty | provider/model for LLM extraction; empty = default model | | `maxExtractPerDay` | `30` | daily LLM extraction budget | | `piiPolicy` | `redact` | `off` / `warn` / `redact` | ## Verify ```bash # service health (port from runtime.json) curl -s "$(node -e "console.log(require(process.env.HOME+'/.dsh/shared-memory/runtime.json').apiBase)")/health" # local tests, no running Harness required node test/host-smoke.mjs # tools, capture, prompt digest, HTTP API, auth node test/mcp-smoke.mjs # MCP protocol, 35 assertions node test/standalone-smoke.mjs # standalone hub + MCP bridge, no Harness needed ``` Verified on 2026-10-26 against DeepSeek Harness Desktop with Node 24: both suites pass; live HTTP `/health` OK; MCP `memory_status` / `memory_search` / `memory_current` read and write the same store; the digest is injected into the system prompt. ## Known limitations - No Web UI panel: inspect or edit via tools, HTTP, `digest.md`, or the JSONL directly. - The HTTP service lives inside Harness: when Harness is closed the bridge returns a readable "service is not running" error and recovers automatically. - Local-only by default; set `apiToken` before exposing it beyond loopback. - Memory is plaintext JSONL and contains raw user messages; use `captureUserMessages: false` if that is not acceptable. - Plain ChatGPT chat / web cannot connect to a local stdio MCP server (remote Connector only). ## License MIT