← Back to home@lmzhen

dsh-evolution

Hermes-inspired agent self-evolution plugin family, purpose-built for DeepSeek Harness

Stars
1
Language
TypeScript
Created
Aug 16, 2026
Updated
Sep 18, 2026

Introduction

dsh-evolution — self-evolving memory & skills for DeepSeek Harness

English · 中文

npm release CI license

One install. The agent keeps notes about your project, and improves its own skills.

Contents: What it is · Should you install it · Install · Choose your install · How it works · Day to day · Turn it down or off · Boundaries · Limits · Troubleshooting · Docs

Community-published packages under @lmzhen are maintained by the dsh-evolution community and are not official DeepSeek releases; they use neither the @deepseek-ai/* package names nor DeepSeek branding.

What it is

30 composable Cordis plugins that give a DeepSeek Harness install a self-evolution layer: the agent reviews its own conversations, keeps memory, proposes and patches skills, and curates that skill library over time. The model may only write memory and skills — policy, prompts, routing, state and audit history are control-plane data it can never touch.

It is not a model, not a hosted service, and not a GUI of its own: what it adds is model tools, slash commands, and files under your own $DSH_HOME.

Should you install it

Install it if you are tired of re-explaining the same project to a fresh session, or of hand-maintaining a pile of skills that never improve. Then:

  • Facts survive. A review writes what mattered into memory; later sessions get it injected automatically.
  • Skills improve themselves. The agent patches its own skills from what actually happened, with plans validated before execution — and a curator that merges near-duplicates and archives what stopped being used.
  • You stay in control. Every write passes a threat scan and an immutable policy; with one flag, every write also waits for your approval. Skill destruction is never a hard delete.
  • You can see everything. Counters, run reports and a mutation log live in files under $DSH_HOME. No telemetry service, nothing leaves your machine except the prompts you already send.

Skip it if you want a fully hands-off black box, or if you need per-session tools without profile-wide automation (that is install form ①: packages/INSTALL.md has the forms and their verified status).

Install

dsh plugin --profile web add @lmzhen/dsh-evolution-all   # the DEFAULT full bundle
# restart the host so the profile is recomposed, then in any session:
/evolution doctor

You should see 29 packages installed (the published list is 30; @lmzhen/dsh-evolution-preset ships as an agent preset, not as a node_modules plugin), and after the restart a doctor report naming your install form and the rows it found. Verify without asking the model anything:

dsh --profile web --dump-config | grep -c 'id: evolution-'   # 19 rows
dsh --profile web --dump-config | grep -c 'id:'              # 209 ids, all distinct

Nothing writes on boot: the first review waits for the interval window. Want every write gated by your approval instead of full-auto? Add approval.enabled: true (that is mode M2).

Choose your install (M1–M4)

The M numbers are defined HERE; the install forms and their per-platform status are single-sourced in packages/INSTALL.md.

ModeHowWhat you get
M1 Full-auto (DEFAULT)dsh plugin --profile web add @lmzhen/dsh-evolution-allBoth loops run and write; model tools in every session
M2 Human gatedM1 + approval.enabled: trueEvery write appears as /evolution pending for you to approve or reject
M3 Infrastructure onlydsh plugin --profile web add @lmzhen/dsh-evolution-hostAutomation runs, the model gets no memory/skill tools
M4 Per-session (advanced)M3 + /evolution preset installTools only in sessions that select the Evolution preset (exclusive with M1 and the legacy one-click preset)

Mount exactly one of these: the bundles share infrastructure rows, and the loader aborts at startup on duplicate ids. The bundle also pins provider: json on the state row, so an unrelated overlay cannot silently move your state onto an empty domain.

Compatibility

Value
Validated DSH platform line0.1.5-rc.2 (PLATFORM_VERSION; UPSTREAM_SHA=fb2c4b9e…)
Declared dependency window^0.1.5-rc.2 on every @deepseek-ai/dsh-* dependency/peer
Family version0.7.0 (npm latest; per-form status in packages/INSTALL.md)
Node22.19+ or 24+ (engines)

A prerelease range admits one anchor, not a family of them: ^0.1.5-rc.2 rejects later prerelease successors while admitting stable 0.1.5. Earlier prerelease lines fail at dependency resolution — that is the support window, not a bug.

How it works

LayerWhat it doesWhat you notice
Reviewwatches session events, applies the substantive gate, produces a validated plan (evolution-review, evolution-plan-validator)reviews happen at conversation boundaries, not mid-task
Memory loopwrites durable facts and a user profile, injects guidance into new sessions (memory, memory-files, tool-memory)new sessions already know your project
Skill loopproposes, writes and patches skills through the skill_manage tool; the catalog exposes them to the model (tool-skill-manage, evolution-skill-catalog)skills you did not have to write yourself
Curatordeterministic stale/archive lifecycle plus LLM nomination, with a snapshot before every run (evolution-curator)the library stays small and merges duplicates
Control planethreat scan, immutable policy, optional staged approval with replay (evolution-threat, evolution-policy, evolution-approval)a refused write tells you why, and nothing destructive is silent
PlumbingIO seam, state providers, events, activity, replay, learning graph (evolution-io*, evolution-state*, evolution-activity, evolution-replay)everything is a file you can read, back up or delete
$DSH_HOME/evolution/events.json      append-only feedback/usage timeline
$DSH_HOME/evolution/review-state.json  per-session review counters
$DSH_HOME/evolution/activity.json    plan outcomes          reports/  curator run reports
$DSH_HOME/skills/                    the skill tree (+ .usage.json)
$DSH_HOME/memories/                  MEMORY.md + USER.md

Two defaults worth knowing up front. Reviews run in-session (reviewMode: 'inject', the default since 0.3.74) — nothing is spawned, so there is no separate review ledger; subagent is an explicit opt-in for a clean parent context or a dedicated model. Cross-session consumers are session-scoped: review and usage telemetry act on a session only if that session can resolve the family's model tools — true for every session under M1, never true for a host-only install (M3), which the plugin reports once instead of failing silently.

Day to day

  • /evolution doctor reports what is installed: form, scoped rows, services, pending count.
  • /evolution pending + approve / reject handle the staged writes (M2).
  • /evolution curator status shows the last run and the next due time (the curator ticks hourly; a run is due every 168 h by default, so quiet weeks are normal).
  • /evolution preset install [--base <name>[,<name>...]] generates the family agent preset (M4).
  • /evolution mutations (the write log) and /graph (skills and memory as a graph).

The full command surface is rendered once in packages/README.md (§Command reference); the complete environment-variable and field-level knob reference lives there too.

Changing parameters from the GUI

The family ships exactly one browser surface: a settings section named 自进化. It lists the user-writable parameters of the review, memory, curation and skill namespaces as collapsible cards — each field carries its unit, where the current value comes from (部署 deployment / 用户 your override), a control typed from the parameter registry (switch, dropdown, number, text) and the registry's own explanation. Edit and press 保存; 放弃修改 drops the draft, and 恢复部署默认 removes your override for one field.

Writes land in ~/.dsh/settings.yaml under the owning namespace and take effect live, without a restart. The same store is writable from a session with /evolution policy set <id> <value>, and /evolution params prints every registered parameter with its tier, timing and current source. Deployment-side knobs (resource limits, provider choice, prompt-affecting identity) stay in cordis.yml / the profile patch layer — the section lists only what a user may change, and the doctor's divergence section reports the two sides disagreeing.

Turn it down or off

DialValuesField
autonomyauto / reviewed / observeapproval.enabled, reviewEnabled
scopeglobal / per-sessionevolution-all vs host + agent preset
curatorBackgroundon / offautoStart / curatorIntervalHours / minIdleHours
memoryInjectionon / offmemoryEnabled (off = the whole row is a no-op)
threatStrictnessstrict / exempt-listthreatExemptLabels (declared per config site; the owning list is single-sourced in evolution-threat/README.md)

Three ways down, in increasing order of silence: gate it (approval.enabled: true), stop reviewing (reviewEnabled: false), or shrink to M3 (no model tools at all). Defaults that surprise people: reviewEnabled: true, reviewMode: 'inject', reviewMemoryInterval = reviewSkillInterval = 10 turns, substantive gate = "≥3 tool calls or ≥200 user characters or ≥500 agent characters", curator due-ness 168 h.

Environment variables (complete list)
VariableWhere readEffect
DSH_EVOLUTION_SESSION_QUERYprofile configstartup / first-search / never (SQLite index openAt); invalid values normalize to startup
DSH_EVOLUTION_SESSION_QUERY_PATHprofile configdurable index path; empty falls back to $DSH_HOME/evolution/session-query.db
DSH_EVOLUTION_ALLOW_ROW_COLLISIONSplugin code1 downgrades a preset delta-row collision from fail-loud to warn+keep-both
EVOLUTION_SCOPEsource installers onlyscope written into generated profile/preset rows; the plugin runtime never reads it
DSH_EVOLUTION_DELTA_PATHsource installers onlyoverrides the agent-preset delta fragment the layered installer composes from
DSH_AGENT_PRESET_ROOTsource installers onlyoverrides the .agent-presets root the preset variants install into; must exist when set
DSH_EVOLUTION_ARCH_STRICTguard scripts only1 makes the architecture-duplication guard fail loud (same as --strict)
DSH_EVOLUTION_DECLARED_CONFIG_STRICTguard scripts only1 makes the declared-config-reach guard fail loud (same as --strict)

Security & boundaries

  1. The model writes memory and skills only. Everything else is control-plane data.
  2. Every mutation is gated by the tools.guard threat scan, and by staged approval when enabled; an approved write replays through the exact runner it registered with.
  3. Nothing is destroyed silently. Skill archival moves to .archive/, and every curator run snapshots the skill tree first.
  4. Text leaving the session for a model is redacted (PEM blocks, URL credentials, inline assignments, camelCase credential keys).
  5. No telemetry. Counters and reports are files under $DSH_HOME; the family publishes no ./invariant companion, because the platform would never execute one.

Known limitations

  • reviewMode defaults to inject: reviews run in-session and produce no evolution/plan-applied ledger, so the activity store and replay views stay empty until you opt into subagent reviews.
  • Session-scoped consumers never match on a host-only install (M3), and on M4 only sessions on the Evolution preset match.
  • The only GUI surface is one settings section (自进化): the family adds slash commands, model tools and that parameter panel — nothing else in the browser UI.
  • One platform anchor: a new platform line needs a family migration, not a config bump.
  • npm dist-tags.next is stale at 0.3.18 (historical residual); latest is correct and is what add resolves.

Troubleshooting

Nothing has been written yet. The first review waits for the interval window (memoryInterval / reviewSkillInterval, default 10 turns) and the substantive gate — a one-line session is deliberately not worth a review.

activity.json is empty. That is inject-mode behavior, not a failure; see the first limitation above.

How do I check the running version? Compare profiles/<name>/pnpm-lock.yaml with npm view @lmzhen/dsh-evolution-all version; the profile is recomposed at host restart.

A threat scan refused a write. Rephrase it, or exempt a known-innocent label via threatExemptLabels.

Error codes
CodeMeaningNext step
startup invariants: package "…" is already registeredtwo bundles double-mount the same rowskeep ONE of evolution-all / evolution-host / evolution-preset
E-301 / E-302 / E-303approval / curator / replay service not mountedmount the row (they ship with host/all), then run doctor
E-306this deployment stages foreground writes, but the named command is not replayable through the skill runnerapprove-and-execute it directly, or set stageForeground: false deliberately
E-304the mounted approval service predates the release capability (a skewed/partial upgrade)reject the pending record instead of release
E-305the invocation carries no agent (a script/headless caller reached a session-backed branch)run the command from a session in the GUI or the CLI
doctor says install form: noneno bundle installeddsh plugin --profile web add @lmzhen/dsh-evolution-all

Uninstall

dsh plugin --profile web remove @lmzhen/dsh-evolution-all

The loops stop, your data does not: memory, skills, state, reports and approval history stay under $DSH_HOME and are picked up again on reinstall.

Documentation index

DocumentWhat it holds
INSTALL.mdinstall forms, scopes, profile override examples
packages/INSTALL.mdinstall-form semantics and the per-platform verification matrix
packages/README.mdcommand reference, package map, environment/knob reference, layout notes
CHANGELOG.mdwhat changed in each version, with reasons and evidence
CONTRIBUTING.mdwhere a fact may live, the 18-step gate, house rules
For maintainers: upstream upgrade checklist
  1. Skill-provider shadow rank. Our provider registers EVOLUTION_SKILL_RANK = 390 and relies on the upstream USER_DSH_RANK (400 on 0.1.5-rc.2) sorting above it; re-verify both sides.
  2. @deepseek-ai name collisions. The release tooling rewrites family names to @lmzhen; check each upstream release for names that collide with ours.
  3. ToolRuntime argument freeze. tool.execute gets a deepFreezed snapshot: build a new object rather than assigning onto args.
  4. Per-skill invocation frontmatter. Our shadowing provider must keep parsing the same keys as upstream; its legacy-key posture is single-sourced in evolution-skill-catalog/README.md.
  5. Home-path semantics. Upstream resolveDshHome trims only as the adoption test, keeps the RAW env value, expands ~ and always resolves; evolutionRoot and install-layered.mjs follow the same line.

License and attribution

MIT — see LICENSE. The design is inspired by Hermes Agent (MIT); this is an independent implementation, not affiliated with or endorsed by Nous Research or DeepSeek. Issues and feedback are welcome on the repository — since the family ships no telemetry, a report that includes your /evolution doctor output is the fastest path.