İçeriğe geç

DS-ReCall Install Guide: Our Own Install Check Failed

First the verification step of our own release came back red on a healthy install, then we tested our own defaults on realistic repos. An install guide for the current version, 0.3.0, and what a verification step has to prove.

Updated: 19 October 2026, for 0.3.0. This article was first written for 0.2.1. On 19 October 2026 version 0.3.0 was released, and we have updated the article to match. Two things changed: the commit-gate no longer blocks by default, it warns; and setting up a project is one command instead of eight manual copy steps. The current state in this article is 0.3.0. What belongs to 0.1 and 0.2.x stays in as history, labelled with its version.

DS-ReCall is our open-source memory plugin for Claude Code. This article walks you through installing and using the current version, 0.3.0, today. It also covers the two times we saw red while re-testing our own releases: while preparing 0.2.1, the command our README tells new users to run to verify an install printed RESULT: FAIL on a healthy install; then we tried 0.2.1 on realistic repositories and found that our own default was wrong. The commands and outputs below come from the 0.3.0 documentation, whose commands were run as written.

1. What DS-ReCall is, and who it is not for

Claude Code loads two things on its own at the start of every session: your project's CLAUDE.md and the .claude/rules/ folder. DS-ReCall does not invent a new storage layer. It switches off Claude Code's uncurated auto-memory and disciplines those native files instead: every fact carries a date and a status tag (verified, assumption, outdated, unknown); /ds-recall:wrap folds a session into the canon at the end; an integrity check catches broken links and orphaned notes; and session locks keep parallel sessions from overwriting each other's files.

The hooks make no model calls and no network requests, depend on nothing but Node.js, and keep everything as plain Markdown in your own repo. In August we wrote about alarm fatigue (in Turkish): a warning in version 0.1 of this tool that was wrong 98% of the time. That fix shipped in 0.2.0 on 7 August 2026. This article is the sequel: the tool can now be installed from outside, and this time we put our own verification to the test.

Is it for you?

  • A good fit: a shared CLAUDE.md across several people or parallel sessions; a client-facing project where “what did the AI make up?” needs a real answer; a workflow where you want to know exactly what was kept and what was dropped.
  • Not a good fit: you want memory that just works with zero thought. Claude Code's own auto-memory, Anthropic's Remember plugin and community tools such as claude-mem are more mature at that, and DS-ReCall does not compete on that axis. The /ds-recall:wrap step is the price of curation: deliberate friction.

2. How to install it today

Requirements: Claude Code 2.1.275 or later for the one-line install (earlier versions work with --plugin-dir), and Node.js on your PATH. It was tested on Node v22 and uses no npm packages.

The recommended route is a per-project install. In the project folder:

claude plugin install ds-recall --marketplace toresoysal/ds-recall --scope project

This adds the marketplace to your user settings and enables the plugin for this project only, by writing "enabledPlugins": { "ds-recall@devsoy": true } into the project's .claude/settings.json. Teammates run the same command. Inside a Claude Code session the equivalent is /plugin install ds-recall --marketplace toresoysal/ds-recall.

Scope matters

If you install without --scope project, the hooks run in every project you open, including ones you never set up: they create .claude/active/, a stub under docs/sessions/, an index file and a transcript backup. Empty stubs are retracted when the session ends, but the backup stays. Unless you want exactly that, install per project.

To try it without installing: git clone https://github.com/toresoysal/ds-recall, then claude --plugin-dir ./ds-recall. The plugin loads for that run only.

3. The second half of the install: one command in the project

Installing the plugin gives you the hooks and the commands. Each project additionally needs its own index, a config file and three helper scripts. The reason: /ds-recall:wrap and /ds-recall:status call the project-local copies (node .claude/scripts/...), because command bodies are prompts, not shells, and the variable that points at the plugin root was not expanded inside them when we built 0.1. We have not re-verified that on newer versions. Since 0.3.0 one command does all of it; from the project root:

# macOS / Linux / Git Bash
node ~/.claude/plugins/cache/devsoy/ds-recall/0.3.0/scripts/init.js

