
Security News
White House Authorizes Private Companies to Conduct Offensive Cyber Operations
A new federal program will let vetted U.S. cybersecurity firms help investigate and disrupt foreign cybercrime groups under government direction.
Native DeepSeek Harness (dsh) plugin: hybrid local and XMemo cloud memory for Cordis-based agents.
Native local-first + cloud memory for dsh.
Hybrid local storage with an offline durable write queue, plus real OAuth 2.1 login — reimplemented as an ordinary Cordis plugin instead of a thin MCP bridge.
Quick start · Auth · Config · Web GUI card · Tools · Capabilities · Limitations
A native DeepSeek Harness (dsh) plugin: hybrid
local + XMemo cloud memory, with offline durable write queuing, active state,
timeline, TODOs, decisions, and restart snapshots — the same tool surface as
xmemo-cindy-plugin, reimplemented as an ordinary
Cordis plugin instead of going through Cindy's host-specific plugin protocol.
This plugin talks directly to the MemoryOS REST API (the actual backend behind XMemo) and keeps
its own local store, rather than going through XMemo's hosted MCP server (https://xmemo.dev/mcp)
— dsh can also reach XMemo the MCP way via the harness's own @deepseek-ai/dsh-mcp-client bridge,
but this repo is the deeper, native alternative. Endpoint paths, request/response field names, and
the auth header were verified against the MemoryOS source, not guessed from another client —
including live, end-to-end verification of the OAuth flow against production xmemo.dev.
[!NOTE] DeepSeek Harness itself is a developer preview. This plugin has been exercised locally against production
xmemo.dev(unit tests, a live web GUI session, and a real OAuth registration + authorize round trip) but has not seen broad multi-user usage yet.
| Package | dsh-xmemo |
| Plugin ID | xmemo |
| Runtime | DeepSeek Harness (dsh) |
| Version | 0.1.0 |
| Bundle | Native Cordis plugin (host) + web GUI settings card (browser) |
| Backend | MemoryOS REST API — https://xmemo.dev |
| Authentication | OAuth 2.1 + PKCE (recommended), or a static API key (compatibility) |
| Local storage | JSON hybrid store with a durable offline write queue |
| Tool surface | 16 tools, same names/schemas as xmemo-cindy-plugin |
| License | MIT |
xmemo_forget defaults to a soft, recoverable delete.Not yet published to npm (see Known Limitations), so install from GitHub or a local checkout:
dsh plugin --profile <name> add github:yonro/xmemo-deepseek-plugin
# or, from a local checkout:
dsh plugin --profile <name> add ./xmemo-deepseek-plugin
A git install fetches source, not the built lib/, so pnpm blocks this package's prepare script
(which builds both halves — see Development) on the first add and prints the exact
key to allow. Add it to the profile's pnpm-workspace.yaml and re-run add:
allowBuilds:
dsh-xmemo: true
Connect an XMemo account or set an API key (see Auth below), then verify the row loaded:
dsh --profile <name> --dump-config # look for "# == dsh-xmemo"
Two methods, resolved in this order on every request (src/auth.ts) — never both at once:
connect:<anything> value to the XMEMO_OAUTH_ACTION credential — src/oauth.ts listens for
this via the seam-wide credentials/updated event. Connecting: registers a fresh public OAuth
client through MemoryOS's Dynamic Client Registration (POST /oauth/register, one per connect
attempt — cheap, and avoids caching a client_id with its own staleness edge cases), opens your
default browser to /oauth/authorize with a PKCE challenge, and runs a temporary
127.0.0.1:<ephemeral-port> HTTP listener as the redirect target — the same loopback-native-app
pattern MemoryOS documents for Cindy's desktop OAuth flow (verified live against production
xmemo.dev: DCR accepts a brand-new client's loopback redirect_uri, and /oauth/authorize
accepts that client_id + PKCE + explicit resource end to end). The resulting access/refresh
token pair is stored under the XMEMO_OAUTH credential reference and refreshed automatically
(with rotation — a used refresh token is never replayed) a minute before it expires. Disconnect
the same way with a disconnect:<anything> value, which also revokes both tokens server-side.XMEMO_KEY credential through dsh's own credential seam
— any of an environment variable (XMEMO_KEY=... dsh --profile <name>),
$DSH_HOME/.credentials.yaml (XMEMO_KEY: ...), or <project>/.env / $DSH_HOME/.env. Sent as
the X-API-Key header (MemoryOS's primary auth header — Authorization: Bearer is only its
fallback; see auth/api_key.py). The credential reference name is configurable
(apiKeyCredential in cordis.patch.yml) if you'd rather not use XMEMO_KEY.Unlike Cindy, whose host runs the OAuth dance generically for any plugin that declares an "OAuth
credential source," dsh has no such primitive (see Known Limitations) — this
plugin runs the whole flow itself in src/oauth.ts, with no deepseek-harness changes required.
Set in this bundle's cordis.patch.yml, or override per-profile/home cordis.patch.yml:
| Field | Default | Meaning |
|---|---|---|
mode | hybrid | hybrid (local-first + cloud sync), local-only (never calls MemoryOS), or cloud-only (no local persistence). Overridable at runtime — see Web GUI card. |
apiKeyCredential | XMEMO_KEY | Credential reference resolved through ctx.credentials. |
apiBaseUrl | https://xmemo.dev | MemoryOS REST API base. Override for a local dev server, e.g. http://localhost:8000. |
defaultScope | dsh | Default scope tag when a tool call omits one. |
agentId | DeepSeek Harness | Sent as X-Memory-OS-Agent-ID. |
requestTimeoutMs | 30000 | Default per-request timeout. |
longRequestTimeoutMs | 60000 | Timeout for xmemo_recall and xmemo_restore_progress. |
mode is resolved per tool call (src/mode.ts, mirroring how src/auth.ts resolves the API key) rather
than read once at boot: a hybrid/local-only/cloud-only value stored under the XMEMO_MODE
credential reference wins over the cordis.patch.yml default, so a change saved through the web GUI's
mode selector reaches the very next tool call without a restart.
xmemo_status, xmemo_update_state, xmemo_record_event, xmemo_list_timeline, xmemo_remember,
xmemo_recall, xmemo_forget, xmemo_create_todo, xmemo_list_todos, xmemo_complete_todo,
xmemo_create_decision, xmemo_list_decisions, xmemo_resolve_decision, xmemo_save_progress,
xmemo_restore_progress, xmemo_sync — same names, schemas, and behavior as
xmemo-cindy-plugin's tool surface.
| Area | Tools |
|---|---|
| Status & sync | xmemo_status, xmemo_sync |
| Working state | xmemo_update_state, xmemo_save_progress, xmemo_restore_progress |
| Timeline | xmemo_record_event, xmemo_list_timeline |
| Memory lifecycle | xmemo_remember, xmemo_recall, xmemo_forget |
| TODOs | xmemo_create_todo, xmemo_list_todos, xmemo_complete_todo |
| Decisions | xmemo_create_decision, xmemo_list_decisions, xmemo_resolve_decision |
Skill instructions (when to call which tool) are intentionally not part of this package — reuse
xmemo-claude-plugin/skills/*/SKILL.md as-is by dropping them into a project's .agents/skills/;
dsh's skill-filesystem provider discovers the same frontmatter format from that directory.
The dsh --profile web GUI's Settings → 插件配置 (Plugin Config) panel shows an "XMemo" card
alongside the first-party Bash/Agent-loop/Web-search cards, via a browser bundle this same package
ships (src/client/, built to lib/client.js, declared through the dsh.client manifest field in
package.json — no changes to deepseek-harness itself are needed; dsh-client-modules scans every
loaded plugin's package.json for that field, not just first-party ones).
Three controls are genuinely live:
已连接 · OAuth/Connected · OAuth or 已连接 · API Key/Connected · API key — mirroring
auth.ts's own "OAuth first, API key fallback" precedence exactly, and only falls back to
未连接/Not connected when neither is configured, so a working API-key setup never reads as
broken just because OAuth hasn't been connected. When both happen to be configured at once, a
short note under the button says so and states that OAuth is the one actually being used. Since
this card has no direct RPC into host-side code (the same credentials.*-only constraint below),
the buttons relay through the write-only XMEMO_OAUTH_ACTION signal credential rather than
calling anything directly, then poll credentials.describe('XMEMO_OAUTH') (every 2s, up to ~5.5
minutes) to detect when the browser login completes.credentials.describe/credentials.set calls, including correctly showing it as read-only when
XMEMO_KEY is supplied by the launch environment rather than the credentials store.<select> (hybrid / local-only / cloud-only) with an explicit Save
button, saved under the XMEMO_MODE credential reference and picked up by src/mode.ts on the
very next tool call. Unlike the API key field, the select can't show which value is currently
stored — credentials.describe deliberately never exposes a credential's value, only whether it's
configured (see Known Limitations) — so it always starts from the hybrid
default and a "customized"/"default" badge stands in for the value itself, the same way the API
key field's "configured" badge never reveals the secret.The other five config fields (apiBaseUrl/defaultScope/agentId/requestTimeoutMs/
longRequestTimeoutMs) aren't shown in the card at all — their defaults are fine for the vast
majority of setups; override them via cordis.patch.yml (see Config) if needed.
Build with npm run build:client (separate from the host build — needs its own tsconfig.client.json
and scripts/build-client.mjs, since the host and browser halves target different runtimes).
Ported from xmemo-cindy-plugin/plugins/xmemo-memory/main.js's business logic:
src/http.ts — request/error handling (AUTH_REQUIRED, RATE_LIMITED, XMEMO_SERVER_ERROR, …).
One structural change from upstream: Cindy's host injected Authorization based on request
hostname; this plugin resolves and attaches the auth header itself (src/auth.ts, src/oauth.ts).src/store.ts — the local JSON store (schema, prune limits, quota guard, corrupt-file → backup
fallback, write-temp-then-rename atomicity).src/outbox.ts — the durable write queue: staged → sent | pending | held | failed, idempotent
ops auto-retry (5 attempts), non-idempotent ops go straight to held and need an explicit
xmemo_sync {action: 'push', include_held: true}, local-id → cloud-id dependency resolution for
writes that target an entity that hasn't synced yet (e.g. completing a TODO offline).src/recall.ts — local token-overlap scoring merged with cloud recall, including the fail-closed
bucket/scope filter (compactCloudRecallItems): a cloud item that doesn't exactly match the
request is dropped, and any single violation suppresses all opaque cloud text in that response.src/redact.ts — the 7-category credential-like-text redaction, ported verbatim.src/oauth.ts — the whole OAuth 2.1 + PKCE client: Dynamic Client Registration, an ephemeral
loopback HTTP listener as the redirect target, token exchange/refresh with rotation, and revoke.One acknowledged divergence: main.js's store is one dynamic JSON blob, so it can replay a queued
write generically. This port's store is typed per entity kind, so a replayed write (via
xmemo_sync, possibly in a later process) only generically patches cloud_id + sync_status;
richer field back-fill happens only on the first attempt, made synchronously inside the same tool
call. See the comment at the top of src/outbox.ts.
| Capability | Included | Boundary |
|---|---|---|
| Local-first hybrid memory | Yes | Local store is not encrypted at rest |
| OAuth 2.1 + PKCE login | Yes | Needs a desktop session to open a browser in; headless dsh falls back to the API key |
| Static API key auth | Yes | Compatibility fallback only — never sent alongside a connected OAuth session |
| Durable offline write queue | Yes | Non-idempotent writes wait in held for explicit replay approval |
| Recoverable deletion | Yes | xmemo_forget is soft delete by default |
| Web GUI settings card | Yes | Only OAuth login, the API key, and memory mode are editable from the browser — the other five config fields need cordis.patch.yml |
| Recall and search | Yes | Limited to memory visible to the authenticated account, and fail-closed on any bucket/scope mismatch |
| Cross-agent continuity | Yes | Other agents/clients need their own authorized XMemo connection |
| PII redaction | No | Only credential-like text is redacted, matching xmemo-cindy-plugin upstream |
| MCP transport | No | Talks to MemoryOS REST directly; dsh's own dsh-mcp-client bridge is a separate, untouched path |
| Bundled skill instructions | No | Reuse xmemo-claude-plugin/skills/*/SKILL.md instead — see Tools |
| Encryption at rest | No | Same as upstream — honest that there isn't one, see Known Limitations |
dsh plugin add dsh-xmemo doesn't work today; install from GitHub
or a local checkout instead — see Quick start. Also not yet tagged with the
dsh-plugin GitHub topic, the harness's only discovery mechanism ("Contribute to the ecosystem"
in CONTRIBUTING.md)
— DeepSeek Harness has no central plugin marketplace or submission process by design.dsh instance (no desktop session to open a
browser in) can't complete it — use the static API key there instead.XMEMO_OAUTH and XMEMO_OAUTH_ACTION appear in $DSH_HOME/.credentials.yaml and the Models
page's credentials list, alongside XMEMO_MODE — an accepted tradeoff of reusing the one
channel that's actually open to an out-of-tree plugin (see the web GUI card limitation below).
XMEMO_OAUTH holds the access/refresh token pair as an opaque JSON blob; XMEMO_OAUTH_ACTION is
a transient write-only signal, never holding anything meaningful at rest; XMEMO_MODE isn't a
secret at all.dsh processes writing to the same store directory
are not coordinated; run one instance per store directory.xmemo-cindy-plugin's tool descriptions
claim email/phone redaction, but no such code exists in main.js either — it's server-side or
aspirational. This port's tool descriptions say only what the code does.cloud_id, not richer response fields — see Architecture notes.apiKeyCredential, and mode; the other five
config fields aren't editable from the browser at all. The harness's generic
settings-persistence pipeline (ctx.settingsScope) is gated by a hardcoded namespace allowlist in
deepseek-harness's own packages/host/apiproxy/src/api-proxy.ts (WEB_SETTINGS_NAMESPACES) that
an out-of-tree plugin cannot extend from its own package (the source comment there calls
generalizing it "deferred work"). Only the ungated credentials.* RPC is open to third-party
plugins today — the same channel apiKeyCredential already used for its API key — so mode and
OAuth both piggyback on it too (XMEMO_MODE, XMEMO_OAUTH/XMEMO_OAUTH_ACTION), and the
remaining five config fields have no open channel to bind to at all.credentials.describe reports configured/writable but never a credential's value — correct
for secrets, but it means the mode select can't be pre-filled with the true stored mode the way
Cindy's /kv-backed selector can. The select always starts from the hybrid default; saving
always overwrites blindly, same as the API key field already does.configured/writable booleans (credentials.describe) — it can change the API key, OAuth
tokens, and mode, but never read their values back.XMEMO_OAUTH
credential reference; refresh tokens rotate on every use, and a reused (already-consumed) refresh
token is rejected server-side rather than silently accepted.src/redact.ts,
7 categories, ported verbatim from upstream) — a safeguard, not a substitute for keeping secrets
out of prompts.xmemo_forget soft-deletes unless a caller explicitly
requests a hard, permanent delete.XMEMO_KEY), never values.Canonical service policies: Privacy policy · Terms of service · Support
npm install
npm run build # tsc -> lib/ (host half)
npm run build:client # tsc --emitDeclarationOnly + esbuild -> lib/client.js (browser half)
npm run typecheck
npm test # node --test over tests/*.spec.ts
| Field | Value |
|---|---|
| Package | dsh-xmemo |
| Plugin ID | xmemo |
| Runtime | DeepSeek Harness (dsh) |
| Version | 0.1.0 |
| Role | Native Cordis plugin + web GUI settings card |
| Service | https://xmemo.dev |
| Backend | MemoryOS REST API (not MCP) |
| Authentication | OAuth 2.1 + PKCE (recommended), or static API key via XMEMO_KEY |
| OAuth scopes | memory:read memory:write |
| Tool profile | 16 tools, same names/schemas as xmemo-cindy-plugin |
| Local storage | Yes — JSON hybrid store with a durable outbox, not encrypted |
| Repository | https://github.com/yonro/xmemo-deepseek-plugin |
| License | MIT |
MIT © 2026 Yonro
FAQs
Native DeepSeek Harness (dsh) plugin: hybrid local and XMemo cloud memory for Cordis-based agents.
We found that dsh-xmemo demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
A new federal program will let vetted U.S. cybersecurity firms help investigate and disrupt foreign cybercrime groups under government direction.

Research
/Security News
The campaign amassed more than 75,000 installs by targeting Russian-speaking users seeking access to blocked services.

Company News
Open source maintainers are under more pressure than ever. We're raising our open source program from the Team plan to the Business plan, free.