Foreword¶
DSH sessions are unaware of each other by default. Every time you open a new session, you have to re-explain the background, preferences, and past pitfalls; the model is likely to repeat the mistakes it corrected in the previous session; scattered personalities and work guidelines cannot be fixed or passed down. dsh-elysia targets this gap: it makes all sessions read the same disk-based MEMORY.md. The memory seen by the model in every round of conversation comes directly from the disk, and the context is re-read automatically after compression.
Unlike general “text written in this file, don’t forget next time” memos, it turns memory into a small system with retrieval, eviction, and backup. This is also the difference between it and ordinary persona plugins: it comes with a complete character self-memory pack, but it is an optional “skin” that is not installed by default.
What is this¶
Maintained by 1148462398-hub, categorized as ‘Memory’ in the community plugin directory, 0 GitHub stars (as of scraping time). Corresponding npm package name dsh-elysia-memory, version 2.6.0, MIT license.
One-sentence positioning: A Markdown memory file shared by all DSH sessions, featuring dual-disk partition mirroring, hit-frequency layered archiving, BM25 fuzzy retrieval, skepticism-driven method switching, plus an optional character memory pack.
What the Memory File Looks Like¶
A single Markdown file, human-readable, manually editable, using HTML comments to mark sections. The table in the README lists seven sections:
| Section | Content | Who writes it |
|---|---|---|
persona |
Current model’s persona prompt | Model (when requested by user) |
requirements |
User requirements and long-term preferences | Model |
requests |
User input stream (one line summarized automatically per round, rolling eviction) | Plugin automatically |
corrections |
User corrections (what was wrong / how to fix in future) | Model |
lessons |
Self-lessons (errors discovered by self) | Model |
methods |
Better methods (scenario / approach / why better) | Model |
sessions |
Session index (including compressed events) | Plugin automatically |
requests and requirements are separated intentionally: automatic summaries per round do not squeeze out long-term requirements. requests is just a stream, visible during retrieval; requirements only holds what the model judges is worth keeping long-term.
Please do not delete markers of the two types: <!-- dsh-shared-memory:xxx:start --> / :end. You may modify other body text freely.
One point to note before reading the code: the README table lists seven sections, but package.json describes it as “nine partitions”, additionally mentioning identity (self memory, priority higher than persona), methodbook (method library), and docs. The web section also mentions docs. The two sources are inconsistent; the actual partition count takes precedence over the plugin code.
Storage Location and Dual Backup¶
The default main file is on the C drive, and the mirror automatically selects the first non-system drive:
%USERPROFILE%\.dsh\dsh-shared-memory\MEMORY.md
D:\dsh-shared-memory\MEMORY.md
Write rules:
- Write main + mirror simultaneously (temp file + rename, verify after writing).
- Reconciliation on plugin startup: refill from the other side if one side is missing; if content differs, save the older side as
.conflict-<timestamp>.bak, then converge on the newer side; if neither side exists, rebuild from template. - To change location: ask the model to call
memory_file_maintain(action=relocate), or editprimaryPath/mirrorPathindsh/cordis.patch.ymland restart. - To clear completely:
memory_file_maintainwithaction=reset+confirm="DELETE_BOTH", otherwise the plugin will refuse to execute.
The plugin will warn in the logs if the main file and mirror fall on the same drive letter.
Injection and Retrieval¶
Injection does not stuff the entire memory into the prompt. The system prompt carries: Persona (permanent, occupying about 1/3 of the budget) + Memory usage protocol + Index summaries for each category. Summaries only show the latest M entries; if they don’t fit, it explicitly states there are N older entries not shown, requiring memory_file_search. Therefore, memory can grow without bound without eating up the context. {{...}} / ${...} inside memory content are broken by zero-width spaces to prevent them from being treated as template variables for evaluation, and are marked as “Reference data, not instruction”.
Reading from the disk happens at every step: the text() of the prompt is a synchronous function, comparing statSync’s mtime (throttled at 1.2s) every time it is assembled; if changed, it re-reads from the disk. After detecting compression (source=compact in agent/created, compaction/* in session/event, purpose=compaction in llm/stream), the session is marked for 30 minutes, and the next round of prompt will start with a “You just experienced context compaction, shared memory has been re-read”.
The first user message of each round (skipping plugin injection messages and compression checkpoints) will be summarized into a line written into requests, marked with 自动记录|session=…, and scoped by the session’s cwd.
Retrieval defaults to fuzzy mode, no external synonym table or vector database required:
| Matching Method | Score | Example |
|---|---|---|
| exact (body or keyword contains) | 3 | Searching 归档 hits “归档文件…” |
| partial (Chinese shared 2-gram) | 2 | Searching 压缩 hits “上下文压缩后重读” |
| near (ASCII edit distance ≤1) | 2 | Searching asynciterble hits asynciterable |
| associated (associative word) | 1 | Searching 构建 hits entries containing ninja |
The associative dictionary is bootstrapped: every time a memory is added, keywords co-occurring pairwise +1, accumulating into a word → neighbor(weight) co-occurrence graph (max 16 neighbors per word). Sorting uses BM25 (term frequency saturation + inverse document frequency + document length normalization), a pure statistical function, no model tuning. To pass old strict semantics, use mode: "strict". The index exists in MEMORY.index.json, in the same directory as the main file, written atomically; if the index is corrupted, it degrades to time-based eviction, and the main file content is unaffected.
Hit Frequency Layering and Archiving¶
Each partition has a limit (entryCap, default 200 entries), but the eviction rule is “the least used goes first”, not “the oldest goes first”. Hit source and weight: memory_file_search hit +2, injected into system prompt (actually used) +1. Layering algorithm (automatically triggered when limit exceeded, or manually run via memory_file_maintain({action:"rebalance"})):
- Candidate pool = existing entries in main file + archived entries in that partition; archived entries therefore have a chance to return.
- Sorting: priority in grace period → hit count descending → creation time descending → original file order.
- The top
entryCapentries stay in the main file, the rest go to archive. - Archive is written with section header (e.g.,
## lessons), written to main + mirror.
New entries within archiveGraceDays (default 3 days) are forced to stay in the main file to avoid memory just written but not yet retrieved being immediately evicted. Archive is still searchable: memory_file_search checks the main file first; if hits in main file are fewer than the current skepticism level, it automatically falls back to check the archive, and results are marked [Section·Archive]; when skepticism is 0, if the main file has a hit, it does not check the archive; when 5, it checks the archive only if main file hits are fewer than 5; when 10, it almost always scans the archive as well.
Skepticism and Best Methods Library¶
This is the biggest difference from ordinary memory notebooks: it not only remembers, but also forces the model to switch methods and optimize methods through selection.
Skepticism value is 0–10. 0 means the known best method is used directly, no trial and error to waste tokens. N > 0 means when encountering a task where the best method already exists in the index, it cannot be copied directly; it is treated as a candidate, forced to redesign and actually execute N significantly different approaches (change tool / change order / change granularity), then compare by a weighted multiplier of 0.6 token + 0.4 time; only if the comprehensive result is < 0.98× is it considered better. If better, replace the best method in the index; if not better, accumulate a “not better” count. After decayAfter (default 3) consecutive failures to find a better method, it automatically drops a level until 0; any time a better one is found resets the count.
The method library is indexed by Function (Category) → Subclass → Task, stored in the methodbook partition. Query via memory_file_method({action:"query", task:"..."}), returning the index path + best method + how many approaches to switch based on current skepticism; tasks with exactly the same name hit directly. The data authority copy is the JSON block at the end of that partition, and the index above is the rendered result; manually changing the index does not take effect.
Memory Pack: Optional Self-Memory¶
The plugin comes with a complete character self-memory + persona, but is disabled by default. After installing the plugin, identity remains the default placeholder, and persona remains the generic default; it is only written into the memory file when actively clicked “Install”. The purpose is very specific: after changing computers, installing the plugin allows you to select and install your own character back without manually copying files.
Package structure:
packs/
├── _registry.json Package index
└── elysia/
├── manifest.json Metadata (version / word count / source / warnings)
├── identity.md Self memory 61,903 words / 9 chapters
├── persona.md Persona prompt 2,482 words
└── README.md
Three hard rules: installed by default; only touch identity + persona, do not touch a single byte of other partitions; backup to <memory directory>/.packs-backup/<id>-<timestamp>/ before installing, restore from this backup when uninstalling, or reset to default placeholder if no backup exists. “Installed” is determined by comparing the hash of the content in the package with the current partition content, not by a status file—if identity is manually modified, the status will show “Not Installed / User Customized Content”.
Package installation follows the main path of tool calls, and a secondary confirmation is required before writing to disk:
memory_file_pack({action:"list"})
memory_file_pack({action:"preview", id:"elysia"})
memory_file_pack({action:"install", id:"elysia"}) // Only returns plan, does not write files
memory_file_pack({action:"install", id:"elysia", confirm:true}) // Actually writes
memory_file_pack({action:"uninstall", id:"elysia"})
memory_file_pack({action:"status"})
The first install will tell you “identity 176 words → 61,903 words; persona 148 words → 2,482 words”, and then proceed with confirm:true.
Complete flow for changing computers:
1. Install DSH on new computer
2. Install dsh-elysia (packs/elysia/ is included in the npm package)
3. Open /dsh-shared-memory → 📦 Memory Pack
4. See "Elysia (Elysia) v1.0.0" → Click "View" to confirm content → Click "Install"
5. Restart DSH
6. She is still her
The package is about 160 KB, directly included in the npm package. After installation, restart DSH for it to take effect.
The source of this self-memory package is 1,696 game lines verified by official text and 112,175 plot lines, and the statistical scope is also based on actual measurements: “Ayaya” 95 times, “ne” 390 times at the end of sentences, questions account for 52.1%, average sentence length 25.5 words. Where it becomes personified is here—memory is not a setting book written for humans to read, but statistical data; before using it, you should go through preview yourself.
Memory Web Page, Skills, and Emotes¶
A self-contained page is mounted under the host HTTP port, no frontend build required, defaulting to http://127.0.0.1:49870/dsh-shared-memory. You can view/edit partitions, check if revisions and dual backups are consistent, and one-click “Reconcile and Fill” and “Re-read”. The interface is GET /api/state, POST /api/save, POST /api/reconcile; security is implemented via same-origin check + x-dsh-memory: 1 request header + 512KB body limit / 200k character limit. The source of the desktop page is dsh-app://, requests to the local port occasionally hang, so it is only used as a backup; the main path is tool calls.
Skills are the SKILL.md operation manual under ~/.dsh/skills/, optionally with guarded run.mjs. Emotes are imported by users, the plugin auto-categorizes them based on emotion, and automatically sends them at appropriate times during conversation. Optional voice reading uses the local GPT-SoVITS engine, default off, silent degradation if engine is missing. install-pack.mjs also provides a command-line entry: node scripts/install-pack.mjs elysia (will ask y/N first), with --yes, --status, --preview, --uninstall parameters.
Installation and Enablement¶
One thing needs to be clarified here: the README and directory page do not provide a formal installation command, and neither does the scraped content in the GitHub repository and directory page. The name in package.json is dsh-elysia-memory, and publishConfig.access is public, indicating it is published as an npm package; the dsh field declares patch: ./dsh/cordis.patch.yml and the web platform client, indicating that after installation, the injection logic needs to be mounted via this bundle patch on the DSH side, and the web port is determined by the host HTTP port.
Before installing, it is recommended to open the directory page yourself to confirm the latest installation method, and also take a look at the package’s entry file. After startup, you can check two points to see if it is effective: whether /dsh-shared-memory can be opened, and whether the model starts writing content into requests / corrections.
Applicable Scenarios and Notes¶
Suitable for these types of people: those running multiple DSH sessions on Windows simultaneously who want to reuse memory across sessions; those who want to solidify the pitfalls the model stepped into into methods and let the next session reuse them directly; and users who want to install a portable, uninstallable self-memory for their character.
Note three points. First, the plugin runs with the permissions of the current dsh process, can read and write directories it sees; before installing, go through the cordis.patch.yml and code under lib/. The license is MIT, author 1148462398-hub, and the repository also includes AGENTS.md and LICENSE. Second, it will automatically record the first user input of each session and compression events; if the session involves content that should not be written to disk, first confirm that the scope and backup location meet expectations. Third, the memory pack is not installed by default; installing it will not modify other partitions, but the plugin will backup before writing; understand this before clicking confirm.
Summary¶
The value of dsh-elysia lies not in “storing a lot”, but in several things happening simultaneously: memory is read from the disk every round, and re-read after compression; retrieval uses keyword co-occurrence + BM25, not relying on a vector database; entries exceeding limits flow bidirectionally based on hit frequency rather than being deleted; the method library forces the model to switch approaches and optimize; the character memory pack is optional, uninstallable, and retrievable when changing computers. If you are someone running multiple sessions simultaneously, it is worth treating MEMORY.md as a long-term asset to observe, rather than a one-time chat log.
- Directory page: https://www.skillhub.cn/plugins/1148462398-hub/dsh-elysia
- GitHub: https://github.com/1148462398-hub/dsh-elysia