# Windows PowerShell
node "$env:USERPROFILE\.claude\plugins\cache\devsoy\ds-recall\0.3.0\scripts\init.js"

Adjust the version folder at the end of the path to the version you have. The command creates CLAUDE.md, the decision log, the timeline and the config file, copies the three scripts into .claude/scripts/ and adds the .gitignore lines. It never overwrites a file you already have, and running it twice changes nothing. Look at what it would do first with --dry-run: it writes nothing. Its output on a fresh folder (shortened):

DS-ReCall init — setup · plugin 0.3.0
  created  CLAUDE.md
  created  docs/DECISIONS.md
  created  docs/TIMELINE.md
  created  .claude/ds-recall.config.json
  created  .claude/scripts/validate.js
  created  .claude/scripts/wrap-prep.js
  created  .claude/scripts/session-lib.js
  created  .gitignore  — added .claude/active/ .claude/backups/ …

  8 created · 0 changed · 0 left as they were · 0 to do · 0 errors
  …
RESULT: OK

Options

  • --dry-run: prints what would happen and writes nothing, also when combined with any other option.
  • --upgrade: re-syncs only validate.js, wrap-prep.js and session-lib.js (see Upgrading, below).
  • --append-pointers: if you already have your own CLAUDE.md, appends the two lines that link the new decision log and timeline. Only for files init.js created itself, and only once.
  • --disable-auto-memory: merges {"autoMemoryEnabled": false} into .claude/settings.json; the original is kept as settings.json.dsr-backup. Without this option init.js never edits your settings, it only reports the state.

The command refuses (RESULT: REFUSED, exit code 1) a folder inside the plugin's own folder, a clone of the plugin repository, a folder that does not exist (it will not create one) and an unknown option; a typo such as --force must not run a half-meant command. A settings.json it cannot parse is left untouched. The eight manual copy steps that 0.1 and 0.2 required survive in a collapsed section of the user guide titled “The same setup by hand”.

Two things remain for you to do by hand, because a script should not decide them:

  1. Turn off built-in auto-memory. init.js tells you whether it is still on. Either re-run it with --disable-auto-memory, or add { "autoMemoryEnabled": false } to the project's .claude/settings.json (or set the environment variable CLAUDE_CODE_DISABLE_AUTO_MEMORY=1). If you forget, SessionStart injects a warning every session, so you never silently run both memory layers.
  2. Fill in CLAUDE.md. Replace the <placeholders>: project name, a one-paragraph summary, your hard rules. Keep it an index: point to detail files instead of pasting detail in.

Check it:

node .claude/scripts/validate.js

DS-ReCall integrity — <your project>
  referenced=2  broken=0  orphan=0  unindexed=0  size-warn=0
RESULT: OK

Exit code 0 means clean; 1 means a broken link, an orphaned note or an unindexed session. Size warnings are advisory and never count as a failure.

Upgrading

Run claude plugin update ds-recall and restart Claude Code, then in each project root run init.js from the new version's folder with --upgrade. The hooks run the plugin's own copies, but /wrap and /status run the project-local ones, so the scripts do not update by themselves. --upgrade rewrites only the three scripts and prints old -> new for each file it changes; your CLAUDE.md, config, .gitignore, decision log and any file of your own in .claude/scripts/ stay as they are. Nothing reminds you: make this step part of every upgrade. And if you are coming from 0.2.x, the commit-gate default changes (next section).

4. Before you enable it on an existing repo: the commit-gate now warns

The validator looks at the Markdown files under docs/ and expects an index file (by default CLAUDE.md) to link to each one. A note nothing links to counts as an “orphan”. While any orphan, broken link or unindexed session exists, the commit-gate reacts to every git commit. Since 0.3.0 it only warns by default; the commit goes through. Measured on a fresh install (a repo containing docs/foo.md, with no CLAUDE.md and no config file), the default output:

[DS-ReCall] Memory integrity FAIL — this commit was NOT blocked (gateCommit is "warn"): 0 broken, 1 orphan, 0 unindexed session(s). …

The mode is chosen with the gateCommit key in .claude/ds-recall.config.json:

