claude-memory-admin 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,7 +3,8 @@
3
3
  [![CI](https://github.com/linkdotnet/claude-memory-admin/actions/workflows/ci.yml/badge.svg)](https://github.com/linkdotnet/claude-memory-admin/actions/workflows/ci.yml)
4
4
  [![npm](https://img.shields.io/npm/v/claude-memory-admin)](https://www.npmjs.com/package/claude-memory-admin)
5
5
 
6
- Browse, audit and prune the **auto memory** Claude Code writes for each project.
6
+ Browse, audit and prune the memory Claude Code writes for itself: the **auto
7
+ memory** kept per project, and the **subagent memory** kept per agent.
7
8
 
8
9
  ```bash
9
10
  npm install -g claude-memory-admin
@@ -13,6 +14,11 @@ claude-memory-admin
13
14
  It opens `http://localhost:4173` and reads `~/.claude/projects/*/memory/`.
14
15
  Nothing leaves your machine; the server binds `127.0.0.1` only.
15
16
 
17
+ This project is built heavily with AI tooling: most of the code, the tests
18
+ and this README were written by Claude Code, with a human directing the design
19
+ and reviewing what landed. Fitting for a tool about what Claude writes for
20
+ itself, and worth saying out loud.
21
+
16
22
  <sub>Brought to you by [BitSpire](https://bitspire.ch/).</sub>
17
23
 
18
24
  ---
@@ -37,6 +43,21 @@ Claude Code keeps two kinds of memory. This tool is about the second one:
37
43
  | Lives in | `./CLAUDE.md`, `~/.claude/CLAUDE.md` | `~/.claude/projects/<project>/memory/` |
38
44
  | Contains | rules and instructions | learnings Claude picked up |
39
45
 
46
+ Subagents declaring `memory:` in their frontmatter get their own directories,
47
+ which hold exactly the same thing under a different name, so they are shown
48
+ alongside the projects:
49
+
50
+ | Scope | Lives in |
51
+ | --- | --- |
52
+ | `user` | `~/.claude/agent-memory/<agent>/` |
53
+ | `project` | `<repo>/.claude/agent-memory/<agent>/` |
54
+ | `local` | `<repo>/.claude/agent-memory-local/<agent>/` |
55
+
56
+ The project-scoped ones are found under the repositories this tool already
57
+ resolved from your session transcripts, so it never goes looking through
58
+ directories it has no reason to believe in. A `project`-scoped store is checked
59
+ into git, and the app says so before you delete anything from one.
60
+
40
61
  The auto memory directory holds `MEMORY.md` (a concise index) plus one topic
41
62
  file per memory, cross-linked with `[[wikilinks]]`.
42
63
 
@@ -51,8 +72,23 @@ project is to the cliff, and makes it quick to get back under it.
51
72
  (`-Users-me-repos-Blog`) and the slugification is lossy. The true path is
52
73
  recovered from the `cwd` field in the session transcripts stored next to each
53
74
  memory directory; anything that cannot be confirmed is shown as the raw slug
54
- rather than a plausible guess. `autoMemoryDirectory` in `~/.claude/settings.json`
55
- is honoured if you have moved the store.
75
+ rather than a plausible guess. Claude Code keys the store on the git
76
+ repository, so one memory directory serves every worktree and subdirectory of
77
+ a repo: when the transcripts disagree, the repository root wins and the other
78
+ directories are listed under the project name.
79
+ - **A store keeps its name after its evidence expires.** Claude Code sweeps
80
+ session transcripts on a retention period but never touches `memory/`, so a
81
+ project eventually loses the only proof of what it was called. **Remember
82
+ path** records one you confirm, and is the single thing this app writes
83
+ outside a `memory/` directory.
84
+ - **Where the store is** is read the way Claude Code reads it: `autoMemoryDirectory`
85
+ from any settings layer, managed policy through project and local, not just
86
+ `~/.claude/settings.json`. A value that is neither absolute nor `~/`-prefixed
87
+ is reported rather than quietly ignored.
88
+ - **Whether Claude is still writing.** A project with `autoMemoryEnabled` off, or
89
+ `CLAUDE_CODE_DISABLE_AUTO_MEMORY` set, has a store that will never grow again,
90
+ which on disk is indistinguishable from one Claude has not learned anything
91
+ about yet. The project header says which it is, and names the file that decided.
56
92
  - **Search across every project**: names, descriptions, bodies and index hooks,
57
93
  with snippets and match highlighting. Press `/` to jump to it.
58
94
  - **Read each memory** with its frontmatter as structured metadata and
@@ -62,8 +98,19 @@ project is to the cliff, and makes it quick to get back under it.
62
98
  a neighbour, which is the only practical way to read a dense cluster.
63
99
  - **Health**: orphans, dangling pointers, broken wikilinks, files linked only
64
100
  mid-sentence, `name` fields that disagree with the filename.
101
+ - **Dates you can trust.** Claude Code stamps `modified` into frontmatter, but
102
+ only on files that already have some, and never adds frontmatter to a file
103
+ without it. Anything falling back to the file's mtime is labelled, because
104
+ mtime is reset by any copy or restore.
105
+ - **Context**: what a session starting in this project would load as
106
+ *instructions*, which is the other half of the startup budget (see below).
65
107
  - **Delete with cascade**, always reversible.
66
108
 
109
+ Everything above works the same on both kinds of store. The load meter, graph,
110
+ health checks and trash never needed to know which they were reading: a subagent
111
+ memory directory is a `MEMORY.md` index plus topic files under the same 200-line
112
+ / 25KB limit.
113
+
67
114
  ## Keeping MEMORY.md small
68
115
 
69
116
  The **Prune** tab exists because a bloated index costs tokens on every single
@@ -72,6 +119,14 @@ session and, past the limit, silently stops loading.
72
119
  - **Load meter**. How much of the 200-line / 25KB budget the index uses, and
73
120
  which of the two is binding. Frontmatter and HTML comments are excluded,
74
121
  because Claude Code strips those before loading.
122
+ - **The cutoff, drawn where it falls**. Past the limit, the MEMORY.md tab rules a
123
+ line across the file and dims everything below it, and Prune names the memories
124
+ that stopped being loaded. Because the stripping shifts every line, the cutoff
125
+ is mapped back to real line numbers rather than counted in the loaded text. The
126
+ tab reads the index either **rendered** — headings, lists and clickable entries,
127
+ with pointers to files that do not exist struck through — or as **source**, with
128
+ line numbers. Either way the cutoff is drawn in the same place. The choice is
129
+ remembered.
75
130
  - **Long hooks**. The hook is the text after the dash in `MEMORY.md`. A
76
131
  400-character hook can cost more than the memory it points at, and shortening
77
132
  it is the cheapest win available.
@@ -84,6 +139,36 @@ session and, past the limit, silently stops loading.
84
139
  Anthropic's own guidance for the index: one line per entry, detail in the topic
85
140
  files, merge or drop stale entries.
86
141
 
142
+ ## The other half of the budget
143
+
144
+ `MEMORY.md` is not the only thing loaded at the start of every session. The
145
+ **Context** tab resolves what else is, in load order: managed policy, your
146
+ `~/.claude/CLAUDE.md` and `~/.claude/rules/`, every `CLAUDE.md` and
147
+ `CLAUDE.local.md` from the filesystem root down to the project, `.claude/CLAUDE.md`,
148
+ and `.claude/rules/`, with `@path` imports expanded and `claudeMdExcludes` applied.
149
+
150
+ Unlike `MEMORY.md`, none of it is truncated: `CLAUDE.md` files load in full
151
+ however long they are. So the tab reports cost rather than a cliff, and separates
152
+ what every session pays for from the path-scoped rules that only load on a match.
153
+
154
+ It also finds the failures that leave a file silently doing nothing:
155
+
156
+ - Imports that do not resolve, chains past the four-hop maximum, and cycles.
157
+ - Imports resolving outside the project, which Claude Code asks you to approve
158
+ once and which stay disabled if you decline.
159
+ - A `paths:` glob with a `[` that cannot be read as a bracket expression. It is
160
+ invalid, so it matches nothing and the rule never applies.
161
+ - Brace expansion past the 1,000-pattern budget, where the pattern is used
162
+ unexpanded and its literal braces match no file either.
163
+ - An `AGENTS.md` that no `CLAUDE.md` imports. Claude Code reads `CLAUDE.md`.
164
+
165
+ Backticks are respected, so a `` `@README` `` in your prose is not reported as an
166
+ import, and neither is an email address.
167
+
168
+ This is re-derived from the documented resolution rules rather than reported by
169
+ Claude Code, and the tab says so. Run `/context` in a session for the ground
170
+ truth, or the `InstructionsLoaded` hook to log exactly what loaded and why.
171
+
87
172
  ## Deleting is reversible
88
173
 
89
174
  Delete shows a preview first: the exact lines that will go, the prose mentions it
@@ -127,6 +212,10 @@ claude-memory-admin --root /tmp/memory-snapshot
127
212
  - Binds `127.0.0.1`; no telemetry, no network calls.
128
213
  - Every write target must resolve to a plain `.md` file inside that project's own
129
214
  `memory/` directory. `..`, absolute paths and subdirectories are refused.
215
+ - One exception, and only when you ask for it: **Remember path** writes
216
+ `~/.claude-memory-admin/paths.json`. It holds folder slugs and the directory
217
+ paths you confirmed, never memory content, and forgetting the last entry
218
+ deletes the file. Nothing creates it until you use the action.
130
219
  - `MEMORY.md` is replaced atomically (temp file, `fsync`, `rename`) with a backup
131
220
  restored if anything throws.
132
221
  - A test asserts that parsing and rewriting every real `MEMORY.md` with no
@@ -141,26 +230,39 @@ cd claude-memory-admin
141
230
  npm install
142
231
  npm start # or: node server.mjs
143
232
  npm test # runs on a throwaway copy of your real store
233
+ npm run dev:css # only when editing styles/app.css
144
234
  ```
145
235
 
146
- No bundler and no build step: the backend is `node:http` plus `node:fs`, and the
147
- frontend is plain ES modules the browser loads directly. Two runtime dependencies,
148
- `marked` and `dompurify`, both only for rendering memory bodies safely.
236
+ No bundler and no build step to run it: the backend is `node:http` plus `node:fs`,
237
+ and the frontend is plain ES modules the browser loads directly. Two runtime
238
+ dependencies, `marked` and `dompurify`, both only for rendering memory bodies safely.
239
+
240
+ Styling is the one thing that is compiled. `styles/app.css` is the Tailwind v4
241
+ source and `public/styles.css` is its committed output, so an installed copy is
242
+ ready to serve and never builds anything. After editing the source, run
243
+ `npm run build:css` and commit the result — CI rebuilds it and fails on drift.
149
244
 
150
245
  | Path | Purpose |
151
246
  | --- | --- |
152
247
  | `bin/claude-memory-admin.mjs` | CLI entry point and argument parsing |
153
248
  | `server.mjs` | HTTP server: static files + JSON API |
154
249
  | `src/projects.mjs` | Project discovery, slug → real path resolution |
250
+ | `src/settings.mjs` | Layered reads of Claude Code's settings files |
251
+ | `src/pathcache.mjs` | The opt-in record of confirmed project paths |
252
+ | `src/stores.mjs` | Store discovery: auto memory and the three agent scopes |
253
+ | `src/instructions.mjs` | CLAUDE.md chain, `@` imports and rules resolution |
155
254
  | `src/parse.mjs` | `MEMORY.md` and frontmatter parsers, wikilinks |
156
255
  | `src/model.mjs` | Joins index, files, graph and health into one model |
157
256
  | `src/stats.mjs` | Load-limit accounting and overlap detection |
158
- | `src/search.mjs` | Full-text search across projects |
257
+ | `src/search.mjs` | Full-text search across every store |
159
258
  | `src/mutate.mjs` | Delete / restore / unlink, the only code that writes |
259
+ | `styles/app.css` | Tailwind source, compiled to `public/styles.css` |
160
260
  | `public/` | Frontend |
161
261
 
162
- Tests run against a committed fixture store under `test/fixtures/store/`, which
163
- encodes the awkward shapes real memory directories contain. Your own
262
+ Tests run against committed fixtures under `test/fixtures/`: a projects store
263
+ encoding the awkward shapes real memory directories contain, including one index
264
+ deliberately past the load limit, an `agents/` tree covering all three subagent
265
+ scopes, and an `instructions/` tree covering the import and glob edge cases. Your own
164
266
  `~/.claude/projects` is additionally checked when it exists, always on a
165
267
  throwaway copy.
166
268
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-memory-admin",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Browse, audit and prune the auto memory Claude Code keeps under ~/.claude/projects",
5
5
  "keywords": [
6
6
  "claude",
@@ -54,10 +54,16 @@
54
54
  },
55
55
  "scripts": {
56
56
  "start": "node bin/claude-memory-admin.mjs",
57
- "test": "node --test test/*.test.mjs"
57
+ "test": "node --test test/*.test.mjs",
58
+ "build:css": "tailwindcss -i styles/app.css -o public/styles.css --minify",
59
+ "dev:css": "tailwindcss -i styles/app.css -o public/styles.css --watch",
60
+ "prepublishOnly": "npm run build:css"
58
61
  },
59
62
  "dependencies": {
60
63
  "dompurify": "^3.2.7",
61
64
  "marked": "^16.4.0"
65
+ },
66
+ "devDependencies": {
67
+ "@tailwindcss/cli": "^4.3.3"
62
68
  }
63
69
  }