claude-recall 0.32.0 → 0.33.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
@@ -92,6 +92,8 @@ tail -5 ~/.claude-recall/hook-logs/cc-classifier.log # which model ran, what w
92
92
  claude-recall search "something you said"
93
93
  ```
94
94
 
95
+ Design details (the `claude -p` key-precedence gotcha, recursion guards, which features run on the subscription): [docs/cc-llm-capture.md](docs/cc-llm-capture.md).
96
+
95
97
  ### Pi
96
98
 
97
99
  ```bash
@@ -169,7 +171,7 @@ Once installed, Claude Recall works in the background (CC = Claude Code):
169
171
  | **Session exit** | An auto-checkpoint (`{completed, remaining, blockers}`) is saved for next time | ✓ | ✓ | |
170
172
  | **End of session** | Failure patterns become candidate lessons; validated ones are promoted to rules | ✓ | ✓ | |
171
173
 
172
- Classification runs on each runtime's **own** LLM — Claude Code via headless `claude -p` on your subscription; Kiro via `kiro-cli chat --no-interactive` on Kiro credits — with `ANTHROPIC_API_KEY` (if you exported one *and* opted in) and regex as fallbacks. No API key is ever required; no configuration needed.
174
+ Classification runs on each runtime's **own** LLM — Claude Code via headless `claude -p` on your subscription; Kiro via `kiro-cli chat --no-interactive` on Kiro credits — with regex as the fallback. **An exported `ANTHROPIC_API_KEY` is never touched** unless you explicitly opt in with `CLAUDE_RECALL_PREFER_API_KEY=1`. No API key is ever required; no configuration needed.
173
175
 
174
176
  ```bash
175
177
  # Verify it's working
@@ -206,7 +208,7 @@ claude-recall checkpoint save --completed "API layer" --remaining "wire the UI"
206
208
  claude-recall checkpoint load
207
209
  ```
208
210
 
209
- Auto-checkpoints are also saved on session exit in Claude Code and Pi (Pi has no `--resume`, so this is its main recovery path). Extraction runs on your **Claude subscription** (headless `claude -p`) — like capture, no API key needed; an exported `ANTHROPIC_API_KEY` is only a fallback. The same applies to the other background LLM features (failure hindsight hints, end-of-session lesson extraction). A quality gate refuses to overwrite a manual checkpoint with a fabricated one when the task was already complete.
211
+ Auto-checkpoints are also saved on session exit in Claude Code and Pi (Pi has no `--resume`, so this is its main recovery path). Extraction runs on your **Claude subscription** (headless `claude -p`) — like capture, no API key needed and no key touched. The same applies to the other background LLM features (failure hindsight hints, end-of-session lesson extraction). Pi-only machines without the `claude` binary can opt in to an `ANTHROPIC_API_KEY` with `CLAUDE_RECALL_PREFER_API_KEY=1`. A quality gate refuses to overwrite a manual checkpoint with a fabricated one when the task was already complete.
210
212
 
211
213
  ### Troubleshooting
212
214
 
@@ -387,11 +389,11 @@ Defaults work out of the box; tune via environment variables as needed.
387
389
  | Variable | Default | Effect |
388
390
  | ---------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------- |
389
391
  | `CLAUDE_RECALL_DB_PATH` | `~/.claude-recall/` | Database directory. |
390
- | `ANTHROPIC_API_KEY` | _(unset)_ | Optional personal API key for Haiku-based LLM features. **Never required and never provided by Claude Code** — capture, checkpoint extraction, hindsight hints, and session lessons all use each runtime's own LLM first (Claude subscription via `claude -p`; Kiro credits via `kiro-cli`). A key you exported is only consulted as a fallback, or first with `CLAUDE_RECALL_PREFER_API_KEY=1`. Regex is the final fallback. |
392
+ | `ANTHROPIC_API_KEY` | _(unset)_ | Optional personal API key for Haiku-based LLM features. **Never required, never provided by Claude Code, and never touched unless you opt in** with `CLAUDE_RECALL_PREFER_API_KEY=1` — capture, checkpoint extraction, hindsight hints, and session lessons all run on each runtime's own LLM (Claude subscription via `claude -p`; Kiro credits via `kiro-cli`), with regex as the fallback. |
391
393
  | `CLAUDE_RECALL_CC_MODEL` | `haiku` | Dedicated model for capture classification under Claude Code (passed to `claude -p --model`) — independent of your interactive session model. |