gateCommit values

  • key absent or "warn" (the 0.3.0 default): the commit goes through. The user sees a warning (systemMessage) and Claude receives the same text as context (additionalContext).
  • true or "block": the commit is blocked while integrity fails (the 0.1 and 0.2 behaviour).
  • false or "off": the gate does nothing.
  • anything else (for example the typo "blok"): treated as "warn", and the warning says the value was not recognised; it neither silently switches off nor silently starts blocking.

The warning deliberately returns no permissionDecision: Claude Code's documentation says "allow" skips the user's own permission prompt, and a warning must never auto-approve a commit. A config file that is not valid JSON also falls back to "warn".

History: in 0.1 and 0.2 the default was to block

We measured it on 0.2: a fresh install in a repo containing an unlinked docs/foo.md denied every commit with this message until you linked the notes:

Commit blocked — memory integrity FAIL: 0 broken, 1 orphan, 0 unindexed session(s).

If you have your own CLAUDE.md, the copy keeps it, but the docs/DECISIONS.md and docs/TIMELINE.md that were created stayed orphans until you linked to them. Measured: orphan=2. That is why we changed the default. The fix is still the same two lines (or init.js --append-pointers):

- Decisions (dated, reasoned) -> docs/DECISIONS.md
- Milestones -> docs/TIMELINE.md

A plain path is enough; Markdown link syntax is not required. Your options, least invasive first: do nothing (commits go through, the warning tells you what to fix); link your notes, or write a sub-index that links a whole folder and add it to the indexes list; narrow tracked to the folders you actually want curated; once node .claude/scripts/validate.js is clean, tighten the gate with "gateCommit": "block" or silence it with false.

If you are coming from 0.2.x

For projects whose config has no gateCommit key (or no config at all), the default moves from blocking to a warning. If you rely on blocking, write "gateCommit": "block". Configs that already say "gateCommit": true keep blocking as before.

An honest cost: a warning can be ignored. A project that does not set strict mode is not protected from commits that break integrity. And we have not yet seen the warning's output in a live Claude Code session (section 10).

5. The daily loop

  1. Start a session. SessionStart opens a stub for it, injects the machine's real clock into the model (against date hallucination), warns if auto-memory is still on, and tells you if an earlier session holds real work that was never wrapped.
  2. Work as usual.
  3. Before you leave, run /ds-recall:wrap. Permanent decisions go to the decision log, the index is refreshed, durable rules go to .claude/rules/, the session is marked consolidated and integrity is re-checked. At the end it prints SESSION SEALED or NOT SEALED — WRAP INCOMPLETE; an incomplete wrap never says “saved”.
  4. Forgot? The session still ends safely (transcript backed up, lock released) and the next session tells you what is owed. SessionEnd is not guaranteed to fire: a crash or hard kill skips it, which is why SessionStart runs the same cleanup.

You can check health at any time with the read-only /ds-recall:status: auto-memory state, live locks, sessions waiting to be wrapped, integrity numbers, index size.

6. What it costs and what it writes into your repo

