DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Memory — DSH Plugin for DeepSeek Harness
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins
M

@achasoft/dsh-memory

Memory

Persistent, searchable, per-project memory for the DeepSeek Harness: decisions, rules, and sprint context in a queryable DuckDB file, rules enforced on every model request, with a full management UI in the Web Client

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add github:navid-kianfar/dsh-memory#6645652f1ac489a55b39d373648f2ff35a60c44b
READMECompatibilityVersions

Compatibility and provenance

Memory is published as @achasoft/dsh-memory and currently resolves to version 0.3.0. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
github
Registry updated
9/15/2026

Versions

0.3.0stable
9/15/2026
0.2.1stable
9/15/2026
0.2.0stable
8/30/2026
Show 1 more versionCollapse versions
0.1.0stable
8/26/2026

Related plugins

Loading related plugins…

Latest
0.3.0
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
Unavailable
Files
Unavailable
Surface
web
License
MIT
Source
github
GitHub
★ 0
Weekly downloads
0
Last push
9/15/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue

Related plugins

More verified plugins in memory-context.

Memsearch Dsh@zilliz/memsearch-dshMemSearch plugin for DeepSeek Harness: shared markdown memory across agents, with capture, pre-step context injection, memory-recall skill, and a skill-candidate review panel.Reme@agentscope-ai/remeReMe client and memory integrations for TypeScript agentsStratagate Dshstratagate-dshRecent conversations stay vivid. Older ones fade into summaries, not oblivion. StrataGate gives DeepSeek Harness six-layer, time-decaying memory, while lasting events and relationships settle into a knowledge graph. Bring your memories from other AIs withMeow Memorymeow-memoryCross-session project memory for DeepSeek Harness: seven-layer SQLite memory, first-turn snapshot injection, per-message keyword hits, memory_remember/search/project tools, automatic reflection with reflection-fold UI, and idle-triggered dream consolidati

README

@achasoft/dsh-memory

Persistent, per-project memory for the DeepSeek Harness (dsh). Each project gets a DuckDB file at <project>/.dsh/memory.db holding decisions, architecture notes, sprint goals, session summaries, and binding rules. Mandatory and forbidden rules are a system-prompt section, re-read on every model request, so they survive context compaction. Memories are ranked by keyword (BM25F) and, when an embeddings endpoint is configured, by vector similarity. The Web Client gets a Memory tab to browse and edit all of it.

The Memory tab beside Chat, showing a project's memories, with the database path and active and embedded counts in the header

Features

The Memory tab

A Memory tab sits beside Chat in every session. It always shows the memory of that session's project. The header shows the database path, how many memories are active and how many have a vector, and whether rules are currently injected. The tab has three panes:

  • Memories: search box (labelled Semantic + keyword or Keyword only), category and status filters (Active, Archived, Expired, All), and actions: New, New rule, Import instructions file, Export JSON, Rebuild vectors.
  • Rules: the live mandatory and forbidden rules, and a Show the injected text toggle that displays the rule block exactly as the model receives it.
  • Sessions: the last 50 memory sessions, with summaries and how many memories each wrote and read.

Each memory card offers Edit, Archive or Restore, Delete permanently (removes the row and its audit trail, after confirmation), and History: the audit trail of creates, edits, reads, archives, restores, imports, and expiries.

A decision card with its History expanded

Rules that bind every request

