memory-vault-server
by Luisarg03
README.md
# dsh-memory-vault












Persistent OKF memory for [DeepSeek Harness](https://deepseek-harness.github.io/deepseek-harness/) (DSH):
a Python MCP server (SQLite FTS5 + Markdown), two Cordis plugins (`memory-mcp`, `memory-auto`)
and a vault starter with templates and a type registry.


## Components
| Component | What it does | Bundle |
|---|---|---|
| `memory-mcp` | MCP stdio wrapper: connects DSH to the memory vault server | `@luisarg/memory-mcp` |
| `memory-auto` | Auto memory capture: session digest with commit/compaction checkpoints | `@luisarg/memory-auto` |
| `memory-vault-server/` | Python MCP server: SQLite FTS5 + Markdown OKF | — |
| `memory-vault/` | Vault starter: templates + type registry + tag vocabulary | — |
| `scripts/digest_session.py` | Optional standalone post-session digest (CLI, not used by the plugins) | — |
## Quickstart
```sh
pnpm install
pnpm -r build
# local dev with an overlay (paths relative to the repo cwd)
dsh web --patch ./examples/dev-memory.cordis.yml
```
## Install
```sh
# 1. install both plugins (npm, prebuilt — no build approvals, no repo clone)
dsh plugin --profile web add @luisarg/memory-mcp@0.1.4 @luisarg/memory-auto@0.1.4
# 2. launch — first boot installs the vault server + starter under $DSH_HOME
# (~/.dsh/memory-vault-server and ~/.dsh/memory-vault) automatically
dsh web
# verify
dsh --profile web --dump-config | grep -A8 memory
```
> `uv` on PATH is recommended but no longer required: the bundled
> `launcher.mjs` runs the server with `uv run` when uv is present and falls
> back to a pip-managed venv (`python3 -m venv` + `pip install -r
> requirements.txt`, first boot needs network) when it is not. The packages
> are self-contained: they ship the Python vault server and the OKF vault
> starter, and copy them into place on first boot (existing files are never
> overwritten; upgrades copy only the missing `launcher.mjs` and
> `requirements.txt`). The version is pinned because
> pnpm's default `minimumReleaseAge` (3 days) would otherwise resolve an
> older release. Paths resolve as: env
> (`DSH_MEMORY_PATH`, `DSH_MEMORY_SERVER_DIR`) → `$DSH_HOME/memory-vault(-server)`
> → profile patch (see [Path resolution](#path-resolution-cwd-independent)).
> Launch from any directory.
**Developers** (local checkout instead of npm):
```sh
dsh plugin --profile demo add ./packages/memory-mcp ./packages/memory-auto
```
**Offline**: `pnpm --filter @luisarg/memory-mcp pack` and add the `.tgz` files.
Installing the repo root from GitHub is **not** supported (root has no
`dsh.bundle`; pnpm lacks git subdirectory specs) — use npm or the tarball.
Releases are published by CI: pushing a `v<version>` tag builds, tests,
validates the tarballs and publishes both packages to npm with a
[provenance attestation](https://docs.npmjs.com/generated-provenance-statements),
authenticated by GitHub OIDC — no publish token exists in this repository or on
the maintainer's machine. What runs before an artifact ships, and the guardrails
around it, are in [`docs/releasing.md`](docs/releasing.md#security-layers-around-the-release).
## Usage & interaction commands
Once installed, the agent can read and write the vault through the
`mcp__memory__*` tools — just ask it in the chat:
| You say | Tool the agent uses |
|---|---|
| "search your memory for `<topic>`" | `mcp__memory__search_memory` |
| "remember this: `<fact/decision>`" | `mcp__memory__store_decision` / `store_fact` / … |
| "export everything you know about `<project>`" | `mcp__memory__export_memories` |
| "summarize my profile" | `mcp__memory__get_profile` |
**Automatic capture** (`memory-auto`): git commits, compactions and session
ends trigger digests; idle checkpoints capture when there is activity. Digests
log as `[memory-auto] …` lines in the harness console, and writes land under
`<vault>/projects/<project>/<type>/` (Markdown) + the SQLite FTS5 index.
**Verify the installation and the stored memory:**
```sh
# composed config shows both bundles with the resolved paths
dsh --profile web --dump-config | grep -A8 memory
# what the vault holds (default vault: ~/.dsh/memory-vault)
ls ~/.dsh/memory-vault/projects/ # per-project OKF entries
grep -i "digest" ~/.dsh/memory-vault/log.md # digest markers
# talk to the vault MCP server directly (standalone smoke test)
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"cli","version":"0"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"ping","arguments":{}}}' \
| MEMORY_PATH=$HOME/.dsh/memory-vault uv run --directory memory-vault-server python server.py
```
**Run a second harness instance on another port** (for testing without touching
your main session):
```sh
pnpm dsh web --port 3090
```
### Second MCP client: opencode (zona central `~/.memories`)
Since 2026-09-09 the vault lives in a dedicated git repo at `~/.memories`
(union of the former DSH vault and the legacy `opencode-memory-vault`
bundle; see [`docs/central-zone.md`](docs/central-zone.md)). opencode is a
second stdio MCP client over the same server and vault — `~/.config/opencode/opencode.json`:
```json
"mcp": {
"memory-server": {
"type": "local",
"command": ["uv", "run", "--directory", "<repo>/memory-vault-server", "python", "server.py"],
"enabled": true,
"environment": { "MEMORY_PATH": "/home/hiro03/.memories" }
}
}
```
> opencode requires the key **`environment`** (not `env` — that one is
> silently ignored and the server falls back to the repo default vault).
## Memory stack
The plugins work on an OKF vault (`memory-vault/` in this repo, or your own).
Runtime: `uv` on PATH, or Python ≥3.11 with a network on first boot — both
launch paths go through the bundled `launcher.mjs`, which uses `uv run` and
falls back to a pip-managed `.venv` (`requirements.txt`) when uv is missing.
The post-session digest runs **in-process** through the harness's own LLM
service (`ctx.llm`, provider `deepseek-official` by default — configurable with
`provider`/`model`), so the plugins need no external CLI and store no
credentials: they use the same key DSH is configured with.
### Path resolution (cwd-independent)
DSH does **not** chdir — the launch directory is irrelevant. Paths resolve in
this order:
1. Env vars (override everything): `DSH_MEMORY_PATH`, `DSH_MEMORY_SERVER_DIR`.
2. Defaults under the **harness home**: `$DSH_HOME/memory-vault` and
`$DSH_HOME/memory-vault-server` (`~/.dsh` when `$DSH_HOME` is unset).
3. Profile patch (`cordis.patch.yml`) or `--patch` overlay with explicit values.
| Env var | Used for | Default |
|---|---|---|
| `DSH_MEMORY_PATH` | vault directory | `$DSH_HOME/memory-vault` |
| `DSH_MEMORY_SERVER_DIR` | directory with `server.py` (MCP server) | `$DSH_HOME/memory-vault-server` |
```sh
# run the MCP server standalone:
MEMORY_PATH=./memory-vault uv run --directory ./memory-vault-server python server.py
```
### Vault
`memory-vault/` is an OKF bundle: `templates/` (per-type templates),
`type-registry.yaml` (source of truth for types), `tag-vocabulary.json`
(tag normalization). Runtime data (`projects/`, `raw/`, `logs/`, `memory.db`)
is created by the server on first use and excluded from git (`.gitignore`).
## Architecture & diagrams
Interactive versions of the diagrams (standalone HTML, open in any browser):
- [stack.html](docs/diagrams/stack.html) — architecture
- [session-digest.html](docs/diagrams/session-digest.html) — dataflow
- [mcp-tool-call.html](docs/diagrams/mcp-tool-call.html) — sequence
- [capture-lifecycle.html](docs/diagrams/capture-lifecycle.html) — lifecycle
Editable specs live in `docs/diagrams/*.json` (generated with
[archify](https://github.com/tt-a1i/archify)). Full write-up:
[`docs/architecture.md`](docs/architecture.md); index: [`docs/README.md`](docs/README.md).
## Repository layout
```
packages/memory-mcp/ # cordis bundle: MCP stdio client to the vault
packages/memory-auto/ # cordis bundle: automatic session digest
memory-vault-server/ # Python MCP server (SQLite + Markdown OKF)
memory-vault/ # vault starter (templates + type registry)
scripts/digest_session.py # optional standalone digest CLI (not used by the plugins)
examples/dev-memory.cordis.yml # memory-mcp
examples/dev-memory-auto.cordis.yml # memory-mcp + memory-auto
```
## Layer order
1. `dsh.profile.bundles` (base + every installed bundle)
2. `$DSH_HOME/profiles/<name>/cordis.patch.yml`
3. `$DSH_HOME/cordis.patch.yml`
4. `--patch` overlays
Patch replaces `config` wholesale — it does not merge.
## Troubleshooting pnpm
- `unable to open database file` → the pnpm store is not writable in a sandboxed
environment. Use `--store-dir ./.pnpm-store` on every `pnpm install` and on
`dsh plugin --profile X --store-dir ./.pnpm-store add ...`.
- `dsh: pnpm failed` when installing from GitHub → only applies to packages with
a `prepare` script; copy the printed key into the profile's
`pnpm-workspace.yaml` (allowBuilds). Note: the subpackages of this monorepo
cannot be installed with `github:...` (pnpm has no git-subdirectory support) —
use npm or a tarball.
## Docs
- [`docs/`](docs/README.md) — public documentation (architecture + diagrams)
- [Releasing & version tags](docs/releasing.md) — which commit each `v*` tag maps to
- [Your first plugin](https://deepseek-harness.github.io/deepseek-harness/en/develop/basic/)
- [Build a tool](https://deepseek-harness.github.io/deepseek-harness/en/develop/basic/tool)
- [Plugin configuration](https://deepseek-harness.github.io/deepseek-harness/en/develop/basic/config)
- [Package and install](https://deepseek-harness.github.io/deepseek-harness/en/develop/basic/publish)