DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

CC19990113 /

CC19990113/dsh-plugin-sessiongraph

Verified

Local conversation-history index for DeepSeek Harness — full-text search across every local session (Chinese two-character terms included), with a Rust kernel

★ 1 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@f2fb83e3

dsh-plugin-sessiongraph

English | 中文

Every DSH session on this machine, indexed as one searchable corpus — the model looks up "where did I say or do this" in milliseconds, instead of you digging through the sidebar or grepping compressed logs.

Architecture

Six packages behind one strict seam: adding a store or an indexer never touches the model tools.

Package Role
service Defines the ctx.sessiongraph seam: query vocabulary, store/indexer registries, schema v1, the Chinese bigram tokenizer
sqlite Read provider: answers the five queries from index.db
sessions Write provider: scan session logs, decode frame by frame, extract entries, write the database (TypeScript and Rust engines)
tool Consumer: the two model tools, the /sessiongraph command, and the system-prompt section
native Loader for the Rust kernel (returns undefined on any failure, never throws)
bundle Installable meta-package: cordis.patch.yml

Routing is "exactly one claimant", never first match. Every registered store is asked concurrently on each query; zero claimants and several claimants both throw (SESSIONGRAPH_UNAVAILABLE / SESSIONGRAPH_CONFLICT). Registration order and hot reload therefore never change the result. status is the one operation that answers with no store at all — someone who has never built an index needs to learn that fact, not receive the same failure every other operation raises.

Rust kernel

The indexing path is a napi-rs native module (Rayon for parallelism, rusqlite for the database), not WASM: the kernel must read the filesystem directly, write SQLite directly, and move gigabyte-scale data. WASM's boundary copies and absent fs/sqlite are disqualifying.

Full rebuild Incremental Query Index size
Rust kernel 6.76 s 59–107 ms 0.1–6.9 ms ~170 MB
TypeScript (fallback) 19.22 s 230 ms same ~170 MB

Both databases hold identical content, so this is not "a different index": sqlite_master DDL is byte-for-byte equal, every unchanged session compares field by field with zero differences, entry rows / session rows / FTS token multisets hash to the same SHA-256, and the TypeScript store reads a Rust-built database directly.

Engine selection is engine: 'auto' | 'native' | 'typescript', defaulting to auto: use the native kernel when present, fall back silently otherwise — a missing binary is never an error.

How it relates to memory and to the built-in session search

The same question has three homes, and picking the wrong one means finding nothing:

Memory (OpenViking / MEMORY.md) Built-in DSH session_search sessiongraph
Stores Extracted conclusions: preferences, decisions, entities Semantic text projected from session events, per event type Raw entries: message bodies, tool-call names and arguments
Form Markdown entries under viking:// SQLite FTS5 in an in-memory database (openAt: first-search, rebuilt every start) SQLite on disk, maintained incrementally
Scope Machine-wide The caller's workspace Machine-wide, across workspaces
Chinese Semantic (embeddings), recalls by meaning No — the unicode61 tokenizer does no CJK handling at all: 我今天在改广告SDK is one token, so 广告 matches nothing Yes — purpose-built bigram tokenizer, two-character terms match
How you search By meaning By token or phrase (English keywords, whole words) By characters, full text (Chinese and English)
Can it find the exact words No — only what survived extraction Partly: returns an excerpt Yes — the whole thing, including commands and arguments
Good for "What do I prefer", "what did we decide" English keywords, exact phrases, recent sessions "When did I say this", "what was that command"

In one line: memory answers "what is the conclusion", the built-in search answers "which session mentioned it", sessiongraph answers "what was actually said".

Three differences that matter in practice:

  • Chinese: the built-in search is effectively unusable for Chinese (its tokenizer has no CJK handling); sessiongraph is built for two-character Chinese terms
  • Scope: the built-in search only sees the caller's workspace; sessiongraph spans every workspace
  • Persistence: the built-in index lives in memory, opens on first search, and is gone after a restart; sessiongraph's index is on disk, usable immediately, kept fresh incrementally

