Memory

dsh-anagenesis

3likofj/dsh-anagenesis · ★ 2

3likofj

anagenesis —— DeepSeek Harness 上的可编程记忆编排层 + 自我进化引擎:自带闭环记忆存储(不依赖任何外部记忆插件)、17 个面向 Agent 的语义记忆工具(召回/提交/提升/降级/拆分/锁定/过期/反事实重思)、运行时可切换的注入策略、带审计与回滚的元策略自调节、全程可逆效应、自动注册 `anagenesis` Agent 预设…

License
Apache-2.0
Added
2026-10-30
Maintenance
active
Install kind
github
npm
dsh-anagenesis
Manifest status
Declared
Manifest path
package.json#dsh
Manifest checked
2026-10-30T09:38:05.346Z
Lifecycle scripts
None found

Static manifest checks report declarations only; they are not compatibility or security review.

安装

dsh plugin --profile web add 'github:3likofj/dsh-anagenesis#5dc27762eda0abc7ccf8d26919b4605811dbe327'

GitHub 源码安装:首次需按提示配置 allowBuilds 构建授权后重试

For install and environment setup, plus plugin development tutorials, see DSH community docs ↗

README

Source README · body: en · Read Chinese README

Table of contents
  1. At a glance: how it differs from an "automatic memory" plugin
  2. Four things you feel immediately
  3. New in 0.4.0: measure first, then change
  4. Benchmark (same corpus, 0.3.2 → 0.4.0)
  5. New in 0.3.0: one package, and a facility floorplan
  6. New in 0.2.0: memory is isolated per project, and the preset is a permission switch
  7. What makes it different
  8. What it is, in three lines
  9. Scope: a memory belongs to a project
  10. The preset is a permission switch, not a suggestion
  11. How it differs from a typical "automatic memory" plugin
  12. Install
  13. One command
  14. From source (if you want to hack on it or track main)
  15. Five minutes in
  16. Capability map (20 tools, layered by permission)
  17. Injection strategy: which brain for which moment
  18. Every change can be undone
  19. The boundary on self-direction (why it does not drift)
  20. What you can see
  21. Where the data lives, and privacy
  22. Configuration (all optional, all with safe defaults)
  23. FAQ
  24. License

Memory your agent actually owns — and you can actually see.

Not another "automatic memory black box": memory operations are 20 semantic tools the agent calls on purpose; the injection strategy is a switchable stack of pure functions; every change carries its inverse, lands in the journal and can be reverted; the whole store is self-contained, offline and dependency-free.

中文 · Changelog · Apache-2.0

npm license runtime deps

Listed on dsh-plugin.org dsh.so risk dsh.so install · dsh 0.2.0-rc.2 dshfind

The anagenesis desktop window — the facility floorplan (default face)

At a glance: how it differs from an "automatic memory" plugin

Typical memory plugin anagenesis
Who writes a background extraction pipeline; the model never knows what was recorded the agent calls ana_remember / ana_promote / ana_link — it decides what to write and why
How retrieval works one fixed similarity pipeline 7 intents (orient / recall_fact / recall_precedent / avoid_mistake / reuse_procedure / verify / contrast) × 6 switchable strategy stacks
When it is wrong edits are edits every change is a declarative patch with revert(); the journal is the only truth, auditable and revertible after a restart
Who can see it shared globally, on trust project fingerprints isolate by default; crossing projects needs explicit authorization and is labelled per row; the preset is a permission switch (write tools literally do not exist without it)
What it depends on vector DB / cloud / model calls zero runtime dependencies, offline, plain JSONL; the only network egress is an optional version check
Quality evidence a demo video a bundled offline retrieval benchmark: 211 memories × 41 queries, reproducible with npm run bench

Four things you feel immediately

  1. It does not get dirtier the more you use it. Irrelevant memories are not injected just to fill the budget; superseded beliefs stop appearing; ana_recall reports exactly who was excluded and why (excluded.nearMisses).
  2. You never lose the "why". Every record carries kind / state / confidence / provenance / links, and those links participate in retrieval (one-hop graph expansion) instead of being decoration.
  3. Every change is reversible. Single-writer mutex + event sourcing + frozen snapshots; revert(seq) still works after a restart — and reverting an audit row is explicitly refused.
  4. Nothing hides when it goes wrong. The facility view draws the store as floors (namespaces) × zones (memory kinds) × sensors (records), with readings, an energy baseline, anomalies and a live wire; the dashboard face is an 11-section health report.