Cost (Claude Code 2.1.299's own estimate)

  • Always on: about 158 tokens per session (claude plugin details ds-recall)
  • While a command runs: wrap about 2.2k, status 0.4k, graph 0.6k tokens
  • Hooks' cost in model context: none. Model calls: zero. The runtime scripts import only Node's fs, path and zlib (checked by searching the source; child_process appears only in the test harness).

The dominant cost is not the plugin: it is your own CLAUDE.md and .claude/rules/, because Claude Code loads them in full every session. wrap-prep.js prints that number (PER-SESSION FIXED LOAD) so it stays visible; keeping the index lean is up to you.

What gets written into the repo: .claude/active/<id>.lock (the live-session lock), a session stub under docs/sessions/, .claude/SESSIONS_INDEX.md (one status line per session; whether to commit it for your team is your call) and transcript backups under .claude/backups/. Keep the backups out of git. If you used --disable-auto-memory, there is also a .claude/settings.json.dsr-backup.

7. Why did our own checks go red twice?

0.2.1: red on a healthy install

After installing, the README suggests two commands. node scripts/selftest.js runs the test suite (59 cases in 0.2.1). node scripts/selftest-negative.js is the kind of tool we described in the August article: it deliberately injects real defects into the source and checks that the suite goes red. Both are expected to print RESULT: OK.

While preparing 0.2.1 we ran the second one on Windows and got RESULT: FAIL. The install was healthy. The cause: Git for Windows defaults to core.autocrlf=true and checks files out with CRLF line endings. One of the harness's injection anchors spans two lines; in a CRLF file it silently stopped matching (anchor not found), so the defect it was meant to inject never landed.

The fix: the anchors now adapt to the file's own line ending, and restoring the source stays byte-exact. We proved it with a control, on the same source:

Same source, three runs (the 0.2.1 era)

  • 0.2.1 harness, CRLF copy: CAUGHT 9 · NOT-APPLIED 0 · OK
  • 0.2.1 harness, LF copy: CAUGHT 9 · NOT-APPLIED 0 · OK
  • 0.2.0 harness, CRLF copy: CAUGHT 8 · NOT-APPLIED 1 · FAIL

The third line is the control: the old harness, on the same file, really does see the bug. We also added a .gitattributes to the repo, so the tree stays LF on every platform.

0.2.1 contained other fixes too, none of which changed hook behaviour. validate.js printed its diagnostics in Turkish, which does not belong in a tool we hand to other people; they were made English. The README's status section still said “v0.1, not yet published”, and a section titled “Four building blocks” listed five. When 0.2.0 shipped (7 August 2026) there was no user guide and no way to install other than cloning the repository; both arrived with 0.2.1.

0.3.0: we tested our own default on realistic repos

After releasing 0.2.1 we tried it again on realistic repositories, and two things came out. The first is above: a fresh install in a repo with an unlinked docs/ folder denied every commit (orphan=1; orphan=2 where the repo had its own CLAUDE.md). The second: the one-time setup was eight manual copy commands, and their result went stale, silently, at the next plugin upgrade, because /ds-recall:wrap and /ds-recall:status run the project-local script copies. 0.3.0 changed both: the default became a warning, and setup and upgrade became init.js.

0.3.0: the first full run of our new tests failed

The first full run of the new test arms printed RESULT: FAIL (29 of 31 exercisable defects caught). Both gaps were not in the code but in our own tests. A dry-run (--dry-run) test ran on a project that was already fully set up, so a defect that made the dry run write to files could not show there. And one injection anchor had never applied, because the source line carries a literal BOM character. Both were fixed before release: a dry-run case on a project that still needs everything (which also asserts that the write path was actually seen), and an anchor that does not depend on the BOM.

0.3.0 in numbers

  • Automated tests: from 59 cases to 140 cases
  • Negative harness: 35 injections; 34 of 34 exercisable defects turned the suite red, 0 blind, 0 not applied, 1 declared not exercisable (the gzip round-trip length check, unchanged since 0.2)
  • Environment: run on both an LF tree and a CRLF copy

8. What a verification step has to prove

In August we asked three questions of a verification gate: does it measure the right thing, does it go red when you break it, and how many cases did it leave out? These cases add a fourth.

The fourth question

Does it go green when things are healthy — on the user's machine, in the user's repo? The environment a check runs in (line endings, paths with spaces, the Node version, the files already in the repo) is part of the test's input. A false red is the mirror image of a false green.

9. Compared with the built-in memory: curation, not visibility

One correction of our own belongs here. Since Claude Code 2.1.210, a write that leaves the MEMORY.md index over its read limit returns an explicit error instead of being silently truncated, and since 2.1.268 the truncation warning says how many lines were cut and where the cut starts (source: Claude Code's own release notes). The comparison table in our README used to say “silent truncation” for the built-in memory; that is no longer true, and we have corrected it.

What remains is this: in the built-in memory Claude decides what to keep, in DS-ReCall you do. The price is the /ds-recall:wrap step at the end of a session. Which one suits you depends on whether that price is worth it for your work.

For a wider comparison with claude-mem, Mem0, Supermemory and agentmemory, see our honest comparison of Claude Code memory tools.

10. Honest limits

The code is open source

DS-ReCall is MIT licensed. The user guide, the configuration reference, the troubleshooting page and release notes with the measurements behind each fix are all on GitHub. For an overview of our AI work, see the Devsoy AI page.

View on GitHub User guide 0.3.0 release notes

Frequently asked questions

How do I install DS-ReCall?

On Claude Code 2.1.275 or later, run claude plugin install ds-recall --marketplace toresoysal/ds-recall --scope project in your project folder. That enables the plugin for that project only. Then set the project up once: from the project root, run the plugin's scripts/init.js with node (in 0.3.0 the path is ~/.claude/plugins/cache/devsoy/ds-recall/0.3.0/scripts/init.js). It creates CLAUDE.md, the decision log, the timeline and the config, copies the three helper scripts, adds the .gitignore lines, and never overwrites a file you already have. Add --dry-run first to see what it would do. Finally, turn off the built-in auto-memory and check that node .claude/scripts/validate.js prints RESULT: OK.

Why does git commit show a warning (or get blocked) after installing?

If your docs/ folder holds a note that CLAUDE.md does not link to, DS-ReCall counts it as an orphan, and while the integrity check fails the commit-gate reacts to every git commit. Since 0.3.0 the default mode is a warning: the commit goes through and the warning says what to fix. In 0.1 and 0.2 the default was to block, and in our measurement a fresh install in a repo with an unlinked docs/ folder denied every commit. Strict mode still exists: set "gateCommit": "block" in ds-recall.config.json. Set it to false to switch the gate off. You can also clear the warning by linking the orphan notes from CLAUDE.md, or by running init.js with --append-pointers.

Does DS-ReCall make model calls, and how many tokens does it use?

The hooks make no model calls and no network requests; the runtime scripts import only Node's fs, path and zlib modules. By Claude Code's own estimate the plugin adds about 158 tokens per session, and while a command runs, wrap costs about 2.2k, status about 0.4k and graph about 0.6k tokens. The real cost is not the plugin but your own CLAUDE.md and .claude/rules/ files, which load in full every session.

How is it different from Claude Code's built-in memory?

The difference is no longer visibility, it is curation. Since Claude Code 2.1.210, a write that leaves MEMORY.md over its read limit returns an explicit error instead of being silently truncated. In the built-in memory Claude decides what to keep; in DS-ReCall you decide, and the price is the /ds-recall:wrap step at the end of a session. DS-ReCall has no search over past sessions: recall is the index plus grep.

I am on 0.2.x. How do I move to 0.3.0?

Run claude plugin update ds-recall, restart Claude Code, and in each project root run the plugin's new scripts/init.js with --upgrade. That re-syncs only validate.js, wrap-prep.js and session-lib.js and leaves your CLAUDE.md, config and decision log alone. Nothing reminds you to do this, so make it part of every upgrade. Mind one change: for projects whose config has no gateCommit key, the commit-gate default moves from blocking to a warning. If you rely on blocking, set "gateCommit": "block"; configs that already say true keep blocking as before. (On 0.2.0, selftest-negative came back red on Windows; that was fixed in 0.2.1.)

Have you seen the commit-gate warning in a live Claude Code session?

No, not yet. The warning's output follows Claude Code's documented hook format and is exercised by our own tests, but we could not run the live check with a logged-in claude: headless claude reported “Not logged in”. scripts/live-check-gate.js proves it on your machine with a logged-in claude and two tiny model calls; a measurement it cannot make is reported as UNMEASURED, never as a pass. A result from you, OK or FAIL, is worth an issue.

The command outputs and figures in this article were taken on 19 October 2026 from the DS-ReCall 0.3.0 documentation (measurements from the 0.1, 0.2.0 and 0.2.1 eras are labelled with their version; those for 0.2.1 date from 18 October 2026). Token figures are Claude Code 2.1.299's own estimates, not exact counts. What we say about Claude Code's MEMORY.md behaviour rests on Claude Code's published release notes. All documentation and release notes are open on GitHub. Also available in Turkish.