Introduction¶
When developing agents with the DeepSeek Harness (DSH), you will quickly encounter a specific problem: sessions are isolated from each other. Opening a new round of conversation, the agent cannot find out what was said last time or what tools were called. Trying to write your own plugin to subscribe to session/event to accumulate a record isn’t enough—session/event is an “append-after-submit” event stream. Resumed sessions do not replay seed history events, so content from old sessions cannot be retrieved.
dsh-session-index fills this gap: it builds a cross-session full-text index of all session content and exposes it as a tool directly callable by the model. Below is an introduction to its positioning, working method, and installation steps.
What is it¶
dsh-session-index is a session full-text indexing plugin for the DeepSeek Harness, distributed as a bundle (dsh.bundle). The author is longyu065, current version 0.1.0, MIT license.
It listens to the session/event event stream, extracts session content into searchable documents, builds a cross-session inverted index, and exposes it to the model via two tools: session_search and session_index_stats, allowing the agent to retrieve what was said or done in any previous conversation.
Indexed content includes: user/message and assistant/message text (reasoning optional), tool/call (tool name + arguments), tool/result, and session/title.
Core Features¶
Real-time Indexing and History Backfill¶
Each session/event append immediately enters the index, deduplicating idempotently by sessionId#seq, so overlapping backfill and real-time events are not double-counted.
To address the gap where resumed sessions do not replay historical events, the plugin performs a two-step backfill at startup:
- First, use
ctx.sessions.list()to index active sessions in memory; - Then, use
ctx.sessionPersistence.list()combined withreadFrom(id, watermark+1)to incrementally complete persisted old sessions based on a watermark.
The watermark exists both in memory and in the persistent index file; after a restart, only the increment is added.
Hybrid Search¶
When preferFts is enabled (default), FTS5 and the memory index run in parallel and are deduplicated and merged by session:
- The framework’s
ctx.sessionQuery(SQLite FTS5) handles English/word-level recall; - The built-in bigram index supplements Chinese recall. FTS5’s
unicode61tokenizer does not segment Chinese text; the entire CJK string is a single token, so “can search history across sessions” does not match “search across sessions”. The bigram recall complements this perfectly.
The engine field reports the actual search engine used: memory / fts5 / hybrid.
Rich Cards¶
Search results are projected into the card:'search' card in the Web UI: presentCall / presentResult combined with output.presentationMeta render the hits grouped by session as an expandable list. The group header is the session ID and title, and inside the group are the hit snippets. Card data is persisted along with tool/result events and can be replayed.
Persistence and Cleanup¶
Index documents are appended to $DSH_HOME/session-index/<sessionId>.jsonl in JSONL format; a restart only adds the increment. When a session is destroyed (session/disposed), all documents and index files for that session are removed synchronously.
Privacy Switches¶
Two configuration items control the indexing scope:
indexReasoning: Default off, does not index Chain of Thought (CoT) reasoning text;indexToolResults: Default on, controls whether to index tool return results.
Installation and Enablement¶
The source code is in the GitHub repository (links at the end of the article). After cloning locally, install in three steps:
# ① Package (in repository root)
pnpm pack # Produces dsh-session-index-0.1.0.tgz
# ② Install into profile (web = profile used for desktop)
dsh plugin --profile web add ./dsh-session-index-0.1.0.tgz
# ③ Restart desktop app / dsh web
Why use a tarball instead of add ./directory: pnpm does not install dependencies for local directory packages using the link: protocol (verified); the tarball produced by pnpm pack is a standard package, dependencies will be installed normally into the .pnpm sub-tree of the profile, allowing imports of @deepseek-ai/* inside the bundle to resolve.
The bundle comes with a cordis.patch.yml that does two things: mount the plugin itself; change the framework’s built-in FTS5 (session-query-sqlite) from the default openAt: never to openAt: first-search, and set the persistence path to $DSH_HOME/session-query.sqlite. This allows session_search to automatically enter hybrid search. If you don’t want this layer of override, override that line in your own profile’s cordis.patch.yml—patches are applied in order, later ones override earlier ones.
Configuration Options¶
| Key | Default Value | Description |
|---|---|---|
dataDir |
'' (auto = $DSH_HOME/session-index) |
Index disk directory; filling in a custom path changes the location |
maxResults |
20 |
session_search default maximum number of hits |
maxSnippetChars |
240 |
Maximum characters for summary snippets (Unicode code points) |
maxDocChars |
4000 |
Maximum characters for a single document index; truncated to prevent tool result inflation |
indexReasoning |
false |
Whether to index the assistant’s reasoning text |
indexToolResults |
true |
Whether to index tool return results |
preferFts |
true |
Whether to prioritize the framework’s FTS5 for hybrid search; false means pure memory index |
Development and Testing¶
The plugin source code is a single-file TypeScript (src/session-index.ts) that can be loaded with stripped native types using Node 22.18+. Runtime dependencies are @deepseek-ai/cordis ^4.0.1, @deepseek-ai/dsh-tools ^0.1.0-rc.6, and @deepseek-ai/schemastery ^3.18.1, installed normally into the profile via the tarball.
For local development, @deepseek-ai/* dependencies need to be symlinked first:
mkdir -p node_modules && ln -sfn <dsh-install-dir>/node_modules/@deepseek-ai node_modules/@deepseek-ai
<dsh-install-dir> is usually ~/.npm/_npx/<hash>/, shared by the desktop app and dsh web. TSC type checking also requires @types/node.
Testing and building:
node test-index.mjs # Independent engine test, does not start dsh, 65 assertions
pnpm run build # tsc compiles src → dist/ → index.js
Applicable Scenarios and Notes¶
Suitable scenarios: DSH users who want the agent to “remember” content from any previous conversation—checking previous conclusions, browsing past tool call logs, and extending context across sessions all rely on this index.
Note a few known limitations before use:
- The index directory should be exclusive to a single dsh process; concurrent access is not protected if multiple processes share the same
dataDir; - Chinese is recalled via bigrams; single-character queries (like “插”) will only hit isolated single-character documents; it is recommended to enter at least two characters;
- The framework FTS5 does not index
session/title; filtering withkind='title'goes through the memory index; - Currently, there is no “jump to original session” interaction inside the card (the framework wire format has no link/action block), but the card carries the session ID and title for sidebar positioning;
session/disposedonly cleans up the plugin’s own memory and JSONL files, without affecting the original session logs.
Additionally, the plugin runs with the permissions of the current dsh process. Its source code is a single file, so before installing, go through src/session-index.ts and confirm that the MIT license meets your expectations; the cost is low.
Conclusion¶
What dsh-session-index does is not complicated: it builds a searchable index of all session content and exposes it as two tools, allowing the agent to retrieve what was said or done in any previous conversation. Indexing, backfilling, hybrid search, and card presentation are all handled within the package, under the MIT license, with a single-file source code that is easy to audit.
- GitHub: https://github.com/longyu065/dsh-session-index
- Community Directory: https://www.skillhub.cn/plugins/longyu065/dsh-session-index
The community directory is an independent site and has no official affiliation with DeepSeek or Huanfang; it is used solely for plugin indexing.