dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
为 DSH 补上 ai-memory 的收敛闭环:DSH 会话结束时调用 ai-memory finalize-session,把本次捕获的观察整理成 wiki 页面,供 ai-memory 服务的其他 harness 读取;跳过子代理、串行化并发结束的会话,并补扫被强制重启遗留的会话。
Memory bridge between DeepSeek Harness and ai-memory.
ai-memory shares one memory across 20+ coding agents: Claude Code, Codex, Cursor, Gemini CLI, OpenCode, and more all read and write the same wiki. DSH could only ever read it. This plugin makes DSH a full writer too.
Read this first, because it decides whether this package is for you.
ai-memory command-line program you install
yourself. See Credits.The memory engine this plugin drives is entirely the work of others:
akitaonrails/ai-memory — MIT licensed. One Rust binary that captures agent sessions through lifecycle hooks, consolidates them into a searchable Markdown wiki, and serves that memory to 20+ harnesses over MCP and HTTP.
No ai-memory code is included here. This repository contains zero lines
taken from that project. It is a DSH-side adapter that shells out to the
ai-memory binary, nothing more. If this plugin is useful to you, the credit
belongs upstream — please star their repository.
This is the point of the plugin, so it is worth stating precisely.
ai-memory is built on the idea that memory should follow you, not your editor. Quit Claude Code mid-task, open Codex in the same directory, and the next agent picks up a real handoff. That works because every harness writes into one shared store, and session-end consolidation turns the raw record into readable wiki pages the next agent can search.
DSH was the odd one out. ai-memory's consolidation is triggered by a session end event, and DSH never fires one — its session-terminating path exits through a signal that emits no disposal event at all. So DSH sessions landed in ai-memory as raw observations and stopped there:
Claude Code session ends ──► consolidated ──► wiki page ──► readable by every harness
DSH session ends ──► raw observations only ──► invisible to every harness
DSH could search the memory other agents wrote, but nothing DSH did ever became memory the others could read. One-way, in the wrong direction.
This plugin closes that loop by firing the finalize step DSH never fires. With it installed:
DSH session ends ──► this plugin ──► ai-memory finalize-session ──► wiki page
│
Claude Code, Codex, Cursor, Gemini CLI, … ◄────────────┘
A DSH session becomes a page that Claude Code can retrieve, that a teammate's Codex can search, that shows up in the next agent's handoff brief. DSH stops being a read-only consumer of the shared memory and becomes a peer writer in it.
That is the whole value: not a new memory system, but one harness joining an existing one properly.
Two things must already work. The plugin will not do either of them for you.
1. A running ai-memory server with capture wired into DSH.
Install ai-memory from upstream,
then wire DSH's lifecycle hooks so events are captured. ai-memory >=3.2.0
supports DSH natively; earlier versions need the legacy Claude Code bridge
configuration. A manual, single-command-string example supporting older servers
is in docs/hooks-dsh.json; see its native migration notes.
Verify capture independently before blaming this plugin:
ai-memory status # sessions and observations should be increasing
ai-memory doctor # inside your project directory
2. The ai-memory CLI on the same machine.
That is all. It resolves its own data directory and server URL, so the default configuration needs no settings at all.
If the server is not running, this plugin logs a clear warning at startup and does nothing else. Capture failing is a separate problem with a separate cause.
dsh plugin --profile web add dsh-ai-memory
From GitHub instead of npm:
dsh plugin --profile web add github:rasyidmmz/dsh-ai-memory
Restart DSH afterwards. The loader imports plugin code without a cache-buster, so an edited or newly added plugin is not picked up until the process restarts.
Confirm it loaded by searching the harness log for ai-memory:
[dsh-ai-memory] active v1.2.0 -- fast path session/disposed (zero idle cost) + ...
[dsh-ai-memory] preflight: ai-memory v3.1.1 | data_dir=... | server=127.0.0.1:49374
The preflight line is the fastest way to confirm the plugin found the same ai-memory your hooks are writing to.
Installing from a marketplace gives you the finalize half in one row. Two things are still yours to provide, and the startup log now names whichever one is missing instead of looking merely idle:
ai-memory itself. The plugin shells out to the ai-memory binary; it does
not bundle or install it. When the binary is missing the log says so, with the
install link and the exePath key that overrides the expected location, and
nothing is finalized until it appears.
Capture hooks. ai-memory only knows about a DSH session if DSH forwards
lifecycle events to it. That wiring is one insert: row in the profile's
cordis.patch.yml pointing @deepseek-ai/dsh-hooks-claude-code at a hooks
file; the reference file ships in this package as
docs/hooks-dsh.json. Without it ai-memory records no
DSH sessions at all — so there is nothing to finalize, and the log says
exactly that, with the path to that template.
The plugin deliberately does not write that row for you. The desktop
profile reloads cordis.patch.yml live, so writing it from inside a running
harness is how people hang their app; and a second hooks row sitting next to
one you already have would capture every session twice.
When both are in place, the preflight is one line and the rest is silent.
Optional. The defaults are correct for a standard ai-memory install, and the
plugin behaves identically with no config: block at all.
- insert:
- id: ai-memory
name: dsh-ai-memory
config:
exePath: /usr/local/bin/ai-memory # default: platform standard location
dataDir: /home/me/.local/share/ai-memory # default: let the CLI decide
# agentKind: dsh # optional pin; must match capture hooks
sweep: true # default: true
preflight: true # default: true
timeoutMs: 120000 # default: 120000
| Key | Default | Meaning |
|---|---|---|
exePath | Windows: %LOCALAPPDATA%\Programs\ai-memory\ai-memory.exe; elsewhere: ai-memory from PATH | Path to the ai-memory executable. |
dataDir | unset | ai-memory data directory. Leave unset unless you use a non-standard location; the CLI then resolves its own, which is what the hooks use. |
agentKind | stored session kind, falling back to claude-code | An explicit value pins finalization to that capture identity. Leave unset for mixed legacy/native stores. |
sweep | true | The abandoned-session safety net. Set false to disable it entirely. |
preflight | true | Log one line at startup naming the ai-memory version, data directory, and server it found. |
timeoutMs | 120000 | Per-finalize-session timeout. |
ai-memory 3.2.0 added AgentKind::Dsh and migration V85. Its DSH support is
now listed as Hooks + MCP. Earlier releases require --agent claude-code.
The UUID mapping is unchanged.
A server upgrade does not change the identity written by existing hooks.
This plugin therefore reads each session's agent_kind from the local store
(read-only), accepting only dsh and claude-code. That identity stays fixed
through all project fallbacks and --reopen. Preflight never changes it.
The sweeper also excludes unrelated harness kinds before applying its existing
live-session, idle-time and UUIDv5 guards.
If the row/store or node:sqlite is unavailable, finalization falls back to
claude-code, matching the shipped legacy hook template. For native capture on
a remote-only store, explicitly configure agentKind: dsh.
To opt into native capture, first upgrade ai-memory to 3.2.0 or later, then
change every capture command in your hooks file from --agent claude-code to
--agent dsh and restart DSH (the bridge reads hooks once). Start a new session
and verify its stored identity. Leave plugin agentKind unset so old captured
sessions can still finalize as claude-code. The plugin does not rewrite hooks,
relabel database rows, or modify your profile patch.
Two paths, deliberately asymmetric.
When a session closes cleanly, DSH fires session/disposed. The plugin listens,
derives the session's stored UUID, and calls ai-memory finalize-session.
It uses session/disposed rather than the two events that fire alongside it
because it is the only one carrying the full session object, so the working
directory is read directly instead of being cached or guessed.
DSH terminates through SIGTERM, and SIGTERM fires no disposal event at
all. A session open at that moment is never finalized: it stays open forever
with no page. This is not hypothetical — one session with 459 observations was
left behind that way.
So a sweeper exists that depends on no event: it reads ai-memory's store directly and finalizes sessions that are provably dead. Its schedule is dense at first and then eases off — 25s, 1 min, 3 min, 10 min, then every 30 min — because the only case an event misses is a session abandoned by a restart, which happens right when DSH starts.
Getting this wrong is worse than not doing it: finalizing a live session produces a page from half its content, and that page is never updated again. So four guards must all pass:
Guard 2 covers a second DSH window: that is a separate process, so its session is invisible here, and without the delay it would be closed mid-write.
Guard 3 has a useful side effect worth knowing if you run DSH alongside real Claude Code sessions in one repository: ai-memory stores those as version-4 UUIDs, so they can never be selected by this sweeper.
Set sweep: false to turn the whole net off; the fast path is unaffected.
Each of these broke an earlier version, and each fix is load-bearing. They are worth listing because they are the reason a naive "just call finalize-session" plugin does not work.
session-<uuid> and
ai-memory stores them as a derived UUID v5. Passing the raw string is
rejected: invalid uuid: invalid character: found 's' at 1. Child agents use
a bare UUID and must be passed as is — two id shapes, two treatments..ai-memory.toml marker only match after a lowercase retry.2>&1. DSH runs commands with stderr unredirected, and collapsing it
inside the command fails there, exiting non-zero having done nothing.running guard
silently discards the second.SIGTERM fires nothing — hence the sweeper above.All output is prefixed [dsh-ai-memory]. Search the harness log for it.
The prefix deliberately is not [ai-memory]: ai-memory has its own logs, and an
identical prefix makes it impossible to tell whose line you are reading.
| Log line | Meaning | Action |
|---|---|---|
active v1.1.0 ... | Plugin loaded | — |
preflight: ai-memory vX | data_dir=... | Found the server | Confirm the data directory matches your hooks |
WARNING: ai-memory executable not found | Wrong exePath | Set exePath in config |
preflight: the ai-memory server did not answer | Server not running | Start ai-memory |
sandbox runner is broken (0xC0000142) | DSH's sandbox runner is failing under Electron; the plugin switched to the unconfined path | See "Sandbox runner" below. Sessions still finalize |
session ... -> page created | Working | — |
session ... -> no open session matched | Already finalized, or never captured | Check ai-memory status; if observations are not rising, the hooks are the problem, not this plugin |
session ... FAILED | The CLI returned an error | The message tail is included |
sweeper could not read the store | ai-memory's schema changed | The fast path keeps working; only the safety net is down |
sweeper: no abandoned sessions | Normal, most sweeps | — |
If nothing appears at all, the plugin is not loaded — check the profile's
cordis.patch.yml and restart DSH.
Note on
finalize-sessionand consolidation. This plugin callsfinalize-session, which is a client of the running server. It does not invoke an LLM and does not write wiki pages itself; the server does that. If pages are not appearing, check the server's own logs.
DSH: developed and tested against DSH Desktop 0.2.1-rc.2
(the @deepseek-ai/dsh-desktop package), Node 24. Re-verified on 0.2.1-rc.2
on 2026-10-18 from the installed app.asar: agent/created,
agent/disposed and session/disposed are still emitted, ctx.sessions.get()
still returns a session whose header carries cwd, origin and
delegationDepth, and ctx.shell still exposes execute() only (the
run()-then-execute() capability branch below covers both). 1.0.4 and
1.1.1 were verified on 0.2.0-rc.2.
Earlier revisions of this README said "DSH Desktop 0.9.1". That was wrong — no such DSH version exists.
0.9.1had been read off an unrelated changelog; the package version at the time was0.1.7-rc.2. Revisions 1.0.0-1.0.3 were tested on0.1.7-rc.2.
ai-memory: developed against 2.5.2 (upgraded from 2.4.0 through 2.5.2, each verified working end-to-end), re-verified on 3.1.1 on 2026-10-18. What was actually checked, not assumed:
finalize-session still accepts --agent, --workspace, --project,
--session-id, --reopen and --json;Finalized … on success and
No open … sessions matched … when there is nothing to close, which is
what this plugin's classification reads;uuid5(NAMESPACE_OID, native id)
(crates/ai-memory-core/src/ids.rs:94), the exact mapping
sessionIdToUuid reproduces;status --json still exists and still reports version, data_dir and
bind, which the startup preflight prints.
--reopen and the marker's identity key arrived in 2.5.0 and are used by
1.1.0+. See the compatibility notes below for what the upgrades changed.Platforms: Windows is the tested platform. Linux and macOS command construction is implemented and exercised, but not run end-to-end by the author — treat those as untested.
No dependencies. No dependencies, no peerDependencies, so there is no
build step and no allowBuilds approval on install.
No tools, no UI. The plugin registers no model tools and draws no interface. It only listens and shells out.
The CLI contract this plugin uses did not change, but the server may refuse to start after the jump, and that failure looks like the plugin's fault because finalize calls then fail with a connection error. Observed on the author's machine going 2.6.0 → 3.1.1 against a copy of the store:
provider not configured: no openai-oauth token found at <data-dir>\auth.json;
run `ai-memory auth login openai-oauth`
2.6.0 was serving with an openai-compat provider configured through
llm_base_url plus environment keys; 3.1.1 wants a credential file for that
provider route. The store migrated cleanly (schema V83, same pages,
sessions and observations) — so this is a provider/auth step, not data loss.
Run the ai-memory auth login … command the message names (or point the config
at a still-valid api_key_env) before restarting the service, then check
ai-memory status again.
The upgrade was run and verified on the author's machine; nothing broke. The store kept every page, session and observation, and embeddings improved (6 pages missing → 0). Two entries in that release are worth knowing here:
pinned / expires_at silently lost).
Relevant on Windows, which is the tested platform.D:\…\Default Project could
become two separate projects. On an affected store, this release merges them.The plugin calls ctx.shell through one helper that accepts both shapes:
| Harness | Call | Result |
|---|---|---|
| older | shell.run(spec) | { exitCode, stdout, stderr } |
| DSH 0.1.7-rc.2 | shell.execute(spec) | handle, then handle.result() |
This is detected by capability (typeof ctx.shell.execute), never by version
number, so a future rename cannot silently break it again. It matters because
PwshLocalExecutor in 0.1.7-rc.2 exposes only execute(): without the
branch, every finalize dies with shell.run is not a function — and because the
failure only reaches the log, it looks like "the plugin is loaded but nothing
happens" rather than an error.
DSH 0.1.7-rc.2 launches its sandbox runner through Electron, and the confined
child process dies with STATUS_DLL_INIT_FAILED (0xC0000142). Measured
directly, same command, correct SID:
| Launcher | Result |
|---|---|
node.exe + runner | exit=0 (works) |
DeepSeek Harness.exe + runner | exit=3221225794 (0xC0000142) |
A plugin's ctx.shell calls carry no session, so they fall back to the default
workspace-write policy and always take the broken path.
The plugin therefore tries the normal, confined path first and falls back
only when it sees 0xC0000142, remembering the switch. The moment DSH fixes its
runner, finalize returns to being sandboxed with no change needed here.
Be aware of the trade-off: the fallback widens the CLI call's permissions
beyond the workspace (danger-full-access). It is contained to the
ai-memory finalize-session invocation — not the agent's own tools — and the
plugin never writes files itself. If that is not acceptable in your setup, do not
run it on a harness with a broken runner; there is no config switch to disable
the fallback in 1.0.2.
The plugin reads ai-memory's SQLite store directly in one place, the
sweeper, and only to find abandoned sessions. If a future ai-memory release
changes that schema, the sweeper logs an error and stops; the fast path is
untouched because it uses no SQL at all. Set sweep: false to silence it
entirely in that case.
MIT — see LICENSE. This license covers this plugin only. ai-memory is separately licensed (also MIT) by its own author.