Rules are injected through the system prompt, not a message, so every request carries the current rule set and an edit in the tab applies from the next request. Rule text reaches the model verbatim: a literal {{, as in ${{ secrets.GITHUB_TOKEN }}, is escaped so the harness prompt renderer does not treat it as a template variable.

Rules an agent recorded carry an Added by an agent badge in the tab and an [added by an agent] label in the prompt. When an agent-added rule is present, the block also tells the model that the user's own rules win on conflict.

Each rule is rendered on exactly one line, in the prompt and in memory_rules output. Line breaks (CR, LF, U+2028, U+2029), other control characters, and invisible format characters such as bidi overrides and zero-width spaces are collapsed to single spaces in the title and body, so a rule cannot add a heading or an unlabelled rule of its own. ZWNJ and ZWJ are kept. The stored text is unchanged; the Memory tab shows it as written.

The Rules pane listing mandatory rules, one of them marked "Added by an agent"

The injected text is bounded, because it is paid for on every request:

LimitValueWhen it is reached
One rule in the block2,000 charactersThe rule is cut, with a marker pointing at memory_rules.
The whole rule block24,000 charactersAgent-added rules are left out before user rules, and once any user rule is left out no agent-added rule is shown; a line says how many were left out.
One sprint goal or decision in session context1,000 charactersCut with a marker.
The whole session context12,000 charactersLater entries are left out; a line says how many.

Session continuity

Each top-level agent gets its own memory session. When it starts, the model receives one message with the last real session summary (up to 1,500 characters), up to 10 sprint goals, and up to 20 decisions from the last 7 days. Sprint goals and decisions follow the rule block's format: one line each, agent-recorded ones labelled [added by an agent], with a note that the user wins on conflict. Entries a subagent created or edited are left out of this message; they are still found by search and recall. Sessions left open by a crash or a disposed agent are closed with an [auto-closed: …] summary, which is skipped when picking the last summary. At the end of a turn the model is reminded to call memory_session_end (see remind).

A subagent (a session whose header has origin: 'subagent' or delegationDepth > 0) is bound by the same rules, but gets no memory session, no session context, and no reminder. A user's fork of a session is not a subagent.

Retention

Each non-rule memory gets an expiry date when it is written. Once that date passes, the memory drops out of search, session context, recall by title, and the Active list, and it is listed and reported as expired. Its stored status changes to expired at the next top-level session start in that project.

CategoryDefault days
session30
sprint, feedback90
devops, developer_docs180
decision, project_plan, architecture, reference365
mandatory_rules, forbidden_rulesnever

Priority 1 multiplies the lifetime by 1.5. Priority 2 and 3 never expire. Rules are always raised to at least priority 2. Restoring an archived or expired memory starts a new retention window.

Import and export

Import instructions file accepts .md, .markdown, or .txt (for example CLAUDE.md or AGENTS.md). Headings decide the category; list items under rule-like headings ("Never", "Always", "Rules", "Conventions", …) become one rule each. An import creates at most 1,000 entries and is validated in full before anything is written. Imported entries count as user-written.

Export JSON downloads every memory in the project, in all statuses, as <project>-memory.json. There is no JSON import.

Settings card

Settings → Plugins → Memory shows whether semantic recall is ready and lets you change the fields marked in Configuration.

The Memory settings card expanded, showing the semantic recall status, the injection switches, the reminder and toolset selectors, the ranking fields, and the database path

Requirements

  • Harness: tested with @deepseek-ai/dsh 0.1.5-rc.2.
  • Node.js: ^22.19 || >=24 (engines in package.json).
  • pnpm on PATH: dsh plugin forwards to it.
  • DuckDB: @duckdb/node-api 1.5.5-r.4 is a regular dependency. Its bindings ship as prebuilt optional packages for macOS (arm64, x64), Linux (arm64, x64, glibc and musl), and Windows (arm64, x64); nothing is compiled at install time. Other platforms are not supported.
  • Harness services: peer dependencies are @deepseek-ai/cordis, dsh-agent, dsh-credentials, dsh-llm, dsh-session, dsh-system-prompt, dsh-tools, dsh-typert-protocol, and schemastery, all provided by a standard dsh-base profile. The host half requires the agents service; settings (for the Settings card and live edits) and memoryEmbedding are optional. The browser half needs a Web Client profile (dsh-api-remotes, dsh-client-locale, dsh-client-ui-conversation, dsh-client-ui-settings, dsh-client-ui-settings-plugins).
  • Embeddings (optional): any endpoint that implements OpenAI's POST /v1/embeddings, such as a hosted API, a local inference server, or Ollama. Without one, ranking is keyword-only and every other feature works.

Install

dsh plugin --profile web add @achasoft/dsh-memory
dsh web

dsh plugin --profile <name> <args> runs pnpm <args> in $DSH_HOME/profiles/<name> ($DSH_HOME defaults to ~/.dsh) and creates the profile on first use. After a successful add, any dependency whose package.json declares dsh.bundle is appended to the profile's dsh.profile.bundles. No manual edit is needed.

At boot the harness composes the profile from patch layers, in this order: each bundle's cordis.patch.yml (in bundles order), the profile's own cordis.patch.yml, $DSH_HOME/cordis.patch.yml, then any --patch <file> overlays. This package's patch inserts four rows:

Row idLoadsDefault
memory@achasoft/dsh-memory/host: store, prompt hooks, RPC, settingson
memory-tools@achasoft/dsh-memory/tools: model-facing toolson
memory-ui@achasoft/dsh-memory: the browser halfon
memory-embeddings-openai@achasoft/dsh-memory/embeddings-openaidisabled: true

To uninstall:

dsh plugin --profile web remove @achasoft/dsh-memory

This removes the dependency and its bundle entry. Remove any rows in your own patch files that target the ids above. .dsh/memory.db files in your projects are left in place.

Configuration

Override a row from your profile's cordis.patch.yml by id. A patch replaces the row's whole config, so restate every key the row needs:

- id: memory
  config:
    databasePath: .dsh/memory.db
    injectRules: true
    injectSessionContext: true
    autoSession: true
    remind: once
    vectorWeight: 0.6
    minSimilarity: 0.3
    searchLimit: 10
    candidateLimit: 1000
    embedBatch: 64
    retentionDays:
      sprint: 30
      decision: 0
    relevanceWeights:
      similarity: 0.7
      recency: 0.15
      access: 0.15

The patch row is the base layer. Values saved from the Settings card go to the harness settings layer (the memory: section of $DSH_HOME/settings.yaml) and take precedence over it. Committed changes apply from the next request or call, without a restart.

memory row

KeyDefaultIn Settings cardWhat it does
databasePath.dsh/memory.dbyesRelative paths resolve against each project directory. An absolute path makes every project share one file. Changing it moves open projects and running agents to the new file.
injectRulestrueyesInject the rule block into every request. Off keeps rules stored but not enforced.
injectSessionContexttrueyesSend the last summary, sprint goals, and recent decisions when a top-level session starts.
autoSessiontrueyesOpen a memory session per top-level agent. Off also disables the reminder.
remindonceyesnever, once (first stop boundary with an open session), or every-turn.
toolsetcoreyescore or full tools. Only a value saved in the settings layer (the card, or settings.yaml) counts, and it overrides the memory-tools row live. Set on this row in a patch file, it has no effect.
vectorWeight0.6yesShare of the vector score in a blended similarity, 0–1.
minSimilarity0.05yesSimilarity floor for searches that do not set one, 0–1.
searchLimit10yesResults for a Memory-tab search that sets no limit, 1–100.
candidateLimit1000noRows each search probe (keyword and vector) considers.
embedBatch64noMemories embedded per background pass.

The shipped cordis.patch.yml restates retentionDays and relevanceWeights with these defaults. An older override that leaves them out still loads; the schema supplies the same defaults.

memory-tools row

KeyDefaultWhat it does
toolsetcorecore registers six tools; full adds four more. This is the default: a toolset saved from the Settings card overrides it without a restart, and the card shows the toolset in force.

memory-embeddings-openai row

Enable the row and restate its config:

- id: memory-embeddings-openai
  disabled: false
  config:
    baseUrl: http://127.0.0.1:11434/v1
    model: nomic-embed-text
    timeoutMs: 30000
    batchSize: 64
KeyDefault in patchRequiredWhat it does
baseUrlhttps://api.openai.com/v1yesEndpoint prefix; /embeddings is appended.
modeltext-embedding-3-smallyesSent as model, and stamped on every stored vector.
apiKeyEnvOPENAI_API_KEYnoName of the credential to send as a bearer token, resolved through the harness credential service on every call. Omit it for an endpoint that needs no key.
timeoutMs30000yesPer-request deadline.
batchSize64yesTexts per HTTP request.
dimensionsunsetnoSent as dimensions, for endpoints that support shortened vectors.

Vectors are stored with the model name and the vector length. When the model or length changes, old vectors are excluded from comparison and re-embedded in the background. If the provider cannot describe itself, the plugin does not attach it and ranks by keyword. If an embed call fails, that search falls back to keyword ranking. Rebuild vectors runs a backfill immediately and reports how many memories still lack a current vector.

Model-facing tools

Every tool resolves the project from the calling agent's session working directory. Writes are stamped source: assistant.

ToolToolsetWhat it does
memory_searchcoreRanked search by keyword and, with embeddings, by meaning. Default 8 results.
memory_storecoreStore a non-rule memory (decision, architecture, devops, sprint, project_plan, developer_docs, feedback, reference, session), priority 0–3.
memory_recallcoreRead one memory by id or exact title, and count the read.
memory_rulescoreReturn the complete live rule set, agent-added rules labelled.
memory_add_rulecoreAdd a mandatory or forbidden rule.
memory_session_endcoreFile the summary against the caller's own open session. Any other session_id is refused.
memory_listfullFilter and page memories by category, status, tags, or substring.
memory_updatefullChange title, content, tags, priority, or category.
memory_archivefullArchive a memory, with an optional reason recorded in history.
memory_provenancefullRead the last 25 history entries of one memory.

No tool hard-deletes a memory or restores an archived one; those actions are only available in the Memory tab.

RPC

The browser half calls a Typert remote namespace named memory. The contract is generated into generated/ and ships in the bundle. Every endpoint takes an optional project (an absolute directory; when omitted, the host process's working directory is used) and returns either { ok: true, … } or { ok: false, code: 'invalid' | 'not-found' | 'unavailable', message }.

EndpointPurpose
describeCounts, embedding status, live rules, the rendered rule block, and the toolset in force.
listFiltered, sorted, paged listing.
searchRanked search.
create, updateWrite as the user.
discardArchive (hard: false) or permanently delete (hard: true).
sessionsThe last 50 sessions.
provenanceThe last 100 history entries of one memory.
importInstructionsParse and import a Markdown instructions file.
exportAllAll memories as JSON text.
reembedRun an embedding backfill now.

Data and storage

  • Location: <project>/.dsh/memory.db, where <project> is the session's working directory. The .dsh directory is created with mode 0700.
  • Commit or ignore it: it is an ordinary file. Commit it to share rules with a team, or add it to .gitignore.
  • Layout: version 1, stored in a meta table. A file with any other version is refused with a message; there are no migrations.
  • Tables and views: memories, sessions, provenance, meta, plus two views for reading by hand:
duckdb .dsh/memory.db "select kind, title, content from rules"
duckdb .dsh/memory.db "select category, title, source, updated, expires from memory"
  • Locking: DuckDB takes an exclusive lock on the file. While dsh holds a project open, another process (a second dsh, or the duckdb shell) cannot open it and gets a "locked by another process" error. Stop dsh before querying by hand.
  • One open per file, per process: a process opens each database file once, whatever path spelling or plugin reload reaches it. An earlier bug that opened the same file twice in one process and corrupted it is fixed. Do not run two dsh servers against the same $DSH_HOME.
  • Transactions: each write, its authorship check, and its audit entry run in one transaction, so an edit is always applied to the row as it currently is.
  • Backups: stop dsh and copy .dsh/memory.db, or use Export JSON for a readable copy you cannot re-import.

Security and trust model

A rule is repeated to the model on every request, so the plugin limits who can change the rule set:

  • User rules are the user's. A rule written in the Memory tab or imported from a file can only be edited, archived, or deleted from the Memory tab. A tool call that tries is refused with a message saying so. An agent also cannot turn a user-written memory into a rule.
  • Agents can add rules and manage their own. With toolset: full, an agent can edit or archive rules that an agent added. It can also edit or archive any non-rule memory, including ones you wrote.
  • Agent rule caps: a rule an agent writes is at most 4,000 characters, and a project holds at most 100 live agent-added rules. The user's rules count toward neither limit.
  • Subagents cannot change rules at all. They can search, store non-rule memories, and read rules. Their writes are recorded in the history with the actor subagent, and anything with such a create or edit entry is kept out of the next session's opening context.
  • Sessions are per agent. memory_session_end closes only the calling agent's own open session. A session_id naming another agent's session, a session opened by another process or an earlier run, or one that already ended is refused. Such an open session is closed as an orphan at the next session start.
  • Authorship is the source column. Only the exact value assistant counts as agent-written. Anyone who can write the DuckDB file can change it.
  • Credentials for embeddings are referenced by name (apiKeyEnv) and never stored in the database or shown in the UI.

Known limitations

  • The RPC accepts any project path. Any authenticated Web Client caller can name any absolute directory as project. The plugin then creates .dsh/memory.db there and reads or writes it.
  • memory_rules output is not capped. Unlike the injected block, it returns every rule in full.
  • Subagent writes recorded by earlier versions are not recognised. They were recorded with the actor agent, so they are labelled as agent-added in session context but not left out of it.
  • An agent's edit of a memory you wrote is not labelled. Authorship follows who created the entry, so a decision you wrote and a top-level agent later rewrote is shown unlabelled.
  • The last session summary is carried as written, line breaks included. Only top-level agents file summaries.
  • Changing retention does not recompute existing expiry dates. New values apply when a memory is created, or when its category or priority changes, or when it is restored.
  • Single writer per file. See Locking.

Development

The devDependencies link a deepseek-harness checkout at ../../deepseek-harness, relative to this repository, for types and tests. pnpm install expects it there.

pnpm install
pnpm run typecheck
pnpm test             # checks generated/ against src/host, then runs vitest
pnpm run build        # writes generated/, then tsc, then tsdown

generated/ holds the Typert RPC contract, rendered from scripts/typert-endpoints.mjs. pnpm test (scripts/check-typert.mjs) fails when src/host/index.ts, src/host/types.ts, the endpoint table, or the renderer changed since the contract was last recorded, or when a file under generated/ differs from what the table renders. After updating the table to match src/host/, run:

pnpm run regen:typert

build writes generated/ but does not record the fingerprint; only regen:typert does.

To run a checkout in a local profile, add it by path and restart the web server:

dsh plugin --profile web add link:/absolute/path/to/dsh-memory
dsh web

A linked package resolves its imports from its own directory, so the harness packages it imports must resolve there to the same copies the running harness uses. The maintainers' workspace does this with publish-plugins.sh and .dsh-compat/install-plugins.sh in the parent dsh-plugins directory, not in this repository. After a rebuild, restart dsh web.

License

MIT

retentionDays{}noDays per category. An absent category uses the default table above; 0 means never expire. Rules never expire.
relevanceWeights{ similarity: 0.7, recency: 0.15, access: 0.15 }noHow match, recency, and read count combine into the final ordering.