What it deliberately does not do: no background extraction, no bridging to other memory plugins, no model calls, no subprocesses, no telemetry. Uninstall it and your memory is still a pile of readable JSONL.

New in 0.4.0: measure first, then change

No new tools and no new dependencies. This release is about whether every injected token earns its place. Storage moves to v8 (automatic migration, one added field).

Change Before Now
Relevance floor none: the budget was always filled absolute + relative floors, scaled per intent; empty-query briefings are exempt
Lexical score raw BM25 (longer records win) IDF-weighted coverage: in-vocabulary coverage ranks, full coverage gates
Vector term (cos+1)/2: every record collected 0.5 max(0, cos): unrelated is 0
Redundancy sort once, then subtract a penalty real MMR over a bounded shortlist; a candidate that does not fit leaves the pool
links drawn in the graph, never used in retrieval one-hop expansion: supports/part_of/caused_by can rescue context the gates dropped
Supersession supersedes was never written ana_link rel=supersedes writes both sides; replaced beliefs are no longer injected (includeSuperseded shows history)
Time decay read updatedAt (linking a record made it "fresh") reads confirmedAt (promotion/lock counts as confirmation)
Writes exact-string dedupe only near-duplicate top-3 + suggested action; supersedes: [id...] consolidates in one transaction
Meta-tuning four knobs with no consumer every knob wired or removed; rewards come from the post-change window; one change in flight
Recall output rejection counts only excluded: counts by reason + the three strongest near misses with why

Benchmark (same corpus, 0.3.2 → 0.4.0)

211 deterministic synthetic memories × 41 queries with gold answers, covering exact / paraphrase / graph / supersession / scope / no-relevant-record cases:

Metric 0.3.2 0.4.0
nDCG@10 0.903 0.974
MRR 0.780 0.854
Recall@5 0.963 1.000
Precision@5 0.180 0.809
Contamination (injected but irrelevant) 0.908 0.193
Records injected per query 11.6 1.6
Tokens per relevant record 627 162
Records injected for a no-match query 8.3 0.0
crossProject: true hits 0 1.0

npm run bench reproduces it; bench/baseline.json is the regression gate. The corpus is synthetic and deterministic — not a substitute for real sessions, but it makes every scoring change comparable and revertible.

Upgrade note (behaviour change): storage v7 → v8 migrates automatically; records that are not relevant are no longer injected just to fill the budget, so recall may return less — that is the honest answer, and ana_recall's excluded report says who was left out and why. recall.explorationRate was removed (it never had any effect).

New in 0.3.0: one package, and a facility floorplan

Two things this release: the two plugins became one (the window is no longer a sibling package you install separately), and the dashboard became a facility view — the memory store drawn as a building you can actually operate.

New In one line What you see
One package dsh-anagenesis-window folded into dsh-anagenesis: one package, six Loader rows (each still individually disabled: true), one dsh.client half A single install command; row ids and tools unchanged
Facility view (default face) floor = namespace (current project / global / each session), zone = memory kind, sensor = one live record Icon rail / floorplan / zone detail / status bars
Real readings salience / confidence / freshness, and "per-record energy in this zone vs the measured building average" No number reaches the screen that the model does not contain
Anomaly desk contradicting links, expiring soon, loud-but-stale, dangling links, locked, safe mode, redaction off, read-only tier Each one carries a count and why it matters
Live wire the real tail of the journal, scrolling at the bottom What you just changed, at a glance
Host 0.2.1-rc.2 all peerDependencies raised to ^0.2.1-rc.2, re-verified with a real Cordis over 98 boot-contract checks It installs, and it boots

Upgrade note (breaking): the old dsh-anagenesis-window package is no longer maintained. If you installed it, remove it (dsh plugin remove dsh-anagenesis-window, or delete that row from the profile bundles) and keep dsh-anagenesis only — the window is its sixth row now. The window route moved to /anagenesis/api. The storage format did not change (still v7); nothing to migrate.

New in 0.2.0: memory is isolated per project, and the preset is a permission switch

Two real defects drove this release: one project's experience was recalled in another, and the model could write memories with no preset enabled.

