Skip to content

Memory ​

This page is for anyone who wants the agent to remember things across sessions: project conventions, your feedback, facts about the codebase. dsh-cc gives you two complementary layers — a CLAUDE.md conventions file that is loaded into every session, and a durable file-based memdir (MEMORY.md plus topic files) that the agent writes through a dedicated memory_save channel and reads back through dynamic recall.

The two layers at a glance ​

LayerWhat it holdsWho writes itWhen it is loaded
CLAUDE.mdProject conventions, build commands, house styleYou (scaffolded by /init)Every session
Memdir (MEMORY.md + topic files)Durable facts: user preferences, feedback, project and reference notesThe agent, via memory_saveMEMORY.md index always; topic files on demand via recall

The memory layer supports CLAUDE.md-style context plus a dedicated write channel for durable memories. Memory is isolated by workspace, with optional shared team memory.

The CLAUDE.md layer ​

CLAUDE.md is the conventions file: the durable, human-authored instructions you want applied in every session in a repository — build commands, code style, repo-specific rules. It lives at the repository root and is mounted as context each session.

Run /init to scaffold it. Per the compatibility matrix, /init in dsh-cc drives a follow-up model turn that writes or refreshes CLAUDE.md, rather than Claude Code's upstream one-shot initializer flow (status: partial). You can edit the file by hand afterwards like any Markdown file.

One upstream feature is not ported: CLAUDE.md @path imports are absent — no parser or loader handles imports today.

The memdir layer ​

The memdir is the durable store. Its layout:

  • A memory home (by default the harness home's memory/) acts as the global layer shared by every workspace.
  • Each git repository gets its own workspace directory under <memoryHome>/projects/<slug>/ — linked worktrees and subdirectories are collapsed onto the main checkout first (canonicalMemoryRoot), so they share one store. Session transcripts still group by raw cwd; memory no longer follows that grouping for worktree sessions.
  • Every layer holds an always-loaded MEMORY.md entrypoint (capped at 200 lines / 25 KB), each line an index of .md topic files.
  • Each topic file carries name, description, and type frontmatter (user / feedback / project / reference) plus a Markdown body.

Sessions of different repositories never see each other's private memories; facts useful everywhere are saved with scope: "global".

The memory system-prompt section always renders — a memoryless layer shows a placeholder — so the save guidance never disappears. Delegated subagent children render it empty, so the section drops out of their prompt; the parent prompt must pass any facts the child needs.

The memory_save channel ​

The agent's only working save channel is the memory_save tool. Memory directories live outside every session workspace, so direct write/edit calls against them are fenced by the fs sandbox and always fail — the system prompt says so explicitly. memory_save takes structured fields (name, type, description, body, optional scope: workspace (default) or global), resolves the target directory from the calling agent's canonical git root, generates the frontmatter host-side, and upserts the MEMORY.md pointer.

INFO

memory_save writes the workspace and global layers only; a team-scope save channel and a delete channel are deferred. Registration is opportunistic: hosts without a tools service stay read-only.

/memory ​

The human-facing /memory command lists memory files or prints one memory's body. It registers as a global command, so it runs without a model turn.

InputResult
/memoryList each topic as - name (type) — first line, sorted by name, plus the memory directory header.
/memory <name>Print a single memory's frontmatter and full body, matched by frontmatter name or filename. An unknown name yields a friendly notice.

It is fully read-only, and the slash input and output are absent from model requests — using it consumes no model tokens.

Distilling failures with /learn ​

While /memory inspects memory, /learn writes it: the command scans the durable session transcripts for recurring failure→success corrections and distills them into workspace memory. It is dry-run by default — it renders the ranked findings and the proposed memory block and writes nothing. Only /learn apply writes: it creates the session-learnings memory topic as a managed marker block that /learn owns entirely and regenerates wholesale on every apply — hand-written memory elsewhere is untouched — and updates the MEMORY.md pointer. Empty findings leave existing memory untouched. /learn all scans every project's sessions instead of the current workspace only, and /learn days=N overrides the recency window (default 14). Tuning lives in the cc-learn settings namespace: enabled (default true), days (default 14), min-occurrences (default 2).

Automatic consolidation ​

Memory maintenance runs in the background and never blocks your session. The memory layer gates MEMORY.md writes with an index gate; when index pressure builds, a .consolidation-needed marker is written and a forced "dream" consolidation is queued.

The consolidation package (dsh-memory-consolidation) adds turn-end extraction: a background forked subagent with read/search tools only extracts durable facts from the turn as structured output, which the plugin validates and writes host-side — the forks hold no write tools, so a sandboxed session can never write memory directly.

Dream consolidation is a read-only forked subagent that reviews past sessions and reports a rewritten MEMORY.md + topic file set, applied by the plugin the same way. It runs only when three gates all pass:

  1. Time — at least minHours (default 24) since the last consolidation.
  2. Session count — at least minSessions (default 5) new transcripts.
  3. Lock — a .consolidation-lock file enforces mutual exclusion; a stale holder older than lockStaleMs (default 1 hour) is reclaimed, so a crash mid-consolidation recovers automatically. A failed or killed consolidation rolls the lock back so the time gate re-opens.

Two more knobs bound the forced path: pressureCooldownMinutes (default 60) is the minimum minutes between forced (pressure) dreams, and sessionsRoot (default <DSH_HOME>/sessions) is the session store root the gates scan.

Recall: how memories surface later ​

You do not have to ask for memories back. An agent/pre-step listener runs a small-model side query — a forked subagent — asking which topic files are relevant to the current turn, then injects their bodies into context:

  • Recall scans both layers (the agent's workspace directory plus the global one) and deduplicates: topic files already shown this session are never re-injected.
  • Tools used earlier in the session are tracked, and reference-doc memories for an actively-used tool are suppressed — warnings and gotchas about it are still surfaced.
  • Recall is opt-out via recallEnabled (default true); with recallUseSmallFast: true the recall fork runs on the cheap lane. Absence of the subagent service or provider skips recall without error.

TIP

The recall side-query relies on a registered one-shot subagent provider; no provider ships with the memory package itself (compose fork or spawn).

Team memory (opt-in) ​

When teamEnabled is true, a shared per-workspace team directory (<workspaceDir>/team) is layered on top of the workspace's private memdir, and the memory section renders a combined workspace + team + global prompt. It is off by default: enabling it changes the persisted memory layout and what the model writes, and points team-memory reads at a shared directory.

The source is explicit about the safety boundary: the per-access validation chain closes path traversal (key sanitization, final-segment symlink rejection, resolve + containment), but the intermediate-component TOCTOU window is not fully closed. Do not enable teamEnabled in multi-tenant or untrusted-writer deployments — it is intended for single-tenant, trusted-writer projects.

Practical hygiene ​

  • Put stable project conventions (build commands, style rules) in CLAUDE.md; save per-fact knowledge (user preferences, feedback, tool gotchas) through memory_save so it can be indexed and recalled.
  • Keep memories durable, not ephemeral: a topic file is re-injected in later sessions until it is superseded, so transient task state does not belong there.
  • Prefer scope: "global" only for facts genuinely useful across every repository — workspace memories stay private to the repo's store.

Next ​

dsh-cc is not Claude Code and is not a wrapper around Claude Code. Not affiliated with or endorsed by Anthropic.