Memory
dsh-anagenesis
3likofj/dsh-anagenesis · ★ 2
anagenesis —— DeepSeek Harness 上的可编程记忆编排层 + 自我进化引擎:自带闭环记忆存储(不依赖任何外部记忆插件)、17 个面向 Agent 的语义记忆工具(召回/提交/提升/降级/拆分/锁定/过期/反事实重思)、运行时可切换的注入策略、带审计与回滚的元策略自调节、全程可逆效应、自动注册 `anagenesis` Agent 预设…
安装
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
Table of contents
- At a glance: how it differs from an "automatic memory" plugin
- Four things you feel immediately
- New in 0.4.0: measure first, then change
- Benchmark (same corpus, 0.3.2 → 0.4.0)
- New in 0.3.0: one package, and a facility floorplan
- New in 0.2.0: memory is isolated per project, and the preset is a permission switch
- What makes it different
- What it is, in three lines
- Scope: a memory belongs to a project
- The preset is a permission switch, not a suggestion
- How it differs from a typical "automatic memory" plugin
- Install
- One command
- From source (if you want to hack on it or track main)
- Five minutes in
- Capability map (20 tools, layered by permission)
- Injection strategy: which brain for which moment
- Every change can be undone
- The boundary on self-direction (why it does not drift)
- What you can see
- Where the data lives, and privacy
- Configuration (all optional, all with safe defaults)
- FAQ
- 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.

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
- 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_recallreports exactly who was excluded and why (excluded.nearMisses). - 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.
- 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. - 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
defineTooland 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/*.jsonlplus 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 markedmigrated-globaland 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 runtimeana_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
passiveunregisters 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 ownassertGrant), 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 profilebundles).
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
- Install, restart the profile, and select the
anagenesispreset in a new session (default stackguard + exploit). - Just work: the agent calls
ana_recallandana_rememberitself — there is no query language to write. - To look at the store, ask the agent for
ana_dashboard(one TUI frame, right in the answer) orana_diagram(a diagram you can paste into Markdown). - For a live view in a real terminal:
node tools/viz-watch.mjs --watch(read-only, separate process). - 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()returnsrevert(reason), which commits the inverse as a compensating event in the same journal — so reverts still work after a restart.ana_strategy action:"revert"andana_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

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





- 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 (withsupports/contradicts/supersedesedges), the strategy timeline, and observed lifecycle transitions (only what the journal really recorded;lock/expirestyle 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=statusreports 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.mjsis 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>andsession:<id>events live in segments named after them, while global memory keeps the unprefixedjournal-*.jsonl.Entirely local: no model download, no model calls, no subprocesses; the only network request is the optional update check (
updateCheck: npmin the shipped bundle,offin code — withoffnothing 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.strictmasks labels too;noneis 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/evolutionholds more data, the plugin keeps using it and says so in the log, moving not a single byte. To move it, runnpm 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