songjongdevsecops/dsh-lembrar

dsh-lembrar

DeepSeek Harness plugin: semantic recall of what you already said in earlier sessions of the same workspace, appended to the conversation and available as an on-demand tool.

미분류deepseek-harness

dsh-lembrar

Semantic recall of what you already said, inside DeepSeek Harness.

An agent starts every session knowing nothing that happened in the previous ones. dsh-lembrar indexes your own messages (user/message events) from earlier sessions of the same workspace and puts the matching ones back in front of the agent: once automatically before each turn, and on demand through a tool. Matching is by meaning, not by exact words.

It is recall, not a diary or a summary: the indexed text is your raw message, and what comes back is the excerpt plus the session id and event sequence number, so the agent can open the original event with the harness session tools.

Install

# 1. pnpm — the harness manages profile plugins with it
npm install -g pnpm

# 2. add the plugin to your `web` profile
npx @deepseek-ai/dsh plugin --profile web add github:songjongdevsecops/dsh-lembrar

# 3. restart the harness: the bundle layer is read at boot
#    stop `dsh web` (Ctrl+C) and start it again
npx @deepseek-ai/dsh web

If dsh is already installed globally, step 2 is dsh plugin --profile web add github:songjongdevsecops/dsh-lembrar.

The package declares dsh.bundle.patch, so dsh plugin add appends the plugin row to the profile bundle list. That row is the only activation, and it is applied at every boot.

Check the loaded line:

npx @deepseek-ai/dsh --profile web --dump-config | grep -A10 lembrar

Expected shape:

- id: lembrar
  name: dsh-lembrar
  config:
    colecao: sessoes-bgem3-v1
    injetar: true
    ...

Update and uninstall

# update: re-run the add command, then restart the harness
npx @deepseek-ai/dsh plugin --profile web add github:songjongdevsecops/dsh-lembrar

# uninstall
npx @deepseek-ai/dsh plugin --profile web remove dsh-lembrar
# then restart the harness

Requirements

  • Node.js ^22.19.0 || >=24.0.0 (the same range DeepSeek Harness supports).
  • pnpm on PATH — the harness uses it to manage profile plugins.
  • DeepSeek Harness with session history indexed. The web profile mounts @deepseek-ai/dsh-session-query-sqlite, which maintains ~/.dsh/storages/session-search.db; dsh-lembrar reads that database for the session list. Without it there is no past to search, and the plugin stays silent.
  • memsearch with local ONNX embeddings for the vector index: uv tool install "memsearch[onnx]" (or pipx install "memsearch[onnx]"). Point the plugin at the binary when it is not named memsearch on PATH (LEMBRAR_MEMSEARCH or the memsearch config key).
  • sqlite3 CLI on PATH (the plugin reads the session list with it).
  • Python 3 to export the corpus (standard library only; exportar.py).
  • Optional: @deepseek-ai/dsh-tool-session-query for the session_event_read tool the skill mentions when an excerpt is not enough.

The plugin itself is plain ESM using only Node built-ins: no build step and no native dependency.

Build the index

dsh-lembrar reads an existing memsearch collection; it does not embed anything itself. The package ships the two commands that turn the harness session database into that collection:

# where the installed package lives (adjust if your profile has another name)
PKG="$HOME/.dsh/profiles/web/node_modules/dsh-lembrar"
STATE="${XDG_STATE_HOME:-$HOME/.local/state}/dsh-lembrar"

# 1. one markdown file per user message, from session-search.db
python3 "$PKG/scripts/exportar.py" --destino "$STATE/corpus"

# 2. embed them (only new or changed text is embedded; `--force` redoes all)
memsearch index "$STATE/corpus" -c sessoes-bgem3-v1

# 3. write the marker the plugin checks before it searches
"$PKG/scripts/marcar-indice.sh"

The three lines are idempotent. After the first full run, a refresh takes seconds when little has changed, so it is reasonable to run them from cron or a systemd timer (for example, once a day):

0 3 * * * PKG="$HOME/.dsh/profiles/web/node_modules/dsh-lembrar" STATE="${XDG_STATE_HOME:-$HOME/.local/state}/dsh-lembrar"; python3 "$PKG/scripts/exportar.py" --destino "$STATE/corpus" && memsearch index "$STATE/corpus" -c sessoes-bgem3-v1 && "$PKG/scripts/marcar-indice.sh"

The marker is a small JSON file in <estadoDir>/<colecao>.json. It exists so the hook never pays a failed search for an index that was never built: run the indexer without step 3 and the plugin keeps quiet.

The collection name is the contract between the index and the plugin: it defaults to sessoes-bgem3-v1 on both sides and is configurable.

