dsh-zcode-memory
ZCode-compatible project memory, a post-turn changed-files panel with review/open actions, and a memory settings page for DeepSeek Harness (dsh).
Compatibility: dsh >=0.1.0-rc.6 <0.2.0 (declared via engines.dsh in package.json; developed and verified against 0.1.0-rc.6). Re-verify after upgrading dsh.
Features
- ZCode-compatible project memory — per-project memory directories whose names follow the exact same encoding rule as ZCode (
basename slug+-+ first 16 hex of SHA-256 over the normalized absolute path, lowercased on Windows). Copy ZCode'smemories/projects/tree into this plugin's memory root and every project resolves to the same directories, ready to reuse and maintain. Each agent session receives one context injection teaching the model the memory protocol (four memory types, frontmatter format,MEMORY.mdindex rules) plus the project's current index; writes inside the memory root are sandbox-auto-allowed, mirroring ZCode's memory file permission. - Post-turn changed-files panel — at the tail of every turn, files created or modified by the turn are listed with a Review button (inline +/- colored diff) and an Open button (opens in the editor/file manager on a local host). Derived client-side from the session event stream, so it also works on session replay.
- Settings page — a dedicated "ZCode Memory" section in the web settings: view/edit the memory root (persisted), and browse per-project memory statistics (file count, index presence, total size, last modified) down to single-file previews (5 MiB cap, same as ZCode).

Fully compatible with ZCode project memory directories: copy ZCode's
memories/projectstree into the memory root and it is reused as-is.
Install
Prerequisites: Node.js ≥ 20 with npm (dsh and pnpm are located automatically — no PATH setup needed).
From the release archive (one line)
tar -xzf dsh-zcode-memory-0.1.0.tgz && node dsh-zcode-memory/install.mjs
install.mjs registers the plugin into the web profile via the official dsh plugin add flow and links every peer dependency to the running dsh installation, so the plugin and the host share one module instance. Options: --profile <name> (default web), --home <dsh-home> (default $DSH_HOME or ~/.dsh), --dsh <dir> (override auto-detection).
From a git clone
git clone https://github.com/gniquil123/dsh-zcode-memory.git
node dsh-zcode-memory/install.mjs
Then restart the profile: dsh web. The settings page gains a "ZCode Memory" section.
Migrate existing ZCode memories
# Windows (PowerShell)
Copy-Item -Recurse "$env:USERPROFILE\.zcode\cli\memories\projects" "$env:USERPROFILE\.dsh\memories\projects"
# macOS / Linux
cp -r ~/.zcode/cli/memories/projects ~/.dsh/memories/projects
Memory root defaults to <dsh-home>/memories; projects live at <root>/projects/<project-key>/memory/. Keys are computed exactly like ZCode's, so the copy is recognized as-is.
Configuration
Edit the profile's user patch layer (~/.dsh/profiles/web/cordis.patch.yml):
- id: zcode-memory
config:
enabled: true # false disables injection and the remote service
memoryRoot: "" # non-empty overrides the root (wins over the settings page value)
memoryWriteAllow: true # widen the sandbox to danger-full-access for writes inside the memory root only
Runtime changes made on the settings page persist to <dsh-home>/dsh-zcode-memory.json; a patch-configured memoryRoot always wins.
Security notes
memoryWriteAllowwidens the sandbox policy only forwriteText/editTextcalls whose resolved target lies inside the memory root — the equivalent of ZCode's auto-allowed memory writes. Bash and all other paths keep the session's standing mode. Set it tofalseif you prefer approving memory writes manually.- Injected memory content is model-readable context, exactly like ZCode: memory files are written by the model, and consumers must verify freshness before recommending from them (the injected protocol includes that instruction).
Known issues
$DSH_HOME/.credentials.yamlwritten by a newer dsh desktop build uses a rich format that0.1.0-rc.6's flat parser rejects. If you run both, point the web profile'scredentialsrow at a separate file via the user patch layer:- id: credentials config: path: '<dsh-home>/.credentials-web.yaml' dshHome: '<dsh-home>'
Implementation notes
- Host half (
lib/index.js): injects the memory context once per session onagent/pre-step(mid-session re-injection would wake the agent loop into a spurious reply); wrapsctx.fs.writeText/editTextfor the memory-root allowance; registers a Typert Remote gateway. - Remote channel:
lib/typert.host.jsis a hand-written generator-format Typert contract (dsh-typert-loaderauto-registers any mounted package's./typertexport); the client half mounts its descriptors through the publicctx.remote.$mount. Self-mounted namespaces must NOT be declared in the module'sinject(that deadlocks the boot waiting on a service only the module itself creates) — calls resolve throughremote.namespaces. - Changed-files: pure client-side derivation over the conversation event stream, following the official deliverables plugin's accumulator pattern. The turn tail is a chain slot electing the first non-null selector in ascending
priority; this panel registers atpriority: -1so it wins when diffs were captured and defers to the official produced-files panel otherwise. lib/project-key.jsis ported 1:1 from ZCode (zai-org/ZCode,apps/zcode-cli/packages/core/src/memory/project-root.ts, Apache-2.0, marked changed); prompts are adapted from ZCode's provider-visible memory prompts. SeeLICENSEfor third-party notices.- Plain JS, no build step;
lib/client.jsis hand-rolled in dsh ModuleLoader's lazy-CJS factory format.
No comments yet. Be the first to write one.