claude-recall 0.20.6 → 0.20.7
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/.claude/skills/auto-corrections/SKILL.md +2 -1
- package/.claude/skills/auto-corrections/manifest.json +4 -3
- package/.claude/skills/auto-preferences/SKILL.md +6 -1
- package/.claude/skills/auto-preferences/manifest.json +8 -3
- package/dist/cli/claude-recall-cli.js +13 -1
- package/dist/cli/commands/hook-commands.js +5 -0
- package/dist/hooks/memory-stop-hook.js +30 -1
- package/dist/hooks/post-compact-reload.js +57 -0
- package/docs/cc-agent-harness.md +114 -0
- package/package.json +1 -1
|
@@ -8,7 +8,7 @@ source: claude-recall
|
|
|
8
8
|
|
|
9
9
|
# Corrections
|
|
10
10
|
|
|
11
|
-
Auto-generated from
|
|
11
|
+
Auto-generated from 15 memories. Last updated: 2026-04-06.
|
|
12
12
|
|
|
13
13
|
## Rules
|
|
14
14
|
|
|
@@ -24,6 +24,7 @@ Auto-generated from 14 memories. Last updated: 2026-04-06.
|
|
|
24
24
|
- CORRECTION: Memory with complex metadata
|
|
25
25
|
- CORRECTION: Memory with complex metadata
|
|
26
26
|
- CORRECTION: Memory with complex metadata
|
|
27
|
+
- CORRECTION: Memory with complex metadata
|
|
27
28
|
- CORRECTION: License copyright should include user's name instead of 'Claude Recall Contributors'
|
|
28
29
|
- CORRECTION: License copyright should list your name instead of 'Claude Recall Contributors'
|
|
29
30
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"topicId": "corrections",
|
|
3
|
-
"sourceHash": "
|
|
4
|
-
"memoryCount":
|
|
5
|
-
"generatedAt": "2026-04-06T16:
|
|
3
|
+
"sourceHash": "6bede026828253771f48ae5c05e80878ab69beb584dfc06f416814840016ad6c",
|
|
4
|
+
"memoryCount": 15,
|
|
5
|
+
"generatedAt": "2026-04-06T16:51:19.054Z",
|
|
6
6
|
"memoryKeys": [
|
|
7
|
+
"memory_1775494279035_j6uj5lzxo",
|
|
7
8
|
"memory_1775492069326_vksvzmt3f",
|
|
8
9
|
"memory_1775491767369_sepsjmg8y",
|
|
9
10
|
"memory_1775169786543_43p8to1hu",
|
|
@@ -8,10 +8,15 @@ source: claude-recall
|
|
|
8
8
|
|
|
9
9
|
# Preferences
|
|
10
10
|
|
|
11
|
-
Auto-generated from
|
|
11
|
+
Auto-generated from 74 memories. Last updated: 2026-04-06.
|
|
12
12
|
|
|
13
13
|
## Rules
|
|
14
14
|
|
|
15
|
+
- Session test preference 1775494279149
|
|
16
|
+
- Test preference 1775494279061-2
|
|
17
|
+
- Test preference 1775494279061-1
|
|
18
|
+
- Test preference 1775494279061-0
|
|
19
|
+
- Test memory content
|
|
15
20
|
- Session test preference 1775492069465
|
|
16
21
|
- Test preference 1775492069353-2
|
|
17
22
|
- Test preference 1775492069353-1
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"topicId": "preferences",
|
|
3
|
-
"sourceHash": "
|
|
4
|
-
"memoryCount":
|
|
5
|
-
"generatedAt": "2026-04-06T16:
|
|
3
|
+
"sourceHash": "77d6964d46ea058e3de341d9d43c79901bc596a18b5a03fa8e402368ba20b412",
|
|
4
|
+
"memoryCount": 74,
|
|
5
|
+
"generatedAt": "2026-04-06T16:51:19.174Z",
|
|
6
6
|
"memoryKeys": [
|
|
7
|
+
"memory_1775494279150_n4pq7zy11",
|
|
8
|
+
"memory_1775494279108_6hbe8qoit",
|
|
9
|
+
"memory_1775494279088_nv8hjdm7s",
|
|
10
|
+
"memory_1775494279062_jx4wrwn6s",
|
|
11
|
+
"memory_1775494278982_fsc491z41",
|
|
7
12
|
"memory_1775492069467_5cturlg0a",
|
|
8
13
|
"memory_1775492069400_icg4tjivf",
|
|
9
14
|
"memory_1775492069377_goix7nu9v",
|
|
@@ -693,8 +693,20 @@ async function main() {
|
|
|
693
693
|
// This avoids registry lookups on every hook invocation.
|
|
694
694
|
const cliScript = path.join(packageDir, 'dist', 'cli', 'claude-recall-cli.js');
|
|
695
695
|
const hookCmd = `node ${cliScript} hook run`;
|
|
696
|
-
settings.hooksVersion = '
|
|
696
|
+
settings.hooksVersion = '11.0.0'; // v11 = add SessionStart(compact) for post-compaction rule reload
|
|
697
697
|
settings.hooks = {
|
|
698
|
+
SessionStart: [
|
|
699
|
+
{
|
|
700
|
+
matcher: "compact",
|
|
701
|
+
hooks: [
|
|
702
|
+
{
|
|
703
|
+
type: "command",
|
|
704
|
+
command: `${hookCmd} post-compact-reload`,
|
|
705
|
+
timeout: 10
|
|
706
|
+
}
|
|
707
|
+
]
|
|
708
|
+
}
|
|
709
|
+
],
|
|
698
710
|
PostToolUse: [
|
|
699
711
|
{
|
|
700
712
|
hooks: [
|
|
@@ -85,6 +85,11 @@ class HookCommands {
|
|
|
85
85
|
await handleToolFailure(input);
|
|
86
86
|
break;
|
|
87
87
|
}
|
|
88
|
+
case 'post-compact-reload': {
|
|
89
|
+
const { handlePostCompactReload } = await Promise.resolve().then(() => __importStar(require('../../hooks/post-compact-reload')));
|
|
90
|
+
await handlePostCompactReload(input);
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
88
93
|
case 'bash-failure-watcher': {
|
|
89
94
|
// Backward compat alias — routes to tool-outcome-watcher
|
|
90
95
|
const { handleBashFailureWatcher } = await Promise.resolve().then(() => __importStar(require('../../hooks/tool-outcome-watcher')));
|
|
@@ -114,6 +114,21 @@ async function handleMemoryStop(input) {
|
|
|
114
114
|
const sessionEntries = (0, shared_1.readTranscriptTail)(transcriptPath, 50);
|
|
115
115
|
if (sessionEntries.length >= 10) {
|
|
116
116
|
const conversationEntries = buildConversationEntries(sessionEntries);
|
|
117
|
+
// Record failed subagent outcomes
|
|
118
|
+
for (const entry of conversationEntries) {
|
|
119
|
+
if (entry.toolName === 'Agent' && entry.isError) {
|
|
120
|
+
try {
|
|
121
|
+
outcomeStorage.createOutcomeEvent({
|
|
122
|
+
event_type: 'agent_failure',
|
|
123
|
+
actor: 'tool',
|
|
124
|
+
action_summary: entry.text,
|
|
125
|
+
next_state_summary: entry.text,
|
|
126
|
+
tags: ['agent', 'subagent'],
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
catch { /* non-critical */ }
|
|
130
|
+
}
|
|
131
|
+
}
|
|
117
132
|
const extracted = await (0, event_processors_1.extractSessionLearnings)(conversationEntries, input?.session_id ?? '', projectId, 5);
|
|
118
133
|
if (extracted > 0) {
|
|
119
134
|
(0, shared_1.hookLog)('memory-stop', `Session extraction: stored ${extracted} learnings`);
|
|
@@ -417,7 +432,21 @@ function buildConversationEntries(entries) {
|
|
|
417
432
|
else {
|
|
418
433
|
const text = (0, shared_1.extractTextFromEntry)(entry);
|
|
419
434
|
if (text && text.length > 5) {
|
|
420
|
-
|
|
435
|
+
// Detect subagent task notifications
|
|
436
|
+
const notifMatch = text.match(/<task-notification>[\s\S]*?<\/task-notification>/);
|
|
437
|
+
if (notifMatch) {
|
|
438
|
+
const status = notifMatch[0].match(/<status>(.*?)<\/status>/)?.[1] ?? 'unknown';
|
|
439
|
+
const summary = notifMatch[0].match(/<summary>(.*?)<\/summary>/)?.[1] ?? '';
|
|
440
|
+
result.push({
|
|
441
|
+
role: 'tool_result',
|
|
442
|
+
text: `Agent ${status}: ${summary}`.substring(0, 300),
|
|
443
|
+
toolName: 'Agent',
|
|
444
|
+
isError: status === 'failed' || status === 'killed',
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
else {
|
|
448
|
+
result.push({ role: 'assistant', text: text.substring(0, 300) });
|
|
449
|
+
}
|
|
421
450
|
}
|
|
422
451
|
}
|
|
423
452
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* post-compact-reload hook — fires on SessionStart with source "compact".
|
|
4
|
+
*
|
|
5
|
+
* After context compaction, recall rules loaded earlier in the session are
|
|
6
|
+
* gone from the model's context. This hook re-injects them by outputting
|
|
7
|
+
* the active rules to stdout, which CC injects as a system message.
|
|
8
|
+
*
|
|
9
|
+
* Input: { session_id, hook_event_name: "SessionStart", source: "compact" }
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.handlePostCompactReload = handlePostCompactReload;
|
|
13
|
+
const shared_1 = require("./shared");
|
|
14
|
+
const memory_1 = require("../services/memory");
|
|
15
|
+
const config_1 = require("../services/config");
|
|
16
|
+
const DIRECTIVE = 'These rules were re-loaded after context compaction.\n' +
|
|
17
|
+
'Continue applying them. Cite at the point of application: (applied from memory: <rule>)';
|
|
18
|
+
function extractVal(value) {
|
|
19
|
+
if (typeof value === 'string')
|
|
20
|
+
return value;
|
|
21
|
+
if (typeof value === 'object' && value !== null) {
|
|
22
|
+
return value.content || value.value || JSON.stringify(value);
|
|
23
|
+
}
|
|
24
|
+
return String(value ?? '');
|
|
25
|
+
}
|
|
26
|
+
function formatRules(rules) {
|
|
27
|
+
const sections = [];
|
|
28
|
+
if (rules.preferences.length > 0) {
|
|
29
|
+
sections.push('## Preferences\n' + rules.preferences.map(m => `- ${extractVal(m.value)}`).join('\n'));
|
|
30
|
+
}
|
|
31
|
+
if (rules.corrections.length > 0) {
|
|
32
|
+
sections.push('## Corrections\n' + rules.corrections.map(m => `- ${extractVal(m.value)}`).join('\n'));
|
|
33
|
+
}
|
|
34
|
+
if (rules.failures.length > 0) {
|
|
35
|
+
sections.push('## Failures\n' + rules.failures.map(m => `- ${extractVal(m.value)}`).join('\n'));
|
|
36
|
+
}
|
|
37
|
+
if (rules.devops.length > 0) {
|
|
38
|
+
sections.push('## DevOps Rules\n' + rules.devops.map(m => `- ${extractVal(m.value)}`).join('\n'));
|
|
39
|
+
}
|
|
40
|
+
return sections.join('\n\n');
|
|
41
|
+
}
|
|
42
|
+
async function handlePostCompactReload(input) {
|
|
43
|
+
try {
|
|
44
|
+
const projectId = config_1.ConfigService.getInstance().getProjectId();
|
|
45
|
+
const rules = memory_1.MemoryService.getInstance().loadActiveRules(projectId);
|
|
46
|
+
const totalRules = rules.preferences.length + rules.corrections.length +
|
|
47
|
+
rules.failures.length + rules.devops.length;
|
|
48
|
+
if (totalRules === 0)
|
|
49
|
+
return;
|
|
50
|
+
const body = formatRules(rules);
|
|
51
|
+
console.log(`${DIRECTIVE}\n\n---\n\n${body}`);
|
|
52
|
+
(0, shared_1.hookLog)('post-compact-reload', `Re-injected ${totalRules} rules after compaction`);
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
(0, shared_1.hookLog)('post-compact-reload', `Error: ${err.message}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Claude Code Agent Harness — Architecture Reference
|
|
2
|
+
|
|
3
|
+
Reference notes on Claude Code's internal agent harness architecture, based on source code analysis (v1.0.x, March 2026). Useful for understanding integration points and designing Claude Recall features.
|
|
4
|
+
|
|
5
|
+
## Core Orchestration
|
|
6
|
+
|
|
7
|
+
**Query loop** — main while-loop that calls the API, executes tools, handles continuations, retries, and abort. Key behaviors:
|
|
8
|
+
- Infinite loop with explicit terminal conditions (end_turn, max_tokens, budget exceeded, turn limit)
|
|
9
|
+
- Pre-API hooks, post-sampling hooks, stop hooks at each stage
|
|
10
|
+
- Memory prefetch started non-blocking before API call
|
|
11
|
+
- Skill discovery prefetch in parallel with streaming
|
|
12
|
+
|
|
13
|
+
**Tool execution pipeline** — partitions tool calls into batches:
|
|
14
|
+
- Read-only tools (Read, Grep, Glob) run concurrently (max 10)
|
|
15
|
+
- Write tools (Bash, Edit, Write) run serially
|
|
16
|
+
- Each tool goes through: permission check → execute → yield result → apply context modifiers
|
|
17
|
+
- Tool result size budget enforced per turn
|
|
18
|
+
|
|
19
|
+
## Permission System
|
|
20
|
+
|
|
21
|
+
Three modes: `default` (interactive), `auto` (ML classifier), `bypass`.
|
|
22
|
+
|
|
23
|
+
Pipeline per tool call:
|
|
24
|
+
1. Rules-based check (always-allow/deny/ask lists)
|
|
25
|
+
2. Bash classifier (ML, 2s timeout for speculative decisions)
|
|
26
|
+
3. Hook execution (PreToolUse hooks)
|
|
27
|
+
4. Interactive UI prompt (if needed)
|
|
28
|
+
5. Decision persisted to ToolPermissionContext
|
|
29
|
+
|
|
30
|
+
Risk classification: LOW/MEDIUM/HIGH per tool action. Denial tracking state for threshold-based fallback.
|
|
31
|
+
|
|
32
|
+
## Multi-Agent
|
|
33
|
+
|
|
34
|
+
**Coordinator mode** — multi-agent orchestration with parallel worker phases and shared scratchpad.
|
|
35
|
+
|
|
36
|
+
**Agent tool** — forks subagents with inherited context:
|
|
37
|
+
- Child shares parent's prompt cache (byte-identical prefix = free context)
|
|
38
|
+
- Hard turn limit per agent
|
|
39
|
+
- Task notifications via XML: `<task-notification><status>completed</status>...</task-notification>`
|
|
40
|
+
- Agent types: worker (async), teammate (in-process, visible UI), fork (implicit context inheritance)
|
|
41
|
+
|
|
42
|
+
**Worker constraints:**
|
|
43
|
+
- SIMPLE mode: Bash, Read, Edit only
|
|
44
|
+
- Normal mode: full tool list including MCP
|
|
45
|
+
|
|
46
|
+
## State Management
|
|
47
|
+
|
|
48
|
+
**AppState** (Zustand store, 200+ fields):
|
|
49
|
+
- messages, tasks, agents, permissions, MCP clients, models, plugins, settings
|
|
50
|
+
- Observable via selectors
|
|
51
|
+
- Task registry: `{ [taskId]: TaskState }` with status tracking
|
|
52
|
+
|
|
53
|
+
**Task types:** local_bash, local_agent, remote_agent, in_process_teammate, local_workflow, monitor_mcp, dream
|
|
54
|
+
|
|
55
|
+
**Session persistence:** transcript JSONL written per session, resumable.
|
|
56
|
+
|
|
57
|
+
## Context Management / Compaction
|
|
58
|
+
|
|
59
|
+
Four compaction strategies (in order of aggressiveness):
|
|
60
|
+
1. **Microcompact** — cache-editing on every turn (efficient, preserves cache)
|
|
61
|
+
2. **Snip compact** — truncate oldest history (feature-gated)
|
|
62
|
+
3. **Context collapse** — deduplicate/compress (feature-gated)
|
|
63
|
+
4. **Autocompact** — full summarization when token threshold crossed
|
|
64
|
+
|
|
65
|
+
Token tracking: per-message estimates, cache creation/read tokens, danger zone threshold, cumulative budget.
|
|
66
|
+
|
|
67
|
+
Pre/post compact hooks fire at each stage.
|
|
68
|
+
|
|
69
|
+
## Safety & Guardrails
|
|
70
|
+
|
|
71
|
+
- Cyber risk instruction (defensive security, CTF rules)
|
|
72
|
+
- Secret scanner (gitleaks patterns, credential redaction)
|
|
73
|
+
- Path traversal prevention
|
|
74
|
+
- Command injection protection (fixed in security audit)
|
|
75
|
+
- Crypto: `crypto.randomUUID()` / `crypto.randomBytes()` throughout (no weak RNG)
|
|
76
|
+
|
|
77
|
+
## Memory System
|
|
78
|
+
|
|
79
|
+
**extractMemories** — forked sub-agent after each query loop:
|
|
80
|
+
- Reads last ~N messages, decides what to extract
|
|
81
|
+
- 5-turn budget, read-then-write strategy
|
|
82
|
+
- Mutual exclusivity: skips if main agent already wrote to memory
|
|
83
|
+
- Shares parent's prompt cache
|
|
84
|
+
|
|
85
|
+
**autoDream** — background consolidation:
|
|
86
|
+
- Three-gate trigger: 24h since last + 5 sessions + no parallel consolidation
|
|
87
|
+
- Four phases: orient → gather → consolidate → prune
|
|
88
|
+
- PID-based locking, 1h stale window
|
|
89
|
+
|
|
90
|
+
**Memory retrieval** — Sonnet sidequery selects up to 5 relevant memories per query from the memory directory.
|
|
91
|
+
|
|
92
|
+
## Integration Points for Claude Recall
|
|
93
|
+
|
|
94
|
+
### Currently Used
|
|
95
|
+
- PostToolUse / PostToolUseFailure hooks (tool outcome capture)
|
|
96
|
+
- UserPromptSubmit hook (correction detection)
|
|
97
|
+
- Stop hook (session-end processing)
|
|
98
|
+
- PreCompact hook (pre-compaction capture)
|
|
99
|
+
- MCP server (tool registration)
|
|
100
|
+
- Skills directory (behavioral guidance)
|
|
101
|
+
|
|
102
|
+
### Available but Unused
|
|
103
|
+
- Permission decision hooks (observe denied tools as learning signals)
|
|
104
|
+
- Task notification parsing (multi-agent session outcomes)
|
|
105
|
+
- Agent fork interception (inject memory context into subagents)
|
|
106
|
+
- Compaction triggers (pre-compact hooks with message access)
|
|
107
|
+
- Memory prefetch integration (inject recall results alongside native memory)
|
|
108
|
+
|
|
109
|
+
### Architectural Constraints
|
|
110
|
+
- Hooks run as external processes (no shared memory, no prompt cache)
|
|
111
|
+
- MCP tools are request-response (no streaming, no multi-turn)
|
|
112
|
+
- Cannot fork sub-agents from hooks
|
|
113
|
+
- Cannot modify the query loop or tool pipeline directly
|
|
114
|
+
- Feature flags (GrowthBook `tengu_*`) control many code paths — not accessible externally
|
package/package.json
CHANGED