New In one line What you see
Memory scope Every memory carries global / project (default) / session; recall returns the current project + global + the current session only A new scope section in the dashboard: current project in cyan, other projects in yellow, global and legacy untagged at a glance
Project fingerprint p1_<hash> from the git remote (preferred) or the working directory — a pure function, stable across restarts, so two checkouts of one repo are one project Directory changes, machine changes and new sessions cannot misidentify the project
Crossing needs authorization crossProject: true admits another project's memories, down-weighted and each one labelled "⚠ experience from another project — do not follow it blindly" The block itself says what not to trust
Conflicts are downgraded When a foreign memory is semantically similar to a local one but opposite in content, its effective confidence is halved and the pulse says to trust the current environment Only that answer's projection changes — the store is never rewritten by a read
Physical isolation Journal segments are per namespace (journal-<ns>-*.jsonl); global memory keeps its own files; a pre-0.2.0 store loads byte-for-byte node tools/scope-report.mjs shows who owns how many records, in which file
The preset is the permission layer Write tools are registered only while the anagenesis preset is on; gears passive (read) / assisted (write) / autonomous (may self-schedule) ana_preset action="status" is the authoritative answer to "what do I actually hold"
Checked at execution time ctx.tools.guard() plus each tool's own grant check: unregistered means unreachable, and a cached definition refuses once its grant is revoked Prompt rules are the second line, never the only one
Status pulse Every step carries <anagenesis-pulse>: the project fingerprint, the gear, the tools in hand The model can check "may I use this memory" itself
Session memories expire Session-tier writes get a 24h TTL by default; ana_scope action="drop-session" reclaims them in one revertible transaction Scratch state cannot quietly become a permanent belief
New tools ana_list (list by scope), ana_scope (status / list / namespaces / retag / adopt / drop-session) retag is revertible; widening a project memory to global needs an explicit user authorization

Upgrading (breaking): the store migrates from schema v6 to v7 automatically. Records that carried a workspace are filed under the right project; the rest are marked migrated-global — still recallable, but down-weighted, and ana_scope action="adopt" files them back under the current project. Restart the desktop app so the new tool layering loads.

What makes it different

  • Scope is a first-class citizen of the store, not a filter applied at query time: writes, journal partitioning, recall filtering, by-id reads and the visualization all share one namespace decision — so "whose experience is this" holds at the filesystem level too.
  • The preset is a permission switch, not a prompt bundle: the gear decides whether a write tool exists, not whether it should be used. The host offers no permission field on a tool definition, so we use the only reliable lock there is: registered or not registered.
  • One seq space plus declarative patches: because the journal is not sharded per project, revert(seq), the audit trail and every handle a tool returns stay globally unique — isolation lives in the files, revertibility in the counter.
  • Physical isolation without breaking old data: every namespace owns its live and archive segments, while the global namespace keeps the original unprefixed names, so a store written before 0.2.0 loads unchanged.
  • Falsifiable claims: 150 core tests + 91 window tests + a 98-check boot sandbox that runs the real Cordis, the real defineTool and the real preset registry + a reproducible offline retrieval benchmark — the real row code, not a mock of it.