392
394
  | `CLAUDE_RECALL_CC_LLM_TIMEOUT_MS` | `30000` | Hard cap on the headless `claude -p` classify call before the capture worker gives up and falls through. |
393
395
  | `CLAUDE_RECALL_KIRO_MODEL` | `claude-haiku-4.5` | Dedicated model for Kiro-LLM capture classification — **independent of your interactive Kiro chat model**. Raise to `claude-sonnet-4.6` for steadier judgement at more credits. See [docs/kiro-llm-capture.md](docs/kiro-llm-capture.md). |
394
- | `CLAUDE_RECALL_PREFER_API_KEY` | _(unset)_ | Force `ANTHROPIC_API_KEY`-based classification ahead of the runtime's included LLM (uses your Anthropic API credits e.g. for a model you pay for). Applies under both Claude Code and Kiro. |
396
+ | `CLAUDE_RECALL_PREFER_API_KEY` | _(unset)_ | **The only switch that enables the `ANTHROPIC_API_KEY` backend** (and prefers it first). For Pi-only machines without the `claude` binary, or a stronger model you deliberately pay for. Applies to all LLM features, under Claude Code, Kiro, and Pi. |
395
397
  | `CLAUDE_RECALL_KIRO_LLM_TIMEOUT_MS` | `30000` | Hard cap on the headless `kiro-cli` classify call before the capture worker gives up and falls back to regex. |
396
398
  | `CLAUDE_RECALL_LOAD_BUDGET_TOKENS` | `2000` | Token budget for the `load_rules` payload. Rules are emitted in priority order (corrections → preferences by citation → devops by citation → failures) and dropped rules surface via `search_memory`. |
397
399
  | `CLAUDE_RECALL_AUTO_DEMOTE` | `false` | When `true`, auto-demote rules on MCP boot where `load_count >= CLAUDE_RECALL_DEMOTE_MIN_LOADS`, `cite_count = 0`, and age `> CLAUDE_RECALL_DEMOTE_MIN_AGE_DAYS`. Still reversible via `rules promote <id>`. |
@@ -5,10 +5,10 @@
5
5
  * Requires ANTHROPIC_API_KEY in the environment — a personal pay-as-you-go
6
6
  * API key the user exported themselves. Claude Code does NOT mint one from
7
7
  * the user's subscription (hooks just inherit the user's environment), which
8
- * is why this is a FALLBACK backend: the capture workers prefer each
9
- * runtime's included LLM (claude -p / kiro-cli — see cc-classifier.ts and
10
- * kiro-classifier.ts) and only land here when a key is present. Falls back
11
- * gracefully (returns null) when unavailable.
8
+ * is why this backend is STRICTLY OPT-IN (CLAUDE_RECALL_PREFER_API_KEY): the
9
+ * default chains use each runtime's included LLM only (claude -p / kiro-cli —
10
+ * see cc-classifier.ts and kiro-classifier.ts), and an exported key is never
11
+ * spent silently. Falls back gracefully (returns null) when unavailable.
12
12
  */
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
14
  exports.classifyWithLLM = classifyWithLLM;
@@ -146,11 +146,12 @@ function parseJSON(text) {
146
146
  * extraction, checkpoint extraction, batch classification) and return raw
147
147
  * text, or null when no backend is available.
148
148
  *
149
- * Backend order matches capture: the user's Claude SUBSCRIPTION (headless
150
- * `claude -p`) before a personally-exported ANTHROPIC_API_KEY, flipped by
151
- * CLAUDE_RECALL_PREFER_API_KEY. So running out of Anthropic API credits — or
152
- * never having a key at all does not disable these features on any machine
153
- * with the `claude` binary (Claude Code itself, or Pi running alongside it).
149
+ * Backend policy matches capture: the user's Claude SUBSCRIPTION (headless
150
+ * `claude -p`) is the only default backend — a personally-exported
151
+ * ANTHROPIC_API_KEY is STRICTLY OPT-IN via CLAUDE_RECALL_PREFER_API_KEY and
152
+ * never consulted otherwise, not even as a fallback. The opt-in exists for
153
+ * Pi-only users (no `claude` binary; their key is how they run Pi itself)
154
+ * and anyone deliberately paying for a stronger model.
154
155
  *