Configuration

Every path is configurable and the defaults derive from your home directory, so nothing is tied to a specific machine. Override by environment variable, or by the config of the lembrar line in your profile patch. A patch replaces the whole config of the line, so restate every key you want to keep.

Config keyEnvironment variableDefaultMeaning
colecao—sessoes-bgem3-v1memsearch collection
injetar—trueappend memories to each turn via agent/pre-step
maxTokens—800token cap for the appended block (~4 characters per token)
k—8events returned by one search, before the token cut
scoreMinimo—0.55similarity floor; below it the hook stays silent
buscarHabilitado—trueregister the on-demand lembrar tool
buscarTimeoutMs—30000engine timeout per search
exigirMesmoCwd—trueonly sessions with the caller's exact cwd are authorized
estadoDirLEMBRAR_ESTADO_DIR$XDG_STATE_HOME/dsh-lembrar/.estado, or <package>/.lembrar/.estado for a local link: installwhere the index marker lives
bancoLEMBRAR_BANCO~/.dsh/storages/session-search.dbsession database
memsearchLEMBRAR_MEMSEARCHmemsearch on PATHsearch engine binary

Profile patch example (~/.dsh/profiles/web/cordis.patch.yml):

- id: lembrar
  config:
    colecao: sessoes-bgem3-v1
    estadoDir: '/home/you/.local/state/dsh-lembrar/.estado'

Usage

You do not call anything. On the first step of each turn the hook searches your current message against the index, keeps the hits above the floor, and appends a short block at the end of the message list. Appending (never rewriting an earlier message) is what preserves the prompt prefix cache: only the new suffix is paid for. When nothing matches, the decision comes back untouched and the turn costs zero extra tokens.

The agent can also search on demand with the lembrar tool:

lembrar { "consulta": "what did we decide about the backup schedule" }

Each hit returns session_id, seq and the excerpt. The lembrar-recall skill describes the follow-up: open the original event with session_event_read when the excerpt is not enough.

Privacy and authorization

  • Same workspace only. A session only sees sessions whose cwd matches its own exactly, read from persisted_sessions. If that list cannot be read, no hit is authorized: the failure is closed, not open.
  • No cwd, no memory. Headless, CLI and subagent sessions without a cwd receive nothing; with exigirMesmoCwd: false you can disable the gate explicitly.
  • Secret directories stay out. A session whose cwd is inside a segredos/ or vault/ directory is excluded from the corpus and cannot be a caller.
  • Your words only. The corpus is limited to user/message events from the current surface. Assistant messages and tool payloads are never indexed, and messages injected by plugins or by the host are filtered out.
  • Local by default. The index is a local Milvus Lite database (~/.memsearch/milvus.db); the embeddings run locally.

Verification

From a clone of the repository (tests are not part of the installed tarball):

node --test tests/*.test.js

The suite covers authorization by cwd, secret-path exclusion, appending without rewriting, silence when there is no signal, the token budget, one excerpt per session, engine failure handling and the tool/skill registration.

To verify the install, check the dump-config output above, then ask the agent something about past work and look for the [lembrar] block at the end of the message list.

Limits

  1. User messages only. Assistant messages and tool payloads are out of scope: they are the bulk of the history and mostly noise for recall.
  2. Exact cwd means exact. A session started from another directory (or without one) sees no memory from this workspace. This is the harness authorization rule, not a plugin preference.
  3. One excerpt per session. The vector store returns the same file in two or three chunks; the block keeps the best one so repetition does not eat the budget.
  4. The similarity floor is a heuristic (scoreMinimo: 0.55). It prefers silence over noise and was not calibrated against human judgment.
  5. One extra tool in the catalog, about 171 tokens per request for as long as the plugin is loaded. Set buscarHabilitado: false to keep only the hook.
  6. The index is derived and disposable. Deleting the corpus or the collection loses nothing that the session database cannot rebuild.

Troubleshooting

  • Índice ausente para '<collection>' em <dir> — the marker is missing. Run the three index commands, or point LEMBRAR_ESTADO_DIR/estadoDir at the directory that holds <collection>.json.
  • No results, engine says the collection is empty — the collection name does not match the one that was indexed. Run memsearch stats -c <name> and align both sides.
  • Busca indisponível: motor falhou: ... — the engine did not start. Install memsearch, or set LEMBRAR_MEMSEARCH to the binary path.
  • Nothing is ever injected — check that the profile indexes session history (session-search.db exists and persisted_sessions is not empty), that the session has a cwd, and that the hook runs on step 1.
  • sqlite3: command not found — install the SQLite CLI; the plugin uses it to read the authorized session list.

License

MIT