# Install ai-memory in DeepSeek Harness (5 minutes) English. 中文:[INSTALL_DSH.zh-CN.md](INSTALL_DSH.zh-CN.md) One command adds this **repository root** as a dsh plugin. Long chats store turns in **Rust + SQLite** and inject a **token-budgeted** slice (`## Memory (project: …)`), not the full transcript. This is a Cordis Host over the `ai-memory` crate — **not** a TypeScript memory rewrite and **not** an auto-LLM “extract facts” plugin. --- ## 5-minute path (happy path only) Do these in order. Use the **same** profile name everywhere (`web` below). If step 3 fails with *Ignored build scripts*, that is expected the first time — do step 4, then re-run step 3. ### 1. Tools ```bash node -v # v20 or newer pnpm -v # dsh plugin add forwards to pnpm dsh --help # DeepSeek Harness CLI cargo --version # rustc 1.74+ (prepare compiles Rust) ``` Missing `dsh`? Install from [deepseek-ai/deepseek-harness](https://github.com/deepseek-ai/deepseek-harness) first. Missing `cargo`? [rustup.rs](https://rustup.rs/). ### 2. Pin a commit SHA ```bash git ls-remote https://github.com/zzjzzb/ai-memory.git refs/heads/main ``` **Expected** (SHA will differ; copy the **left** column, 40 hex characters): ```text f3ce0b5c1a2b3c4d5e6f7890aabbccddeeff0011 refs/heads/main ``` Call that value `COMMIT`. Paste it into the next command. Do not use floating `main` on a machine you care about. ### 3. Add the plugin ```bash dsh plugin --profile web add github:zzjzzb/ai-memory#COMMIT ``` Replace `COMMIT` with the SHA from step 2 (no `#` doubling). **Expected on success** (cargo takes a few minutes the first time; lines may interleave with pnpm): ```text [dsh-ai-memory] building ai-memory CLI (Rust source of truth)… [dsh-ai-memory] wrote bin/ai-memory [dsh-ai-memory] building napi addon… [dsh-ai-memory] wrote ai-memory.node (from libai_memory_node.so) [dsh-ai-memory] prepare: using napi (CLI also built) ``` macOS may say `libai_memory_node.dylib`; Windows `ai_memory_node.dll`. That is still success. **Napi fail-soft (still success):** if the addon fails but the CLI was written: ```text [dsh-ai-memory] napi crate build failed — plugin will use the CLI fallback if present [dsh-ai-memory] prepare: using CLI fallback (napi addon not built). Runtime still uses the Rust crate, not a JS store. ``` **Expected first-time failure (pnpm ≥10 blocked `prepare`):** ```text [ERR_PNPM_IGNORED_BUILDS] Ignored build scripts: dsh-ai-memory Run "pnpm approve-builds" to pick which dependencies should be allowed to run scripts. ``` dsh may also tell you to copy that package key into the profile `pnpm-workspace.yaml`. Go to step 4, then **re-run the exact add** from this step. ### 4. Allow `prepare` (only if step 3 printed Ignored build scripts) Profile file (create if missing): ```text ~/.dsh/profiles/web/pnpm-workspace.yaml ``` If you set `DSH_HOME`, use `$DSH_HOME/profiles/web/pnpm-workspace.yaml` instead. **Full file you can paste** when the file does not exist yet: ```yaml packages: - '.' allowBuilds: dsh-ai-memory: true ``` If the file **already exists**, add `allowBuilds` at the **top level** (sibling of `packages`, not nested inside it). Keep other keys. The package key must be exactly `dsh-ai-memory` (what pnpm printed), not the GitHub URL. Then re-run step 3’s add command (same `COMMIT`). Treat `allowBuilds` as permission to run this package’s install-time code on your machine, outside the agent sandbox. Official rule: [Package and install a plugin](https://deepseek-harness.github.io/deepseek-harness/en/develop/basic/publish). ### 5. Confirm the layer Use the **same** `--profile` as `plugin add`: ```bash dsh --profile web --dump-config ``` **Expected** (search for this heading; surrounding YAML can vary): ```text # == dsh-ai-memory ``` You should also see a plugin row like: ```yaml - id: dsh-ai-memory name: dsh-ai-memory config: projectId: dsh tokenBudget: 8192 policy: chat prefetchEnabled: true ``` If `# == dsh-ai-memory` is missing, the package is a plain dependency and the layer did **not** activate — see [Troubleshooting](#troubleshooting). Restart so the layer is composed: `dsh --profile web` or `dsh web`. ### 6. First use: remember one fact + budget pack Start dsh with `--profile web`. In a chat, paste this: ```text Call tool memory_remember with text "User prefers dark mode" and tier "profile". Then call tool memory_recall with text "dark mode". ``` The agent should invoke **these exact tool names**: | Step | Tool | Arguments | |------|------|-----------| | 1 | `memory_remember` | `{ "text": "User prefers dark mode", "tier": "profile" }` | | 2 | `memory_recall` | `{ "text": "dark mode" }` | Other crate tools (later): `memory_forget`, `memory_pin`, `memory_consolidate`, `memory_compact`. On the **next** model call, the system prompt should contain Cordis section `ai-memory:pack`, looking like: ```text ## Memory (project: dsh, 1 hits) - [profile id=mem-… score=…] User prefers dark mode ``` That is `prefetch_within_budget`, not the full chat. If you see the entire transcript instead, something else is dumping history — this plugin did not. No Web UI? [Flagship headless sim](#flagship-sim). --- ## What you installed (30 seconds) One long support session (sidebar bug, then a duplicate invoice) would blow past a ~1M (or smaller) window if you dumped the chat. This plugin: 1. Persists turns with `memory_remember` / `memory_pin`. 2. Injects `ai-memory:pack` from Rust `prefetch_within_budget` before the next model call. 3. Isolates by `projectId`. Two projects on one `.db` do not leak recall. Root `package.json` npm name is **`dsh-ai-memory`**. `Cargo.toml` crate name is **`ai-memory`**. Same repository. --- ## Prerequisites (if a check in step 1 failed) | Need | Why | Check | |------|-----|--------| | **Node.js 20+** | Plugin `engines`; wrong Node often fails to load `.node` | `node -v` | | **pnpm** | `dsh plugin add` = pnpm in the profile directory | `pnpm -v` | | **dsh CLI** | Writes the profile + bundle list | `dsh --help` | | **Git** | `github:zzjzzb/ai-memory` is a git fetch | `git --version` | | **Rust `cargo`** | `prepare` builds napi and/or the CLI | `cargo --version` (MSRV **1.74+**) | | **Network** | Public GitHub | [github.com/zzjzzb/ai-memory](https://github.com/zzjzzb/ai-memory) | `npx @deepseek-ai/dsh --help` is one way to get the CLI if it is not on PATH. You still need `pnpm` for `dsh plugin add`. A **profile** lives at `~/.dsh/profiles//` (or `$DSH_HOME/profiles//`). `web` is the usual UI profile; first `dsh plugin --profile web …` creates it. Local clone instead of GitHub: ```bash git clone https://github.com/zzjzzb/ai-memory.git cd ai-memory dsh plugin --profile web add . dsh --profile web --dump-config ``` Do **not** use `github:zzjzzb/ai-memory#path:integrations/dsh-ai-memory` as the user path — that git fetch does not include the Rust crate `prepare` must compile. --- ## Config knobs (copy-paste) Later layers win. A patch **replaces the whole `config` object** (no deep-merge). Edit the **profile** `cordis.patch.yml`, not this repo. ```yaml # ~/.dsh/profiles/web/cordis.patch.yml - insert: - id: dsh-ai-memory name: dsh-ai-memory config: dbPath: ~/.local/share/ai-memory/dsh.db projectId: sme-support tokenBudget: 8192 policy: chat prefetchEnabled: true sectionOrder: 40 # cliPath: /usr/local/bin/ai-memory ``` | Field | Default | Meaning | |-------|---------|---------| | `dbPath` | `~/.local/share/ai-memory/dsh.db` | SQLite file. Empty → `AI_MEMORY_DB` or that default. `:memory:` is for tests. | | `projectId` | `dsh` | Isolation key. Support vs HR need different ids. | | `tokenBudget` | `8192` | `prefetch_within_budget` cap (`ceil(chars/4)`). `256` matches the flagship sim. | | `policy` | `chat` | `chat` / `journal` / `default` — used when the project is **created**. | | `prefetchEnabled` | `true` | Register `ai-memory:pack`. | | `sectionOrder` | `40` | Prompt section order (persona is typically 0). | | `cliPath` | (auto) | Force the `ai-memory` CLI if napi `.node` did not load. | Do **not** insert a second `id: dsh-ai-memory` row on top of the bundle layer — duplicate `id` can crash boot. Override by `id` with **one** row as above. --- ## How this differs from me-too Memory plugins | Typical Memory plugin | This plugin | |----------------------|-------------| | Extra LLM call to auto-extract facts | Tools + **explicit** compact / consolidate | | JS/Python reimplementation of memory | **Rust crate** is the source of truth | | “Supports 1M-token prompts” | Stores the long session; **packs a slice** | | One global bag of facts | `projectId` isolation | --- ## Binding (napi vs CLI) 1. **napi-rs** — preferred. In-process `HostSession.dispatch`. 2. **`ai-memory` CLI** — same JSON envelope, subprocess, if `ai-memory.node` is missing or fails to load. `prepare` tries both and **succeeds if either exists**. Nothing reimplements recall in JavaScript. --- ## Flagship scenario (headless) Tickets **T-1042** (sidebar) and **T-1088** (duplicate invoice), pin Ada Chen, project `sme-hr` must not leak T-1042. ```bash cargo build --bin ai-memory node scenarios/dsh-support-agent/sim/run.mjs npm test --prefix scenarios/dsh-support-agent cargo test --test dsh_support_scenario ``` **You should see:** `tokens <= tokenBudget`; `## Memory (project: sme-support, …)`; tight pack still contains `PINNED-BILLING-OWNER-ADA`; `sme-hr` pack has **no** T-1042. Details: [scenarios/dsh-support-agent/README.md](../scenarios/dsh-support-agent/README.md). Map onto a real profile: same `github:zzjzzb/ai-memory#COMMIT` add, set `projectId: sme-support` in the profile patch, play [`seed/tickets.json`](../scenarios/dsh-support-agent/seed/tickets.json). --- ## Troubleshooting | Symptom | Likely cause | What to do | |---------|--------------|------------| | `Ignored build scripts: dsh-ai-memory` / `ERR_PNPM_IGNORED_BUILDS` | pnpm ≥10 blocked `prepare` | Paste [step 4](#allow-prepare) into the **profile** `pnpm-workspace.yaml`, re-run the **same** `add` | | `allowBuilds` set but add still ignores scripts | Wrong file / nested under `packages` / wrong key | File must be **that profile’s** `pnpm-workspace.yaml`. Key `dsh-ai-memory: true` at top level. Not `ignoredBuiltDependencies` | | `cargo: command not found` / `rustc` missing during prepare | No Rust toolchain | [rustup](https://rustup.rs/), then re-add. JS-only tests: `DSH_AI_MEMORY_SKIP_NATIVE=1` | | napi compile error, then `prepare: using CLI fallback` | Addon failed; CLI built | **OK.** Plugin uses the CLI. Confirm `--dump-config` still has `# == dsh-ai-memory` | | prepare: neither napi nor CLI produced | Both Rust builds failed | `rustc` **1.74+** (`rustup update`). Re-add. Check disk space | | `SyntaxError` / `Unexpected token` loading the plugin | **Wrong Node** | `node -v` must be **≥ 20**. Rebuild `.node` on this Node (`prepare`) | | `.node` present but `invalid ELF` / `wrong architecture` | Addon built on another OS/CPU | Rebuild on this machine. Or rely on CLI fallback (`bin/ai-memory`) / set `cliPath` | | `ai-memory CLI failed to start` | `.node` missing **and** CLI missing/not executable | `allowBuilds` + re-add, or `npm run prepare` in a clone. Look under the installed package for `ai-memory.node` and `bin/ai-memory` | | `dsh: command not found` | CLI not on PATH | Same environment that already runs `dsh web` | | Git 401 / `Repository not found` | Typo or private-fork credentials | Public spec is `github:zzjzzb/ai-memory`. `gh auth login` only for private forks | | `pnpm: command not found` | dsh plugin add needs pnpm | [pnpm.io/installation](https://pnpm.io/installation) | | `--dump-config` has **no** `# == dsh-ai-memory` | Layer not activated | You added **root** `github:zzjzzb/ai-memory`, not a subdirectory URL? `dsh plugin --profile web list`. Re-add after `allowBuilds`. Confirm root `package.json` has `dsh.bundle.patch` | | Added plugin but dump-config looks empty / old | **Profile name mismatch** | `dsh plugin --profile web add` then **`dsh --profile web --dump-config`**. Bare `dsh --dump-config` is a different profile. Typo `web` vs `Web` vs `default` | | Layer heading present, tools missing | Profile not restarted; inject failed | Restart `dsh --profile web`. Boot logs: cannot resolve `dsh-ai-memory` | | Duplicate loader `id: dsh-ai-memory` | Bundle layer **and** a manual insert | One path only: `dsh plugin add` **or** a manual patch row | | Empty memory / wrong tickets | Wrong `projectId` or `dbPath` | Default db `~/.local/share/ai-memory/dsh.db`. Isolation is per project | | Pack looks like the full chat | Other prompt dumping, or you are not looking at `ai-memory:pack` | Search `## Memory (project:`. Do not paste the transcript yourself | --- ## Next step: dsh.pub (optional) You do **not** need the catalog to use the plugin. Topic **`dsh-plugin`** is already on the repo. When you want a directory row, submit the repository URL yourself: - [https://dsh.pub/en/submit/](https://dsh.pub/en/submit/) - [https://dsh.pub/zh/submit/](https://dsh.pub/zh/submit/) This guide does not submit for you. --- ## Related docs - Endorsement / architecture: [INTEGRATION_DSH.md](INTEGRATION_DSH.md) - Plugin internals: [integrations/dsh-ai-memory/README.md](../integrations/dsh-ai-memory/README.md) - Crate usage: [USAGE.md](USAGE.md)