crispy-recall 0.1.4 → 0.1.6
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 +31 -9
- package/dist/SKILL.md.template +34 -0
- package/dist/embed-pending.js +9 -2
- package/dist/recall.js +9 -2
- package/dist/stop-hook.js +9 -2
- package/package.json +5 -7
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ recall install
|
|
|
19
19
|
llama embedding binary, the model, and the SQLite DB), wires a Stop hook into
|
|
20
20
|
Claude Code so your transcripts are indexed automatically as sessions end, and
|
|
21
21
|
installs the `recall` skill. If Codex is detected it also gets the `recall`
|
|
22
|
-
skill (so the agent can search), but not an automatic per-turn hook
|
|
22
|
+
skill (so the agent can search), but not an automatic per-turn hook (yet) —
|
|
23
23
|
index Codex history with `recall backfill --vendor codex`. After that, recall
|
|
24
24
|
runs passively — you only invoke `recall` directly for `status`, `doctor`,
|
|
25
25
|
`repair`, or `uninstall`.
|
|
@@ -37,8 +37,8 @@ Windows-native are separate installs.** If you use both, run the install in each
|
|
|
37
37
|
Prerequisites: Node ≥ 20 and Claude Code installed. If Codex is detected
|
|
38
38
|
(`~/.codex/` exists), recall installs the `recall` skill into Codex (so the
|
|
39
39
|
agent can search) and you can index your Codex history with
|
|
40
|
-
`recall backfill --vendor codex`. Real-time per-turn Codex indexing is **not
|
|
41
|
-
|
|
40
|
+
`recall backfill --vendor codex`. Real-time per-turn Codex indexing is **not
|
|
41
|
+
yet** supported.
|
|
42
42
|
|
|
43
43
|
## What it does
|
|
44
44
|
|
|
@@ -52,23 +52,38 @@ in v0.1.0.
|
|
|
52
52
|
Two steps. First, search for the relevant session:
|
|
53
53
|
|
|
54
54
|
```bash
|
|
55
|
-
|
|
55
|
+
recall "the thing you're trying to remember"
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
That returns a table of matching sessions. Then read one, centered on the match:
|
|
59
59
|
|
|
60
60
|
```bash
|
|
61
|
-
|
|
61
|
+
recall <session-id> <message-id>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Search and list default to the **current directory's project** — from inside one
|
|
65
|
+
repo you only see that repo's sessions. Add `--all` to search across every
|
|
66
|
+
indexed project (use it for cross-repo questions, or when a scoped search comes
|
|
67
|
+
back thin), or `--project <path>` to target a specific repo regardless of where
|
|
68
|
+
you are:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
recall --all "the thing you're trying to remember"
|
|
62
72
|
```
|
|
63
73
|
|
|
64
74
|
The skill's frontmatter teaches Claude *when* to reach for this (before
|
|
65
75
|
non-trivial tasks, architectural decisions, or work with obvious prior
|
|
66
|
-
history), so in practice the agent calls it for you.
|
|
76
|
+
history), so in practice the agent calls it for you. (Inside the installed skill
|
|
77
|
+
the command is written out as `node ~/.recall/bin/recall.js` so it works even
|
|
78
|
+
when `recall` isn't on the agent's `PATH` — `$RECALL_BIN` in the skill source is
|
|
79
|
+
a placeholder the installer substitutes, not an environment variable you set.)
|
|
67
80
|
|
|
68
81
|
## Commands
|
|
69
82
|
|
|
70
83
|
| Command | What it does |
|
|
71
84
|
|---|---|
|
|
85
|
+
| `recall "<query>" [--all] [--project <path>]` | Search past sessions (FTS5 + semantic). Defaults to the current project; `--all` searches every indexed project, `--project` targets one. |
|
|
86
|
+
| `recall <session-id> [<message-id>]` | Read a session, optionally centered on a matched message. |
|
|
72
87
|
| `recall install` | One-time setup: scaffold `~/.recall/`, wire the Stop hook, install the skill. |
|
|
73
88
|
| `recall uninstall` | Reverse the install (skill, hook, CLAUDE.md block). `--purge` also removes `~/.recall/`. |
|
|
74
89
|
| `recall status` | DB size, message count, last ingest, embedding gap, active backfill PID, GPU/CPU backend. |
|
|
@@ -76,6 +91,11 @@ history), so in practice the agent calls it for you.
|
|
|
76
91
|
| `recall repair --fts \| --vectors \| --full` | Rebuild the FTS index, re-embed vectors, or full reingest from JSONL. |
|
|
77
92
|
| `recall backfill [--auto-embed] [--vendor <v>] [--detach]` | Index historical transcripts. |
|
|
78
93
|
|
|
94
|
+
Add `--json` to `install`/`uninstall`/`status`/`doctor` for machine-readable
|
|
95
|
+
output. `recall install` also takes `--offline` (use a pre-staged binary +
|
|
96
|
+
model instead of downloading) and `--no-backfill` / `--auto-backfill` to control
|
|
97
|
+
the initial history index. Run `recall --help` for the full flag set.
|
|
98
|
+
|
|
79
99
|
## Where things live
|
|
80
100
|
|
|
81
101
|
- `~/.recall/` — the DB, model, binary, logs, and `config.json` (the resolved GPU/CPU embedder mode).
|
|
@@ -86,9 +106,11 @@ history), so in practice the agent calls it for you.
|
|
|
86
106
|
|
|
87
107
|
## Privacy
|
|
88
108
|
|
|
89
|
-
Everything is local. No telemetry
|
|
90
|
-
binary + model download at install
|
|
91
|
-
|
|
109
|
+
Everything is local. No telemetry. The only data transfer is the one-time
|
|
110
|
+
binary + model download at install (from llama.cpp's GitHub releases and
|
|
111
|
+
HuggingFace); `recall install` and `recall doctor` also send lightweight
|
|
112
|
+
reachability probes to those two hosts. Nothing else leaves your machine. The DB
|
|
113
|
+
is plain SQLite — open it with any SQLite browser if you want to poke around.
|
|
92
114
|
|
|
93
115
|
## Troubleshooting
|
|
94
116
|
|
package/dist/SKILL.md.template
CHANGED
|
@@ -71,6 +71,12 @@ DATE HANDLING: Any date the user mentions MUST become a flag — never search te
|
|
|
71
71
|
--recent Boost recent sessions (use when user says 'recently', 'latest')
|
|
72
72
|
Example: \"what happened April 10\" → $RECALL_BIN --list --since 2026-04-10 --until 2026-04-10
|
|
73
73
|
|
|
74
|
+
PROJECT SCOPING: search and list default to the CURRENT directory's project.
|
|
75
|
+
--all Search across ALL projects (use when the answer may live
|
|
76
|
+
in another repo, or when a scoped search returns little)
|
|
77
|
+
--project PATH Scope to a specific project path instead of the CWD
|
|
78
|
+
If results look thin or empty, retry with --all before concluding nothing exists.
|
|
79
|
+
|
|
74
80
|
CRITICAL READING RULE: After searching, ALWAYS read the matched message:
|
|
75
81
|
$RECALL_BIN <session-id> <message-id>
|
|
76
82
|
This auto-centers on the match and shows surrounding turns. The output
|
|
@@ -192,6 +198,33 @@ $RECALL_BIN "old bug" --until 2026-03-15
|
|
|
192
198
|
`$RECALL_BIN --list --since 2026-04-10 --until 2026-04-10` to find all sessions,
|
|
193
199
|
then search with topic keywords + date flags if needed.
|
|
194
200
|
|
|
201
|
+
## Project scope
|
|
202
|
+
|
|
203
|
+
**Search and list default to the current working directory's project.** Recall
|
|
204
|
+
filters results to the project whose path is your CWD — so from inside one repo
|
|
205
|
+
you only see that repo's sessions. This keeps everyday recall focused, but it
|
|
206
|
+
silently hides history when the answer lives elsewhere.
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
# Default — scoped to the CWD's project
|
|
210
|
+
$RECALL_BIN "auth refactor"
|
|
211
|
+
|
|
212
|
+
# Search every project (cross-repo questions, or when a scoped search is thin)
|
|
213
|
+
$RECALL_BIN "auth refactor" --all
|
|
214
|
+
|
|
215
|
+
# Scope to a specific project regardless of CWD
|
|
216
|
+
$RECALL_BIN "auth refactor" --project /home/me/dev/other-repo
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
- `--all` — disable scoping; search across all indexed projects
|
|
220
|
+
- `--project PATH` — scope to an explicit project path instead of the CWD
|
|
221
|
+
- Both work in search and list modes
|
|
222
|
+
|
|
223
|
+
**When to reach for `--all`:** the user asks about work that may span repos, the
|
|
224
|
+
question isn't tied to the current repo, or a default (scoped) search returns
|
|
225
|
+
few/zero results. A thin scoped result is often just the scope — retry with
|
|
226
|
+
`--all` before concluding the history doesn't exist.
|
|
227
|
+
|
|
195
228
|
## Recency boost
|
|
196
229
|
|
|
197
230
|
When the user says "recently", "latest", "last few days", or otherwise indicates
|
|
@@ -209,4 +242,5 @@ pushing recent sessions to the top of results. Combine with `--since` for best r
|
|
|
209
242
|
- **Search is cheap, reading is expensive.** Run 3-5 varied queries before committing to reading sessions.
|
|
210
243
|
- **Message IDs are stable.** You can reference them across searches.
|
|
211
244
|
- **Use `--since` / `--until` to scope.** Both search and list modes accept date flags.
|
|
245
|
+
- **Search is scoped to the CWD's project by default.** Add `--all` for cross-repo questions or when a scoped search comes back thin.
|
|
212
246
|
- **Raw JSON output** (`--raw`) is available for programmatic processing.
|
package/dist/embed-pending.js
CHANGED
|
@@ -6419,9 +6419,14 @@ function extractEntryText(entry) {
|
|
|
6419
6419
|
}
|
|
6420
6420
|
return "";
|
|
6421
6421
|
}
|
|
6422
|
+
function entriesCwd(entries) {
|
|
6423
|
+
for (const e of entries) {
|
|
6424
|
+
if (e.cwd)
|
|
6425
|
+
return e.cwd;
|
|
6426
|
+
}
|
|
6427
|
+
return void 0;
|
|
6428
|
+
}
|
|
6422
6429
|
async function ingestSessionMessages(sessionId, transcriptPath, vendor, options) {
|
|
6423
|
-
const rawProjectId = options?.projectId ?? null;
|
|
6424
|
-
const projectId = rawProjectId ? normalizePath(rawProjectId) : null;
|
|
6425
6430
|
let rawEntries;
|
|
6426
6431
|
try {
|
|
6427
6432
|
if (vendor === "claude") {
|
|
@@ -6442,6 +6447,8 @@ async function ingestSessionMessages(sessionId, transcriptPath, vendor, options)
|
|
|
6442
6447
|
if (rawEntries.length === 0) {
|
|
6443
6448
|
return { sessionId, chunksCreated: 0, skipped: true };
|
|
6444
6449
|
}
|
|
6450
|
+
const rawProjectId = options?.projectId ?? entriesCwd(rawEntries);
|
|
6451
|
+
const projectId = rawProjectId ? normalizePath(rawProjectId) : null;
|
|
6445
6452
|
const filtered = stripToolContent(rawEntries);
|
|
6446
6453
|
const topLevel = filtered.filter((e) => !e.parentToolUseID);
|
|
6447
6454
|
const records = [];
|
package/dist/recall.js
CHANGED
|
@@ -13616,9 +13616,14 @@ function extractEntryText(entry) {
|
|
|
13616
13616
|
}
|
|
13617
13617
|
return "";
|
|
13618
13618
|
}
|
|
13619
|
+
function entriesCwd(entries) {
|
|
13620
|
+
for (const e2 of entries) {
|
|
13621
|
+
if (e2.cwd)
|
|
13622
|
+
return e2.cwd;
|
|
13623
|
+
}
|
|
13624
|
+
return void 0;
|
|
13625
|
+
}
|
|
13619
13626
|
async function ingestSessionMessages(sessionId, transcriptPath, vendor, options) {
|
|
13620
|
-
const rawProjectId = options?.projectId ?? null;
|
|
13621
|
-
const projectId = rawProjectId ? normalizePath(rawProjectId) : null;
|
|
13622
13627
|
let rawEntries;
|
|
13623
13628
|
try {
|
|
13624
13629
|
if (vendor === "claude") {
|
|
@@ -13639,6 +13644,8 @@ async function ingestSessionMessages(sessionId, transcriptPath, vendor, options)
|
|
|
13639
13644
|
if (rawEntries.length === 0) {
|
|
13640
13645
|
return { sessionId, chunksCreated: 0, skipped: true };
|
|
13641
13646
|
}
|
|
13647
|
+
const rawProjectId = options?.projectId ?? entriesCwd(rawEntries);
|
|
13648
|
+
const projectId = rawProjectId ? normalizePath(rawProjectId) : null;
|
|
13642
13649
|
const filtered = stripToolContent(rawEntries);
|
|
13643
13650
|
const topLevel = filtered.filter((e2) => !e2.parentToolUseID);
|
|
13644
13651
|
const records = [];
|
package/dist/stop-hook.js
CHANGED
|
@@ -2663,9 +2663,14 @@ function extractEntryText(entry) {
|
|
|
2663
2663
|
}
|
|
2664
2664
|
return "";
|
|
2665
2665
|
}
|
|
2666
|
+
function entriesCwd(entries) {
|
|
2667
|
+
for (const e of entries) {
|
|
2668
|
+
if (e.cwd)
|
|
2669
|
+
return e.cwd;
|
|
2670
|
+
}
|
|
2671
|
+
return void 0;
|
|
2672
|
+
}
|
|
2666
2673
|
async function ingestSessionMessages(sessionId, transcriptPath, vendor, options) {
|
|
2667
|
-
const rawProjectId = options?.projectId ?? null;
|
|
2668
|
-
const projectId = rawProjectId ? normalizePath(rawProjectId) : null;
|
|
2669
2674
|
let rawEntries;
|
|
2670
2675
|
try {
|
|
2671
2676
|
if (vendor === "claude") {
|
|
@@ -2686,6 +2691,8 @@ async function ingestSessionMessages(sessionId, transcriptPath, vendor, options)
|
|
|
2686
2691
|
if (rawEntries.length === 0) {
|
|
2687
2692
|
return { sessionId, chunksCreated: 0, skipped: true };
|
|
2688
2693
|
}
|
|
2694
|
+
const rawProjectId = options?.projectId ?? entriesCwd(rawEntries);
|
|
2695
|
+
const projectId = rawProjectId ? normalizePath(rawProjectId) : null;
|
|
2689
2696
|
const filtered = stripToolContent(rawEntries);
|
|
2690
2697
|
const topLevel = filtered.filter((e) => !e.parentToolUseID);
|
|
2691
2698
|
const records = [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "crispy-recall",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Local session transcript memory for Claude Code and Codex — search past sessions with FTS5 + semantic vectors.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Sylvester Wong",
|
|
@@ -39,17 +39,15 @@
|
|
|
39
39
|
"test": "vitest run",
|
|
40
40
|
"prepublishOnly": "npm run build"
|
|
41
41
|
},
|
|
42
|
-
"
|
|
42
|
+
"devDependencies": {
|
|
43
43
|
"@anthropic-ai/claude-agent-sdk": "0.2.114",
|
|
44
44
|
"@clack/prompts": "^0.7.0",
|
|
45
|
+
"@types/node": "^20.0.0",
|
|
46
|
+
"esbuild": "^0.20.0",
|
|
45
47
|
"extract-zip": "^2.0.1",
|
|
46
48
|
"glob": "^10.4.5",
|
|
47
49
|
"node-sqlite3-wasm": "^0.8.53",
|
|
48
|
-
"picocolors": "^1.0.0"
|
|
49
|
-
},
|
|
50
|
-
"devDependencies": {
|
|
51
|
-
"@types/node": "^20.0.0",
|
|
52
|
-
"esbuild": "^0.20.0",
|
|
50
|
+
"picocolors": "^1.0.0",
|
|
53
51
|
"typescript": "^5.0.0",
|
|
54
52
|
"vitest": "^4.0.18"
|
|
55
53
|
}
|