Memory does not overlap with either: a conversation may never enter memory (short, casual, below any threshold) yet it is always in sessiongraph's raw index. Conversely, a memory entry has usually lost its context, and checking it means going back to the original.

Usage

Three entry points

Entry How
The model calls it Just ask "which session discussed the splash screen"; it reaches for sessiongraph
Slash command /sessiongraph status / index / search <term> / workspaces
Command results flow back After the command runs, its result is injected into the conversation as a plugin/notice message, so the model's next turn knows what you looked up — the same mechanism /plan uses

Tools

sessiongraph:

Operation What it does
search Cross-session full-text search; filters on workspace / after / before / kinds. Returns title, workspace, time, turn and a highlighted snippet
session Open one session by full id or unique prefix: metadata, ordered entries, child sessions
timeline List sessions newest-first, optionally scoped to a workspace
workspaces Workspace inventory with session/entry counts
status The index's own state — the only operation that answers before an index exists

sessiongraph_index: build or refresh on its own 300-second budget; sessions whose source mtime and size are unchanged are skipped, and past a thousand sessions the run becomes a host background job returning a job id.

Commands

Command What it does
/sessiongraph Same as status
/sessiongraph status Index size, disk usage, last build time, live session count, current workspace
/sessiongraph index [--force] Build or refresh; large corpora delegate to a background job and print the job id
/sessiongraph search <term> Search directly, printing the top ten hits
/sessiongraph workspaces Workspace list, * marking the current one

Automatic indexing

A fresh install needs nothing from you. Four mechanisms, all automatic:

When Mechanism Cost
The first time (no index yet) Session creation builds it in the background (autoBuild, on by default) seconds to minutes, off the critical path
On session creation (index present) agent/created → incremental run through ctx.jobs, never blocking 59–107 ms
Before a query If status.json's indexedAt is older than 5 minutes, refresh incrementally first ~400 ms
The current session Reads the host's ctx.sessionQuery and indexes live sessions that have not hit disk yet negligible

Prefer to drive it yourself? autoBuild: false disables the first automatic build and autoIndex: false disables the incremental refreshes; everything then goes through sessiongraph_index / /sessiongraph index.

What gets indexed

user/message (only source.kind === 'user', i.e. text a human typed), the text blocks of assistant/message (reasoning is 61% of the bytes and is not indexed), tool/call names and arguments, and session/title. Skipped: tool/result bodies, request/header, step/*, job/*.

Why two-character Chinese terms match

SQLite's unicode61 treats 我今天在改广告SDK as a single token, so searching 广告 finds nothing; trigram needs at least three characters, so two-character words stay unreachable. Write and read paths therefore share one purpose-built tokenizer (packages/service/src/tokenize.ts): CJK runs split into overlapping bigrams (广告点击 → 广告 告点 点击), Latin/digit runs become lowercased whole words split on _, and query tokens are quoted and joined with AND. The trade-off is recall over phrase precision — searching your own history is a "find it" problem.

Install

dsh plugin add dsh-plugin-sessiongraph

Or link a local checkout in a profile:

"dependencies": { "dsh-plugin-sessiongraph": "link:/path/to/dsh-plugin-sessiongraph" },
"dsh": { "profile": { "bundles": [ "...", "dsh-plugin-sessiongraph" ] } }

Restart DSH afterwards; the first sessiongraph_index call builds the database, and everything after that is incremental.

Development

pnpm install
pnpm build      # tsc -b, five TypeScript project references
pnpm test       # vitest run, 200+ tests

Internal contracts — data format, schema, tokenizer rules, per-package responsibilities, and which host capabilities this plugin reuses — live in DESIGN.md.

—/ 5

No ratings yet

Verified DSH bundle

Commit f2fb83e3b21e

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout