claude-memory-admin 1.0.1 → 1.2.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
@@ -97,13 +97,16 @@ project is to the cliff, and makes it quick to get back under it.
97
97
  - **Graph** the wikilinks between memories. Hovering dims everything that is not
98
98
  a neighbour, which is the only practical way to read a dense cluster.
99
99
  - **Health**: orphans, dangling pointers, broken wikilinks, files linked only
100
- mid-sentence, `name` fields that disagree with the filename.
100
+ mid-sentence, `name` fields that disagree with the filename. An orphan can be
101
+ given the `MEMORY.md` bullet it is missing without leaving the page.
101
102
  - **Dates you can trust.** Claude Code stamps `modified` into frontmatter, but
102
103
  only on files that already have some, and never adds frontmatter to a file
103
104
  without it. Anything falling back to the file's mtime is labelled, because
104
105
  mtime is reset by any copy or restore.
105
106
  - **Context**: what a session starting in this project would load as
106
107
  *instructions*, which is the other half of the startup budget (see below).
108
+ - **Settings**: every layer Claude Code would read, side by side, with the value
109
+ that wins and the ones it shadows (see below).
107
110
  - **Delete with cascade**, always reversible.
108
111
 
109
112
  Everything above works the same on both kinds of store. The load meter, graph,
@@ -122,13 +125,28 @@ session and, past the limit, silently stops loading.
122
125
  - **The cutoff, drawn where it falls**. Past the limit, the MEMORY.md tab rules a
123
126
  line across the file and dims everything below it, and Prune names the memories
124
127
  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.
128
+ is mapped back to real line numbers rather than counted in the loaded text. The
129
+ tab reads the index either **rendered** — headings, lists and clickable entries,
130
+ with pointers to files that do not exist struck through — or as **source**, with
131
+ line numbers. Either way the cutoff is drawn in the same place. The choice is
132
+ remembered.
126
133
  - **Long hooks**. The hook is the text after the dash in `MEMORY.md`. A
127
134
  400-character hook can cost more than the memory it points at, and shortening
128
- it is the cheapest win available.
135
+ it is the cheapest win available. **Edit hook** rewrites one in place, with the
136
+ projected load meter next to the character count, and changes nothing but the
137
+ text after the separator - the indent, title, link and the separator character
138
+ itself are kept byte for byte, so a project that writes ` - ` keeps writing it.
139
+ - **Move above the cutoff**. Past the limit, an entry is on disk but invisible.
140
+ **Move up** relocates its bullet, and the indented lines under it, to the end
141
+ of any section that starts above the cutoff. It moves one entry rather than
142
+ making room, so whatever is now last drops below the line instead - the tab
143
+ says so before you do it.
129
144
  - **Possible overlap**. Pairs of memories ranked by shared *rare* vocabulary, to
130
145
  surface the same lesson saved three times from three sessions. It is a hint,
131
- not a verdict.
146
+ not a verdict. **Merge** folds one into the other: the body moves under a
147
+ heading you name, every `[[wikilink]]` that pointed at the source is repointed
148
+ rather than broken, a link the survivor had to the source becomes plain text
149
+ instead of a self-link, and the two index bullets collapse to one.
132
150
  - **Bulk prune**. Sort by age, size, or inbound links, tick several, delete them
133
151
  as one restore point.
134
152
 
@@ -157,15 +175,54 @@ It also finds the failures that leave a file silently doing nothing:
157
175
  - Brace expansion past the 1,000-pattern budget, where the pattern is used
158
176
  unexpanded and its literal braces match no file either.
159
177
  - An `AGENTS.md` that no `CLAUDE.md` imports. Claude Code reads `CLAUDE.md`.
178
+ - A markdown file sitting in `~/.claude` that nothing in the chain reaches. It
179
+ looks load-bearing and loads nothing, which is what happens when the import
180
+ that pulled it in is deleted or its content is inlined.
160
181
 
161
182
  Backticks are respected, so a `` `@README` `` in your prose is not reported as an
162
183
  import, and neither is an email address.
163
184
 
185
+ Every file listed opens in place, so you can read what actually loads without
186
+ leaving the tab. Nothing here is editable: the app never rewrites a `CLAUDE.md`.
187
+
188
+ ### The user scope on its own
189
+
190
+ The half of that chain no project owns — managed policy, `~/.claude/CLAUDE.md`,
191
+ `~/.claude/rules/` and their imports — is also a **Global** entry at the top of
192
+ the sidebar. It is what every session on the machine pays for before a project is
193
+ even chosen, and it resolves without a project directory, so it is there even when
194
+ no project's real path could be recovered from a transcript.
195
+
196
+ It holds instructions rather than memory, so it is read-only and has no MEMORY.md,
197
+ graph or trash. Search does not reach into it.
198
+
164
199
  This is re-derived from the documented resolution rules rather than reported by
165
200
  Claude Code, and the tab says so. Run `/context` in a session for the ground
166
201
  truth, or the `InstructionsLoaded` hook to log exactly what loaded and why.
167
202
 
168
- ## Deleting is reversible
203
+ ## Which settings are actually in force
204
+
205
+ Five files can set the keys this tool cares about, and the one everybody edits,
206
+ `~/.claude/settings.json`, is the weakest of them. The **Settings** tab reads all
207
+ five and shows, per key, the value that wins and the ones it shadows, struck
208
+ through, each labelled with the file it came from:
209
+
210
+ `autoMemoryEnabled`, `autoMemoryDirectory`, `claudeMdExcludes` and
211
+ `cleanupPeriodDays`, plus `CLAUDE_CODE_DISABLE_AUTO_MEMORY` when it is set in the
212
+ environment, where it outranks every file.
213
+
214
+ It also names the failures that are otherwise silent:
215
+
216
+ - A settings file that exists but is not valid JSON. Claude Code ignores the
217
+ whole file, so every value in it is doing nothing, and nothing says so.
218
+ - A file that parses but is not an object, or cannot be read at all.
219
+ - An `autoMemoryDirectory` that is neither absolute nor `~/`-prefixed.
220
+ - A value Claude Code accepts the key of but not the number, like a
221
+ `cleanupPeriodDays` below 1: the tab shows what is written *and* what applies.
222
+
223
+ The tab is read-only. It reports what is configured; it never writes a setting.
224
+
225
+ ## Everything it writes is reversible
169
226
 
170
227
  Delete shows a preview first: the exact lines that will go, the prose mentions it
171
228
  will deliberately leave alone, and which other memories link here and will break.
@@ -181,8 +238,19 @@ exists. The markup goes and the words stay, so `see [[gone]] for details` become
181
238
  `see gone for details`.
182
239
 
183
240
  Everything lands in `memory/.trash/` with a restore record and comes back from the
184
- Trash tab. The app never creates memories and never rewrites their prose beyond
185
- clearing a dead link's brackets.
241
+ Trash tab, one undo per operation however many files it touched.
242
+
243
+ The app never writes a memory file of its own. It edits `MEMORY.md` a line at a
244
+ time - a hook rewritten, a bullet added or moved - and each of those keeps every
245
+ other byte of the file. Adding a bullet to a project that has no `MEMORY.md` yet
246
+ is the one case where a file is created, and undoing it deletes that file again,
247
+ but only if nothing has touched it since. **Merge** is the one action that
248
+ rewrites prose inside a memory, which is why it shows you every file it will
249
+ touch first.
250
+
251
+ Each index edit keeps a copy of the whole `MEMORY.md` in the trash rather than a
252
+ note of which lines changed, so undo means writing back the exact bytes that were
253
+ there instead of recomputing them.
186
254
 
187
255
  ## Usage
188
256
 
@@ -215,8 +283,12 @@ claude-memory-admin --root /tmp/memory-snapshot
215
283
  - `MEMORY.md` is replaced atomically (temp file, `fsync`, `rename`) with a backup
216
284
  restored if anything throws.
217
285
  - A test asserts that parsing and rewriting every real `MEMORY.md` with no
218
- deletions reproduces it byte for byte. Real indexes are hand-written prose with
219
- headings and nested bullets, and mangling one would be silent.
286
+ deletions reproduces it byte for byte, that rewriting a hook and putting the
287
+ original back does too, and that no edit ever disturbs a line it was not
288
+ aimed at. Real indexes are hand-written prose with headings and nested bullets,
289
+ and mangling one would be silent.
290
+ - Every index edit is guarded by the text the browser last saw, so an edit made
291
+ against a stale view is refused rather than applied to the wrong line.
220
292
 
221
293
  ## Development
222
294
 
@@ -226,26 +298,33 @@ cd claude-memory-admin
226
298
  npm install
227
299
  npm start # or: node server.mjs
228
300
  npm test # runs on a throwaway copy of your real store
301
+ npm run dev:css # only when editing styles/app.css
229
302
  ```
230
303
 
231
- No bundler and no build step: the backend is `node:http` plus `node:fs`, and the
232
- frontend is plain ES modules the browser loads directly. Two runtime dependencies,
233
- `marked` and `dompurify`, both only for rendering memory bodies safely.
304
+ No bundler and no build step to run it: the backend is `node:http` plus `node:fs`,
305
+ and the frontend is plain ES modules the browser loads directly. Two runtime
306
+ dependencies, `marked` and `dompurify`, both only for rendering memory bodies safely.
307
+
308
+ Styling is the one thing that is compiled. `styles/app.css` is the Tailwind v4
309
+ source and `public/styles.css` is its committed output, so an installed copy is
310
+ ready to serve and never builds anything. After editing the source, run
311
+ `npm run build:css` and commit the result — CI rebuilds it and fails on drift.
234
312
 
235
313
  | Path | Purpose |
236
314
  | --- | --- |
237
315
  | `bin/claude-memory-admin.mjs` | CLI entry point and argument parsing |
238
316
  | `server.mjs` | HTTP server: static files + JSON API |
239
317
  | `src/projects.mjs` | Project discovery, slug → real path resolution |
240
- | `src/settings.mjs` | Layered reads of Claude Code's settings files |
318
+ | `src/settings.mjs` | Layered reads of Claude Code's settings files, and the report behind the Settings tab |
241
319
  | `src/pathcache.mjs` | The opt-in record of confirmed project paths |
242
- | `src/stores.mjs` | Store discovery: auto memory and the three agent scopes |
320
+ | `src/stores.mjs` | Store discovery: the user scope, auto memory and the three agent scopes |
243
321
  | `src/instructions.mjs` | CLAUDE.md chain, `@` imports and rules resolution |
244
322
  | `src/parse.mjs` | `MEMORY.md` and frontmatter parsers, wikilinks |
245
323
  | `src/model.mjs` | Joins index, files, graph and health into one model |
246
324
  | `src/stats.mjs` | Load-limit accounting and overlap detection |
247
325
  | `src/search.mjs` | Full-text search across every store |
248
- | `src/mutate.mjs` | Delete / restore / unlink, the only code that writes |
326
+ | `src/mutate.mjs` | Delete / edit / merge / restore, the only code that writes |
327
+ | `styles/app.css` | Tailwind source, compiled to `public/styles.css` |
249
328
  | `public/` | Frontend |
250
329
 
251
330
  Tests run against committed fixtures under `test/fixtures/`: a projects store
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-memory-admin",
3
- "version": "1.0.1",
3
+ "version": "1.2.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
  }