155
156
  * The CLI backend is skipped inside a nested headless session
156
157
  * (CLAUDE_RECALL_NESTED): if `claude -p` fires user-scope hooks of its own,
@@ -182,7 +183,7 @@ async function completeText(systemPrompt, userContent, maxTokens) {
182
183
  : (0, cc_classifier_1.completeWithClaudeCli)(`${systemPrompt}\n\n${userContent}`, { timeoutMs: SECONDARY_CLI_TIMEOUT_MS });
183
184
  const backends = process.env.CLAUDE_RECALL_PREFER_API_KEY
184
185
  ? [viaApi, viaCli]
185
- : [viaCli, viaApi];
186
+ : [viaCli];
186
187
  for (const backend of backends) {
187
188
  const text = await backend();
188
189
  if (text !== null && text.trim().length > 0)
@@ -166,18 +166,17 @@ function classifyContentRegex(text) {
166
166
  * workers, which set the *_CLASSIFIER env vars — a ~4s CLI call can't run
167
167
  * inline on a turn):
168
168
  * - Under Claude Code (CLAUDE_RECALL_CC_CLASSIFIER set by cc-capture-worker):
169
- * headless `claude -p` on the user's Claude SUBSCRIPTION → ANTHROPIC_API_KEY
170
- * if present → regex.
169
+ * headless `claude -p` on the user's Claude SUBSCRIPTION → regex.
171
170
  * - Under Kiro (CLAUDE_RECALL_KIRO_CLASSIFIER set by kiro-capture-worker):
172
171
  * Kiro's own headless LLM (`kiro-cli chat --no-interactive`, Kiro credits)
173
- * → ANTHROPIC_API_KEY if present → regex.
174
- * - Inline callers (memory-stop batch, etc.): ANTHROPIC_API_KEY regex.
172
+ * → regex.
173
+ * - Inline callers: straight to regex.
175
174
  *
176
- * The included LLM is preferred so a stray exported key doesn't silently
177
- * spend the user's Anthropic API credits; CLAUDE_RECALL_PREFER_API_KEY flips
178
- * the order. NOTE: ANTHROPIC_API_KEY is always a personal key the user
179
- * exported — Claude Code does NOT provide one from the subscription.
180
- * See docs/kiro-llm-capture.md.
175
+ * The ANTHROPIC_API_KEY path is STRICTLY OPT-IN via
176
+ * CLAUDE_RECALL_PREFER_API_KEY an exported key is never consulted
177
+ * otherwise, not even as a fallback. (It is always a personal key the user
178
+ * exported — Claude Code does NOT provide one from the subscription.)
179
+ * See docs/cc-llm-capture.md and docs/kiro-llm-capture.md.
181
180
  */
182
181
  async function classifyContent(text) {
183
182
  // Guard the LLM paths the same way the regex path is guarded: a question or
@@ -202,30 +201,25 @@ async function classifyContentInner(text) {
202
201
  // module graph for hook invocations that don't run in a capture worker.
203
202
  const tryKiro = async () => (await Promise.resolve().then(() => __importStar(require('./kiro-classifier')))).classifyWithKiro(text);
204
203
  const tryCc = async () => (await Promise.resolve().then(() => __importStar(require('./cc-classifier')))).classifyWithClaudeCli(text);
205
- // Order the LLM backends. Each runtime's INCLUDED LLM comes before a stray
206
- // ANTHROPIC_API_KEY: a key exported for other tools should not silently
207
- // spend the user's Anthropic API credits when the runtime already provides
208
- // an LLM Kiro via `kiro-cli chat --no-interactive` (Kiro credits), Claude
209
- // Code via `claude -p` (the user's Claude subscription). Set
210
- // CLAUDE_RECALL_PREFER_API_KEY to force the key first (e.g. to use a
211
- // stronger model you pay for). The CLI backends only run inside their
212
- // detached capture workers (which set the *_CLASSIFIER env vars) inline
213
- // hook paths stay key regex, since a ~4s CLI call can't block a turn.
204
+ // Pick the LLM backends. The ANTHROPIC_API_KEY path is STRICTLY OPT-IN
205
+ // (CLAUDE_RECALL_PREFER_API_KEY): claude-recall was built for runtimes that
206
+ // bring their own LLM Kiro via `kiro-cli chat --no-interactive` (Kiro
207
+ // credits), Claude Code via `claude -p` (the user's Claude subscription)
208
+ // and a key exported for other tools must NEVER be spent silently, not even
209
+ // as a fallback. Without the opt-in, the chain is included LLM → regex.
210
+ // The opt-in exists for Pi-only users (no `claude` binary; their key is how
211
+ // they run Pi itself) and anyone deliberately paying for a stronger model.
212
+ // The CLI backends only run inside their detached capture workers (which
213
+ // set the *_CLASSIFIER env vars) — inline hook paths go straight to regex,
214
+ // since a ~4s CLI call can't block a turn.
214
215
  const backends = [];
215
- if (underKiro && !preferApiKey) {
216
- backends.push(tryKiro, tryApiKey);
217
- }
218
- else if (underKiro) {
219
- backends.push(tryApiKey, tryKiro);
220
- }
221
- else if (underCc && !preferApiKey) {
222
- backends.push(tryCc, tryApiKey);
216
+ if (preferApiKey)
217
+ backends.push(tryApiKey);
218
+ if (underKiro) {
219
+ backends.push(tryKiro);
223
220
  }
224
221
  else if (underCc) {
225
- backends.push(tryApiKey, tryCc);
226
- }
227
- else {
228
- backends.push(tryApiKey);
222
+ backends.push(tryCc);
229
223
  }
230
224
  for (const backend of backends) {
231
225
  const result = await backend();
@@ -0,0 +1,147 @@
1
+ # Using your Claude subscription for memory capture (no API key)
2
+
3
+ The Claude Code counterpart to [kiro-llm-capture.md](kiro-llm-capture.md): how
4
+ claude-recall's LLM features run on the user's **Claude subscription** — the
5
+ same login that powers their interactive session — instead of a personal
6
+ `ANTHROPIC_API_KEY`.
7
+
8
+ ## The problem
9
+
10
+ Claude Recall's LLM classifier originally called Claude Haiku through the
11
+ Anthropic SDK, which needs `ANTHROPIC_API_KEY` — a **personal pay-as-you-go
12
+ key**. For a long time the docs claimed Claude Code "provides the key to its
13
+ hooks." That was false: Claude Code does not mint a key from the user's
14
+ subscription; hooks merely inherit the user's environment. So the key path
15
+ only ever worked for users who had exported their own key, and it silently
16
+ spent **their API credits** — a separate wallet from the Claude subscription
17
+ they were already paying for.
18
+
19
+ The failure mode that exposed all of this: a user's exported key ran out of
20
+ credits. Every SDK call failed silently, capture degraded to the regex
21
+ fallback, and the regex promptly stored four junk memories in one session —
22
+ while the user reasonably believed "the LLM" was doing the classifying.
23
+
24
+ ## The finding
25
+
26
+ **`claude -p "<prompt>"` is a headless one-shot completion that runs on the
27
+ user's Claude Code login** — the direct analogue of the earlier
28
+ `kiro-cli chat --no-interactive` discovery. A background worker can shell out
29
+ to it to classify text with no API key and no extra cost beyond the
30
+ subscription usage the user already has.
31
+
32
+ One gotcha made this non-trivial, and it's the most important line in the
33
+ implementation:
34
+
35
+ > **`claude -p` prefers `ANTHROPIC_API_KEY` over subscription auth when the
36
+ > key is present in the environment.**
37
+
38
+ So a stray exported key — possibly dead, possibly billing a wallet the user
39
+ forgot about — would silently hijack every headless call. The fix:
40
+ `completeWithClaudeCli()` **strips `ANTHROPIC_API_KEY` from the child env**,
41
+ forcing subscription auth unconditionally. (Verified live: with a
42
+ credits-exhausted key in the env, `claude -p` returned
43
+ `Credit balance is too low`; with the key stripped, the same call succeeded on
44
+ the login.)
45
+
46
+ ## The design
47
+
48
+ ```
49
+ Claude Code UserPromptSubmit
50
+
51
+
52
+ hook run correction-detector (name unchanged in settings.json;
53
+ │ returns in <100 ms)
54
+ │ spawn detached, pipe payload via stdin
55
+
56
+ hook run cc-capture-worker (background, survives parent exit)
57
+ │ sets CLAUDE_RECALL_CC_CLASSIFIER=1
58
+
59
+ handleCorrectionDetector → classifyContent()
60
+
61
+ ├─ classifyWithClaudeCli() → claude -p --model haiku "<prompt>"
62
+ │ (subscription auth, key stripped)
63
+ └─ regex fallback
64
+
65
+ (classifyWithLLM() / ANTHROPIC_API_KEY exists but is OPT-IN only —
66
+ see below; it is never in the default chain)
67
+ ```
68
+
69
+ Precedence mirrors Kiro: **the runtime's included LLM → regex.** An exported
70
+ `ANTHROPIC_API_KEY` is **never consulted by default — not even as a
71
+ fallback**; `CLAUDE_RECALL_PREFER_API_KEY=1` is the one switch that enables
72
+ (and prefers) it. The registered hook name (`hook run correction-detector`)
73
+ was deliberately kept, so existing `settings.json` files work with no
74
+ re-setup — only the dispatch behind it changed.
75
+
76
+ **Trade-off:** the synchronous `📌 Recall: auto-captured …` echo is gone.
77
+ A cold `claude -p` takes ~4 s, far too slow to block the user's prompt, so
78
+ capture is silent and lands a few seconds later — the same contract Kiro has
79
+ always had. Verify via `~/.claude-recall/hook-logs/cc-classifier.log`
80
+ (`classified via claude -p (model=…, Claude subscription, no API key)`) or
81
+ `claude-recall search`.
82
+
83
+ ### Recursion guard
84
+
85
+ The nested headless session is itself a Claude Code session. If the user has
86
+ claude-recall hooks registered at **user scope** (`~/.claude/settings.json`),
87
+ the classify call would fire those hooks, which would spawn another worker,
88
+ which would run another `claude -p` — forever. Two layers prevent this:
89
+
90
+ 1. `claude -p` children run with `cwd = os.tmpdir()`, so **project**
91
+ settings/hooks never load.
92
+ 2. Children are marked with `CLAUDE_RECALL_NESTED=1` (plus the legacy
93
+ `CLAUDE_RECALL_CC_CLASSIFIER=1`). The capture hook refuses to spawn a
94
+ worker, and the secondary-feature backend refuses to invoke the CLI, when
95
+ either marker is present.
96
+
97
+ ### Beyond capture: the secondary features (0.32.0)
98
+
99
+ `completeWithClaudeCli()` is a generic completion primitive, and the four
100
+ features that previously knew only the key path now route through it with the
101
+ same precedence:
102
+
103
+ | Feature | Runs in | Without any key, now |
104
+ | --- | --- | --- |
105
+ | Auto-checkpoint extraction | Session-exit worker (CC + **Pi** — Pi's only recovery path, it has no `--resume`) | Works via `claude -p` |
106
+ | Failure hindsight hints | Stop hook, inline | Works via `claude -p` |
107
+ | End-of-session lesson extraction | Stop hook, inline | Works via `claude -p` |
108
+ | Batch classification | Stop hook, inline | Works via `claude -p` |
109
+
110
+ Two budget rules keep the inline ones inside the Stop hook's ~40 s window
111
+ (capture doesn't need them — it runs in a detached worker):
112
+
113
+ - each secondary CLI call is capped at **10 s** (vs the worker's 30 s), and
114
+ - hindsight-hint generation is capped at **5 LLM calls per run** (the loop
115
+ over detected failures is otherwise unbounded; failures past the cap keep
116
+ the grounded generic lesson text).
117
+
118
+ Under **Pi** these functions run in-process, so Pi benefits automatically on
119
+ any machine with the `claude` binary installed alongside. Under **Kiro** the
120
+ Stop-hook features mostly don't run (no transcript in its hooks), and capture
121
+ uses the Kiro backend.
122
+
123
+ ### Configuration
124
+
125
+ | Variable | Default | Effect |
126
+ | --- | --- | --- |
127
+ | `CLAUDE_RECALL_CC_MODEL` | `haiku` | Model passed to `claude -p --model` — a dedicated classifier model, independent of the user's interactive session model. |
128
+ | `CLAUDE_RECALL_CC_LLM_TIMEOUT_MS` | `30000` | Hard cap on the capture worker's `claude -p` call. (Secondary features use a fixed 10 s per call.) |
129
+ | `CLAUDE_RECALL_PREFER_API_KEY` | *(unset)* | **The only switch that enables the `ANTHROPIC_API_KEY` backend** (and prefers it first) — without it an exported key is never touched, not even as a fallback. For Pi-only machines without the `claude` binary, or a stronger model you deliberately pay for. Applies to capture and the secondary features, on every runtime. |
130
+ | `CLAUDE_RECALL_NESTED` | *(set on `claude -p` children)* | Recursion marker — never set it by hand. |
131
+
132
+ ## Caveats
133
+
134
+ - **Requires the `claude` binary on `PATH`.** Absent (e.g. a bare CI box, or a
135
+ Pi-only machine), the CLI backend errors out and the chain falls through to
136
+ regex — or to an `ANTHROPIC_API_KEY` if you opted in with
137
+ `CLAUDE_RECALL_PREFER_API_KEY=1`. No crash, no exception.
138
+ - **Subscription usage.** Each classified prompt is one small Haiku call
139
+ against the user's Claude plan limits. That is the deliberate trade — the
140
+ user's existing plan instead of a second wallet.
141
+ - **Latency.** ~4 s cold per call. Fine in a detached worker; the reason the
142
+ inline features carry the 10 s cap and hint budget.
143
+ - **Consistency.** Same probabilistic caveat as the Kiro backend: the
144
+ classifier is an LLM judgement call. The classify prompt carries a
145
+ "standalone rule" test with negative examples precisely because early
146
+ versions stored one-off task instructions ("first fix the sentence") as
147
+ corrections.
@@ -9,7 +9,7 @@ Claude Haiku through `ANTHROPIC_API_KEY` — a personal API key the user had
9
9
  exported themselves. (Claude Code does **not** mint a key from the user's
10
10
  subscription; hooks merely inherit the environment. The headless-CLI approach
11
11
  documented here was later applied back to Claude Code via `claude -p` on
12
- subscription auth — see `src/hooks/cc-classifier.ts`.)
12
+ subscription auth — see [cc-llm-capture.md](cc-llm-capture.md).)
13
13
 
14
14
  Kiro CLI does **not** set `ANTHROPIC_API_KEY`. So under Kiro the classifier fell
15
15
  back to a conservative regex that only fires on explicit phrasings
@@ -89,20 +89,24 @@ Kiro userPromptSubmit
89
89
 
90
90
  handleCorrectionDetector → classifyContent()
91
91
 
92
- ├─ classifyWithLLM() → ANTHROPIC_API_KEY (unset under Kiro) → null
93
92
  ├─ classifyWithKiro() → kiro-cli chat --no-interactive --agent
94
93
  │ claude-recall-classifier --model claude-haiku-4.5
95
94
  │ → {"type","confidence","extract"}
96
- └─ regex fallback (only if both above yield nothing)
95
+ └─ regex fallback (only if the above yields nothing)
96
+
97
+ (classifyWithLLM() / ANTHROPIC_API_KEY exists but is OPT-IN only —
98
+ never in the default chain)
97
99
  ```
98
100
 
99
- Capture precedence under Kiro: **Kiro's included LLM → `ANTHROPIC_API_KEY` if
100
- present → regex as a last resort.** The Kiro LLM comes first *even when a key is
101
- set*, so a key exported for other tools never silently spends the user's
102
- Anthropic credits Kiro already ships an LLM. `CLAUDE_RECALL_PREFER_API_KEY=1`
103
- flips the order back to key-first for anyone who deliberately wants to pay for a
104
- stronger model. (Under Claude Code the same pattern applies with `claude -p` on
105
- the user's subscription as the included LLM see `src/hooks/cc-classifier.ts`.)
101
+ Capture precedence under Kiro: **Kiro's included LLM → regex as a last
102
+ resort.** An exported `ANTHROPIC_API_KEY` is **never consulted by default
103
+ not even as a fallback** — so a key exported for other tools never silently
104
+ spends the user's Anthropic credits; Kiro already ships an LLM.
105
+ `CLAUDE_RECALL_PREFER_API_KEY=1` is the one explicit switch that enables (and
106
+ prefers) the key, for anyone who deliberately wants to pay for a stronger
107
+ model. (Under Claude Code the same pattern applies with `claude -p` on the
108
+ user's subscription as the included LLM — see
109
+ [cc-llm-capture.md](cc-llm-capture.md).)
106
110
 
107
111
  ### Output parsing
108
112
 
@@ -119,7 +123,7 @@ returns `null`, degrading to regex — a hook must never throw.
119
123
  | `CLAUDE_RECALL_KIRO_CLASSIFIER` | *(set by the worker)* | Enables the Kiro-LLM path in `classifyContent`. Set automatically by `kiro-capture-worker`; never needed by hand. |
120
124
  | `CLAUDE_RECALL_KIRO_MODEL` | `claude-haiku-4.5` | Model for the classify call, passed explicitly as `--model`. This is a **dedicated classifier model, independent of the user's interactive Kiro chat model** (e.g. `auto`) — the headless call always uses this value. Raise to `claude-sonnet-4.6` for steadier judgement at ~3× the credits. |
121
125
  | `CLAUDE_RECALL_KIRO_LLM_TIMEOUT_MS` | `30000` | Hard cap on the headless call before the worker gives up and falls back to regex. |
122
- | `CLAUDE_RECALL_PREFER_API_KEY` | *(unset)* | Force `ANTHROPIC_API_KEY`-based classification ahead of Kiro's included LLM (opt-in; uses your Anthropic credits). |
126
+ | `CLAUDE_RECALL_PREFER_API_KEY` | *(unset)* | **The only switch that enables the `ANTHROPIC_API_KEY` backend** without it an exported key is never touched, not even as a fallback. |
123
127
 
124
128
  ## Caveats
125
129
 
package/docs/kiro.md CHANGED
@@ -74,7 +74,7 @@ To decide what's worth remembering, the capture hook classifies each prompt via
74
74
 
75
75
  **The classifier uses a dedicated, fixed model — not your chat model.** It always runs the model in `CLAUDE_RECALL_KIRO_MODEL` (default `claude-haiku-4.5`, chosen because classification is cheap and high-volume), **independent of your interactive Kiro chat model** (e.g. `auto`). This keeps classification cost predictable no matter what your chat is set to. Set `CLAUDE_RECALL_KIRO_MODEL` to any model from `kiro-cli chat --list-models` to change it. Every successful classification is logged to `~/.claude-recall/hook-logs/kiro-classifier.log` as `classified via kiro-cli (model=…, Kiro credits, no API key)`, so you can always see which model ran.
76
76
 
77
- **Under Kiro the included LLM is used first even if you happen to have `ANTHROPIC_API_KEY` set** — so a key exported for other tools won't quietly spend your Anthropic credits. Order: Kiro's LLM → `ANTHROPIC_API_KEY` (if present) → regex; set `CLAUDE_RECALL_PREFER_API_KEY=1` to force your key first (e.g. for a stronger model you pay for).
77
+ **An exported `ANTHROPIC_API_KEY` is never touched** — a key exported for other tools won't quietly spend your Anthropic credits, not even as a fallback. Order: Kiro's LLM → regex. Setting `CLAUDE_RECALL_PREFER_API_KEY=1` is the one explicit switch that enables (and prefers) your key, e.g. for a stronger model you pay for.
78
78
 
79
79
  Design details, latency measurements, and output-parsing internals: [kiro-llm-capture.md](kiro-llm-capture.md).
80
80
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-recall",
3
- "version": "0.32.0",
3
+ "version": "0.33.0",
4
4
  "description": "Persistent memory for Claude Code and Pi with native Skills integration, automatic capture, failure learning, and project scoping",
5
5
  "main": "dist/index.js",
6
6
  "bin": {