What it is, in three lines

  • A self-contained store: an append-only journal/*.jsonl plus atomic snapshots. It never calls, bridges or proxies an external memory service — no database, no cloud, no model calls.
  • Memory as tools the agent drives (17 ana_* tools): recall is shaped by intent (orient, recall_precedent, avoid_mistake, reuse_procedure, …), not by background extraction.
  • It governs its own behaviour, too: switchable injection stacks, bounded meta-level self-tuning, a monotonic guard, and a revertible history for all of it — with a trail you can audit.

Scope: a memory belongs to a project

Every memory carries a scope tag, by default — there is nothing to configure:

Tier When Who can recall it
global facts that hold everywhere (team conventions, tooling) every project
project (the write default) conclusions that hold here only the current project
session scratch state for one task; expires after 24h by default only the session that wrote it
  • The project fingerprint (p1_<hash>) comes from the git remote (preferred) or the canonicalised working directory: a pure function, stable across restarts. Two checkouts of the same repository are the same project.
  • Recall returns only the current project + global + the current session. Crossing projects needs an explicit crossProject: true: those hits are down-weighted and each one is labelled “⚠ experience from another project — do not follow it blindly”.
  • Conflicts are called out. When another project's memory is semantically similar to a local one but opposite in content, its effective confidence is halved for that answer and both the block and the status pulse say “ignore the historical experience; trust the current environment”. Only the projection changes — a read never rewrites the record it read.
  • Storage is partitioned as well: events are written per namespace (journal-<ns>-*.jsonl), global memory keeps its own unprefixed files, and a pre-isolation store still loads unchanged (those records are marked migrated-global and down-weighted; ana_scope action="adopt" files them back under the current project).
  • Inspect a store: node tools/scope-report.mjs (read-only: namespaces, known projects, files, gears).

The preset is a permission switch, not a suggestion

Installing the plugin gives the model eyes only: what gets registered is the read tier (ana_recall, ana_list, ana_audit, ana_dashboard, ana_diagram, ana_window, plus the inspection actions of ana_scope / ana_preset / ana_strategy / ana_tune). The write-tier tools exist only while the anagenesis preset is enabled — not discouraged, simply never registered, so the model cannot see them.

Gear Write tools Extra
passive none registered read, audit, visualize, inspect
assisted (preset default) registered every write is an explicit tool call by the agent
autonomous registered the plugin may schedule the stack (a reported failure switches to debug) and crystallize repeatedly-cited drafts — both audited, both with a seq
  • The gear lives in the preset config (gear:); at runtime ana_preset action="gear" reports it and can lower it. Raising it needs the host — an agent cannot widen its own permissions.
  • Switching and unloading roll back exactly: dropping to passive unregisters each write tool; unloading the preset returns the tool set to the read tier.
  • The permission check runs at execution time (ctx.tools.guard() plus each gated tool's own assertGrant), so a cached definition refuses to run once its grant is revoked. Prompt rules are the second line of defence, never the only one.
  • The agent sees an <anagenesis-pulse> every step: current project, gear, and the tools it holds.

How it differs from a typical "automatic memory" plugin

Dimension Typical automatic memory anagenesis
Who decides what is stored Background extraction; the agent is not involved The agent decides, with tools: ana_remember, ana_promote, ana_split, ana_rethink, ana_forget
How recall works Keyword or vector similarity Intent-driven: 7 intents expand into kinds, states, confidence floor, weights, granularity, token budget, diversity
Who can see it One shared store for every project Isolated per project: writes default to the current project; crossing needs explicit authorization and is labelled
Who can write it Anything installed can write The preset is the permission layer: without it the write tools do not exist; gears passive / assisted / autonomous
Injection strategy Fixed Switchable at runtime (6 named stacks), and stacks are per scope — one agent switching does not touch another
What a change costs Usually irreversible Every transaction returns an inverse; inverses are journalled next to the forward patch, so reverts survive a restart
Self-tuning None The meta layer tunes itself from feedback: parameter envelope + UCB1 + audit + evaluation + rollback
Blast radius — Monotonic guard + circuit breaker + safeMode; only tier-1 is self-modifiable, the outer ring is frozen
Dependencies Often an external service or vector DB Zero runtime dependencies, offline, no subprocess; the only network request is an opt-in update check (one GET, one line to turn off)
Visibility A black box TUI dashboard + mermaid/d2/ascii diagrams + an optional desktop window

Install

One command

One package, six Loader rows (kernel / read tools / guard / preset / visualization / desktop window); dsh plugin add pulls the latest from npm: dsh-anagenesis.

dsh plugin add dsh-anagenesis

Then restart your profile. Installing registers an agent preset called anagenesis — pick it in a new session.

Upgrading from 0.2.x: remove the old window package first (it is no longer maintained), then restart: dsh plugin remove dsh-anagenesis-window (or drop that row from the profile bundles).

From source (if you want to hack on it or track main)

git clone https://github.com/3likofj/dsh-anagenesis.git
cd dsh-anagenesis
dsh plugin --profile desktop add link:<absolute path to this repo>

window/ is just a directory of this package now (client half + render layer + window host half), not a second package.

Five minutes in

  1. Install, restart the profile, and select the anagenesis preset in a new session (default stack guard + exploit).
  2. Just work: the agent calls ana_recall and ana_remember itself — there is no query language to write.
  3. To look at the store, ask the agent for ana_dashboard (one TUI frame, right in the answer) or ana_diagram (a diagram you can paste into Markdown).
  4. For a live view in a real terminal: node tools/viz-watch.mjs --watch (read-only, separate process).
  5. For the desktop window: restart, then call ana_window (it opens the facility view) or click an entrance.

Capability map (20 tools, layered by permission)

Read tier — installed with the plugin

Group Tools What they do
Recall ana_recall · ana_list Retrieve by intent (current project + global + current session by default); list what the store holds, with scope labels
Inspection ana_audit · ana_scope · ana_preset · ana_strategy · ana_tune Status / journal / audit / one memory; the scope report; gear and permissions; the strategy roster; tuning metrics
Visualization ana_dashboard · ana_diagram · ana_window TUI dashboard (with a scope section), text diagrams, desktop window

Write tier — only while the anagenesis preset is enabled

Group Tools What they do
Write & lifecycle ana_remember · ana_promote · ana_demote · ana_lock · ana_expire · ana_forget Writes default to the current project; draft → active → verified → locked, or demote / expire / forget (a forget leaves an auditable tombstone)
Structure ana_link · ana_split · ana_rethink Links; split an overloaded memory (children inherit the parent's scope); counterfactual re-reasoning
Feedback & correction ana_feedback · ana_scope action="retag"/"adopt" · the mutating actions of ana_strategy/ana_tune Report actual use; re-file a scope (revertible); switch stacks / tune the meta layer (admin gear)

Injection strategy: which brain for which moment

Named stack Composition Best for
explore guard + explore Still mapping the problem: high recall, low bar, writes land as drafts
exploit guard + exploit Executing a known plan: inject only verified/locked beliefs, writes take effect immediately
debug guard + debug The moment things break: failures and open hypotheses first, time decay off
distill guard + distill Long sessions where tokens matter: compression first
recon guard + explore + distill Open up, then tighten
crisis guard + debug + exploit Repeated failure: failures and verified facts injected together

guard is an invariant: always at the bottom, injecting nothing itself — it only weights locked beliefs up, drafts down, and keeps retired records out. Strategies are pure function bundles with bounded parameters: an agent may only derive a strategy by naming a built-in implementation plus a parameter delta. An agent that can persist arbitrary code is an agent that can brick its own harness.

Every change can be undone

  • A change is a declarative JSON patch, never a closure. The store serializes all writers: append to the journal first, then swap in a frozen snapshot (readers never lock).
  • transact() returns revert(reason), which commits the inverse as a compensating event in the same journal — so reverts still work after a restart.
  • ana_strategy action:"revert" and ana_tune action:"rollback" are thin wrappers over that one primitive.
  • The journal has three bounds: segments are merged when there are too many (merging drops no seq), only the newest checkpoint is kept, and the single lossy retention policy is off by default — and when it ever drops something, the status view says so instead of pretending the seq never existed.

The boundary on self-direction (why it does not drift)

It can direct itself — behind a frozen outer ring.

  • tier 1 (self-modifiable): memories, strategy stacks, tunable parameters. The agent can recall its own past failures, derive strategies, and adjust its confidence floor and token budget from feedback it collected.
  • tier 2 (frozen): the parameter envelope, the tunable-namespace allow-list, the existence of guard, tool schemas, and the plugin code itself. A running agent cannot touch any of it.

The reason is blunt: an agent that can rewrite its own fitness function and its own brakes drifts towards "scores well" instead of "actually works", with no recoverable state to roll back to. The boundary is enforced (8 monotonic invariants plus the safeMode freeze), not a slogan.

What you can see

Facility view — floorplan / zone detail / anomalies / wire

When a newer version exists, the top bar grows one pill (this is the real 0.3.1 → 0.3.2 case):

The "new version available" pill in the top bar (example v0.4.1)

Memory graph (horizontal)

Lifecycle transitions

Strategy timeline

Dashboard

  • TUI dashboard (ana_dashboard): overview, lifecycle distribution, kind distribution, strategy stacks and health, tuning knobs that deviate from their defaults, journal tail, salience ranking, and the renderer's own health. Width-exact, including CJK labels; colour only when asked for.
  • Text diagrams (ana_diagram): Mermaid (default) / D2 / ASCII, three kinds — the belief graph (with supports / contradicts / supersedes edges), the strategy timeline, and observed lifecycle transitions (only what the journal really recorded; lock / expire style destination-only events are labelled as such instead of inventing a source edge).
  • Facility view (the window's default face, method=facility): floor = namespace, zone = memory kind, sensor = one live record; the only readings are real ones (salience / confidence / freshness / per-record energy vs the measured building baseline); the anomaly desk lists contradicting links, expiring soon, loud-but-stale, dangling links, locked, safe mode, redaction off and the read-only tier; the bottom wire is the real journal tail. No number reaches the screen that the model does not contain.
  • New-version notice (0.3.1): the facility top bar shows a v0.4.0 可更新 pill and the anomaly desk gets a row; the dashboard face gains an "update" section; ana_audit view=status reports current / latest / last check. It only tells you — it never downloads, installs or restarts anything.
  • Desktop window (sixth row of the same package): three faces — facility, dashboard, graph — sharing one set of pure functions that emit Chinese cards and a hand-rolled inline-SVG directed graph (LR/TB plus zoom), with three entrance seats (better-sidebar row / official right sidebar / conversation header), reading the store as a read-only mirror.
  • Rendering is a read-only projection: a render is not a transaction. The only optional write, auditRenders, is off by default; tools/viz-watch.mjs is an independent read-only process that can redraw continuously in a real terminal.

Where the data lives, and privacy

$DSH_HOME/anagenesis/
  journal/journal-000001.jsonl          append-only event log (the global namespace, original naming)
  journal/journal-<ns>-000001.jsonl     one segment per project/session namespace (physical isolation)
  journal/archive-<ns>-<seq>.jsonl      folded archives, per namespace (the `undo` is kept)
  journal/checkpoint-<seq>.json         frozen state at a boundary (one cache for the whole store)
  snapshot.json                         atomic startup cache
  • Memory is partitioned by namespace in the filesystem, not only filtered at query time: project:<fingerprint> and session:<id> events live in segments named after them, while global memory keeps the unprefixed journal-*.jsonl.

  • Entirely local: no model download, no model calls, no subprocesses; the only network request is the optional update check (updateCheck: npm in the shipped bundle, off in code — with off nothing leaves the machine at all).

  • Zero runtime dependencies: retrieval is a built-in BM25 inverted index plus a deterministic hashing embedder (192 dimensions). A real semantic backend can be injected at runtime.

  • Redaction on by default: tool and window output defaults to secrets — credential-shaped text is scrubbed and bodies are omitted. strict masks labels too; none is an explicit local-debug escape hatch, and the artifact warns about it.

  • Legacy directory compatibility: the default is $DSH_HOME/anagenesis; if the pre-rename $DSH_HOME/evolution holds more data, the plugin keeps using it and says so in the log, moving not a single byte. To move it, run npm run migrate:store (copy + per-file sha256 verification; the source is untouched).

Configuration (all optional, all with safe defaults)

Key knobs on the kernel row:

Key Default Effect
rootDir $DSH_HOME/anagenesis Store root; set explicitly and it is obeyed exactly (no legacy fallback)
safeMode false Freezes strategy registration, switching and tuning
recallDefaultTokenBudget 1600 Default token budget for injected recall
hookBudgetMs 8 Time budget for a single strategy hook (a timeout counts as a failure, never stalls recall)
compactAfterEvents 2000 Compact the journal past this many live events; 0 disables
archiveMaxSegments 16 Upper bound on archive segments (oldest are merged, no seq lost); 0 = unbounded
retainEvents 0 The single lossy policy: keep only archives newer than N events; 0 = keep everything
embedProvider hash Vector backend to open with; a semantic backend can be installed at runtime
reflectionEnabled true Periodic reflection: question established beliefs whose evidence has visibly decayed (filed as draft hypotheses only)
updateCheck off in code, npm in the bundle New-version check: off = fully offline; npm = every 6h read this package's latest from npm (read-only GET, no identifiers, never installs)
updateCheckIntervalMs 21600000 Check interval (also the cache TTL)
updateRegistry https://registry.npmjs.org Point this at a mirror; used only when updateCheck: npm

Also: exposeAuditTool / exposeTuneTool on the tools row; lang / redaction / width / auditRenders and friends on the visualization row; see window/README.md for the window package.

FAQ

Does it slow recall down? Strategy hooks have an 8 ms budget and a timeout counts as a failure; reads use a frozen snapshot and never lock.

Will the store grow into a mess? Lifecycle states, confidence, salience decay, expiry sweeps and counterfactual rethink are all explicit tools you can call to tidy up.

Does uninstalling leave anything behind? Each row releases the effects it created (tools, services, timers, routes, seats); once unloaded the journal handle is closed and the store directory can be deleted normally.

Can I use a real semantic retriever? Yes. Install a backend at runtime with service.useEmbedder(...), then reembed() to recompute stored vectors. Until then the status view keeps reporting that stored vectors are stale.

Why is the desktop window a separate package? A package that declares dsh.client may own exactly one active Loader row, and the kernel is five rows (the preset mounts them again). That is a DSH constraint, so the window is a single-row sibling.

License

Apache License 2.0 © 2026 dsh-anagenesis contributors