dsh-journal
A DeepSeek Harness plugin that turns a plain JSONL file into a first-class journal tool with graded memory: entries carry a level, an expiry, and a review date, so a long-lived assistant can remember the right things for the right amount of time — and let the rest go on its own.
Why memory needs levels
A single undifferentiated memory file fails in two directions at once. Keep everything and the useful part drowns; keep only recent things and the relationship and the standing preferences — the parts that make an assistant feel like the same person — are exactly what gets dropped.
So every entry gets one of four levels, and the level decides its lifetime:
| level | meaning | lifetime |
|---|---|---|
S |
relationship, emotion, shared experience, promises | never auto-deleted; pinned |
A |
durable facts, preferences, key decisions | 365 days |
B |
project context, task progress | 60 days |
C |
transient details, one-off operations | 7 days |
prune soft-deletes expired rows into archive/; nothing is ever physically removed by the tool. Pinned rows are exempt.
The useful question when writing is not "is this important" but "which of these is this, a skeleton or a file" — the rules for how someone talks to you belong in S, the port number you debugged yesterday belongs in B, and a handoff note for the next session belongs in A because it only needs to survive until you read it.
The tool
One tool, eight actions:
| action | does |
|---|---|
add |
write one entry (level, title, text required) |
list |
list entries, optionally by level / status |
search |
substring search across title, text and tags |
digest |
the S + A summary — what a fresh session should read first |
stats |
counts per level, size, expired-but-present |
review |
push one entry's expiry out |
prune |
soft-delete everything past its expiry |
render |
rewrite JOURNAL.md as a readable digest |
Typical use in an agent loop:
journal action=digest # at the start of every new conversation
journal action=add level=S title="..." text="..."
journal action=search query=备考
journal action=prune dryRun=true # see what would expire, change nothing
Storage
One JSON object per line at <root>/journal.jsonl. Writes go through a temp file and a rename, so a crash mid-write cannot tear the store. A torn trailing line on read is skipped rather than failing the call.
Row shape:
{
"id": "j-20261104-140902-479d",
"ts": "2026-11-04T14:09:02+00:00",
"level": "B",
"kind": "fact",
"title": "short one-line title",
"text": "the body; facts, not reflections",
"tags": ["..."],
"pinned": false,
"status": "active",
"expires_at": "2027-01-03T14:09:02+00:00",
"reviewed_at": null,
"source": ""
}
The format is deliberately plain. Any script that can read JSONL can read this, and any script that can write one line can add to it.
Install
A DeepSeek Harness plugin only receives the host packages (@deepseek-ai/*) when it is installed as a link. An ordinary npm dependency fails to import and is silently skipped.
# 1) stable location, outside the profile
# e.g. D:\DSH-Plugins\dsh-journal\0.1.0\
# 2) real junction (a cross-drive symlink can be created broken, silently)
New-Item -ItemType Junction `
-Path "$env:USERPROFILE\.dsh\profiles\desktop\node_modules\dsh-journal" `
-Target "D:\DSH-Plugins\dsh-journal\0.1.0"
# 3) both lists in the profile's package.json must contain it
# dependencies: "dsh-journal": "link:D:/DSH-Plugins/dsh-journal/0.1.0"
# dsh.profile.bundles: "dsh-journal"
# Edit with Node, not a text replace: a stray comma makes the profile
# unparseable and the harness will not start.
# 4) restart the harness
Configuration (in the bundle layer cordis.patch.yml):
| key | default | meaning |
|---|---|---|
root |
D:/dsh-data/journal (Windows) / /dsh-data/journal |
where journal.jsonl lives |
toolName |
journal |
the tool's name in the model's toolset |
JOURNAL_ROOT overrides root from the environment.
Test
node _selftest.mjs
Runs against a temporary store: add at each level, list, search, digest, stats, prune dry-run, render, review, and the two validation paths (bad level, empty title are both rejected).
Note on what it is not
This is not a vector store and does not do retrieval by similarity. It is a small, inspectable, hand-curated log — closer to a notebook than a database. The bet is that an assistant which writes down the right few hundred lines, and forgets the rest on schedule, beats one that hoards everything and searches it.
License
MIT
No comments yet. Be the first to write one.