memcue-dsh
Verifiedmemcue-dsh Β· v0.14.0 Β· MIT
memcue long-term memory for DeepSeek Harness (dsh): facts recalled before a step, extracted when a turn ends
Install
dsh plugin add memcue-dsh Confirm the layer applied with dsh --profile default --dump-config β see the install guide.
Source
Tags
Creators
Readme
memcue for DeepSeek Harness
Long-term memory for DeepSeek Harness (dsh) on top of a memcue
fact base:
- No facts come with a prompt (#361). The system-prompt section tells the model to search the base with
memcue_searchbefore it answers a question that may depend on earlier sessions, several times with synonyms, the system's name and both languages if the first try finds nothing. - At the first prompt and after every compaction
memcue session-cardsupplies the card of global rules and repository decisions as a user-role notice. The card is a view of the base, not a copy. A failed card is not treated as delivered, so the next step retries it (with one report per session), and the step still runs. - When a turn ends the messages it added go to
memcue extract-messagesin the background, onceminNewCharsof new text has gathered. The checkpoint per session lives in<stateDir>/<session>.json: it holds fingerprints of messages already extracted and a pending batch, written atomically before the model call. A failed extraction keeps the batch and retries it on the next turn and when the plugin loads; a successful one acknowledges its fingerprints, so a turn boundary does not send the same text twice. Extraction reads only direct human messages: compaction summaries, cron and goal notices, hook contexts and subagent sessions are left out, and a forked session starts at its inherited prefix instead of re-extracting the parent's history. Tool calls travel with the assistant message and their results follow asRESULT, the same pair Claude Code transcripts carry. When the session is disposed, the listener awaits the remaining tail even if it is belowminNewChars; that call lowers memcue's own 2000-character transcript minimum, so a short final tail can still produce candidates, and a batch left behind by a crash is retried when the plugin loads. - A system-prompt section says the memory is memcue, when to search it and which tools fix it; the built-in memory files are not written.
- Four tools:
memcue_search(facts by words, with their ids; an optionallimit),memcue_add(one new fact),memcue_correct(a new version of a stored fact, with optionalkeywordsandexpires) andmemcue_retire(stop finding a fact; the history keeps it).memcue_searchrunsmemcue searchwith the session's working directory and id, so facts of this host and of the session's repository win ties andMEMCUE_SEARCH_LOG=1can name the session.
The binary owns the base, the extraction prompt and the model it uses. This plugin is only the seam between it and the harness; the harness support matrix lists what differs from Claude Code and Hermes.
Review and vet
Session extraction writes candidates, not active facts: memcue extract-messages stores them, search ignores
them, and memcue vet or memcue approve ID... decides. A fact written by memcue_add is active at
once; memcue_correct of an approved fact is a deliberate correction, not a candidate. The shared rules are in
Review and vet.
Supported dsh
The plugin asks memcue version -json when it loads. Without a configured binary or MEMCUE_BIN, a missing binary
or one older than the plugin's release is replaced by that release, installed into
$XDG_DATA_HOME/memcue/<version>/ (MEMCUE_AUTO_INSTALL=0 turns that off): an older release may not open the base
the new one writes. A binary older than 0.4.0 that stays, a configured one or a failed install, turns the session card
and extraction off with one warning (search keeps working). A build from source reports a suffixed version and counts
as the current tree.
Tested with dsh 0.2.0-rc.2. Both the repository bundle and the standalone package declare
>=0.2.0-rc.2 <0.3.0 peer ranges for @deepseek-ai/dsh-llm and @deepseek-ai/dsh-tools, so dsh's compatibility
check refuses a different minor instead of loading a plugin whose session or event shape it no longer recognises.
Install
The repository root is a dsh bundle wrapper: its package.json declares dsh.bundle.patch, pointing at this
directory's cordis.patch.yml. The plugin directory is also its own package, for npm publication and local
development. The entry is plain ESM (src/index.mjs) on purpose: dsh installs a bundle under node_modules, where
Node refuses to strip TypeScript types, so a .ts entry cannot be loaded from an installed package.
Optional: put the
memcuebinary where the dsh process can run it and note its absolute path. Without a configuredbinaryand without a currentmemcueonPATH, the plugin installs the binary of its own release into${XDG_DATA_HOME:-~/.local/share}/memcue/<version>/, the directory the Claude Code plugin uses (MEMCUE_AUTO_INSTALL=0turns that off; see Binary from the plugin).Install the bundle from the repository:
- Desktop / Web: open Plugins in the sidebar, choose Add plugin β Install a third-party plugin, and
enter
github:juev/memcue. - CLI:
dsh plugin --profile web add github:juev/memcue.
No
path:parameter and no local directory are needed. From a local checkout,dsh plugin add /path/to/memcueinstalls the same root package.The plugin directory is also a standalone package, published as
memcue-dsh.dsh plugin add memcue-dshinstalls it without the repository; a local checkout can usedsh plugin add /path/to/memcue/plugins/deepseek-harness.The plugin manager adds the package to the profile's
dsh.profile.bundles; the install dialog's Enable now switches the bundle on. dsh 0.2.0-rc.2 does not update installed plugins: to move to a new release, uninstall the plugin and install it again (Releasing).- Desktop / Web: open Plugins in the sidebar, choose Add plugin β Install a third-party plugin, and
enter
Configure the row by id in the profile's own patch layer,
$DSH_HOME/profiles/<name>/cordis.patch.yml:- id: memcue config: binary: /Users/you/.local/bin/memcue facts: /Users/you/.claude/memory/facts.db model: deepseek-flash apiUrl: https://api.deepseek.com apiKey: sk-...binaryis worth setting explicitly: an application launched from Finder may not have~/.local/binonPATH.factsmay be omitted when the base is memcue's default (~/.claude/memory/facts.db).
Choosing the extraction model
model is the model memcue uses for the extraction. No MEMCUE_* environment variable needs to be exported: the
plugin forwards the configured values to every memcue child process as MEMCUE_MODEL, MEMCUE_API_URL and
MEMCUE_API_KEY.
- With
apiUrlmemcue calls an OpenAI-compatible/chat/completionsendpoint:model: deepseek-flash,apiUrl: https://api.deepseek.com,apiKey: sk-.... - Without
apiUrlmemcue falls back toclaude -p --model <model>:model: claude-opus-5-5uses the Claude Code login already on the machine and needs no API key.
A field left out falls back to the process environment, then to memcue's own default. A configured value wins over
the ambient one, so a stale MEMCUE_MODEL in the launching environment does not override the profile patch. With
neither set, memcue's default claude-opus-5-5 runs through claude -p.
apiKey is stored in the profile patch under the private $DSH_HOME directory, but it is still a secret in a
configuration file: keep that file out of version control. To avoid storing it, omit apiKey and keep
MEMCUE_API_KEY in the environment that launches dsh, or use the claude -p route with no key at all.
Configuration
All fields are optional; MEMCUE_BIN and MEMCUE_FACTS from the environment are still the ambient fallbacks.
A configured field wins over the environment.
binaryβ path or name of the memcue executable (defaultmemcue).factsβ the fact base; set asMEMCUE_FACTSfor every child process (default: the binary's own default). A leading~/is expanded; a relative path is rejected at load, so the value cannot name a different file for each host.extractβfalseturns session extraction off (defaulttrue).MEMCUE_EXTRACT=0in the environment turns it off too and wins over this field.minNewCharsβ new text a turn must add before extraction runs (default2000).stateDirβ where this plugin keeps per-session extraction checkpoints (default$XDG_STATE_HOME/memcue/dsh). A checkpoint records the base it was written for; pointingfactsat another base starts that session fresh and says so, instead of hiding its messages or retrying a batch into the wrong base.searchLimitβ default formemcue_search(default5).maxToolResultCharsβ how much of one tool result goes to extraction (default1500). Tool output is kept on purpose: a fact sourced from a tool can only quote its evidence from aRESULTblock, and memcue's write policy drops such a fact when the quote is missing.modelβ extraction model; forwarded asMEMCUE_MODEL(default: memcue's own,claude-opus-5-5).apiUrlβ OpenAI-compatible base URL; forwarded asMEMCUE_API_URL(default: unset, soclaude -pruns).apiKeyβ key forapiUrl; forwarded asMEMCUE_API_KEY(default: unset, so the ambient value or no key is used).
Bad values are rejected at load time with the field name, so a typo does not silently fall back to a default.
Testing
node --test plugins/deepseek-harness/test/*.test.mjs
The suite mounts the plugin against a plain object context and a stub binary, so it needs no model, no base and no
running harness β only a checkout where @deepseek-ai/dsh-llm and @deepseek-ai/dsh-tools resolve. It also checks
the bundle metadata and that the bundle patch points at the loadable ESM entry. make test runs it together with the
Go and Hermes suites when those packages are installed, and skips it with the install command otherwise.
Releasing
The standalone package is published as memcue-dsh.
CI publishes on a dsh-v* tag or by manual dispatch through .github/workflows/publish-dsh.yml. It uses npm
Trusted Publishing (OIDC): the workflow has id-token: write, no token, and no NPM_TOKEN secret. The trusted
publisher is configured for the juev/memcue repository and the publish-dsh.yml workflow, with direct publish and
stage-publish allowed. Manual dispatch has a dry_run input: it packs a throwaway prerelease with --dry-run and
uploads nothing.
A maintainer can still publish manually; npm asks for the 2FA code:
cd plugins/deepseek-harness
npm publish --access public
A fork needs its own trusted publisher, or a granular NPM_TOKEN on a NODE_AUTH_TOKEN environment variable. A
granular token without the 2FA bypass cannot run npm publish: use npm stage publish and approve the stage with
npm stage approve <id>.
What differs from the Hermes plugin
- Hermes'
MEMORY.mdmirror has no counterpart here: dsh has no built-in memory files, so there is nothing to mirror. The write path ismemcue_add,memcue_correctandmemcue_retire. - The session card arrives as a durable message in the session log, so it replays with the session and survives a harness restart.
- The Claude Code hooks bridge in dsh cannot do this: it runs
SessionStart, but it ignoresPreCompact/SessionEndand always sends an emptytranscript_path, so extraction never starts and the base never grows.