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:

  1. First, use ctx.sessions.list() to index active sessions in memory;
  2. Then, use ctx.sessionPersistence.list() combined with readFrom(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.

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 unicode61 tokenizer 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 with kind='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/disposed only 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.