Skip to content

Commit 413f373

Browse files
ArchieIndianclaude
andauthored
feat: add dag-recall skill — walk memory DAG to recall detailed context on demand (#42)
Queries the hierarchical summary DAG built by memory-dag-compactor, expands matches from high-level to detailed nodes, and assembles cited answers. Includes FTS5 search, LRU cache, ancestor tracing, and token budget control. Inspired by lossless-claw's sub-agent recall pattern. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 6cfc4c8 commit 413f373

4 files changed

Lines changed: 824 additions & 0 deletions

File tree

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
---
2+
name: dag-recall
3+
version: "1.0"
4+
category: openclaw-native
5+
description: Walks the memory DAG to recall detailed context on demand — query, expand, and assemble cited answers from hierarchical summaries without re-reading raw transcripts.
6+
stateful: true
7+
---
8+
9+
# DAG Recall
10+
11+
## What it does
12+
13+
When the agent needs to recall something from past sessions, reading raw transcripts is expensive and often exceeds context limits. DAG Recall walks the hierarchical summary DAG built by memory-dag-compactor — starting from high-level (d2/d3) nodes, expanding into detailed (d0/d1) children — and assembles a focused, cited answer.
14+
15+
Inspired by [lossless-claw](https://github.com/Martian-Engineering/lossless-claw)'s sub-agent recall pattern, where a lightweight agent fetches and expands nodes on demand rather than loading entire conversation histories.
16+
17+
## When to invoke
18+
19+
- When the agent asks "what did we decide about X?" or "how did we implement Y?"
20+
- When context about a past session is needed but the transcript isn't loaded
21+
- When searching MEMORY.md returns only high-level summaries that need expansion
22+
- Before starting work that depends on decisions or patterns from earlier sessions
23+
24+
## How to use
25+
26+
```bash
27+
python3 recall.py --query "how did we handle auth migration" # Walk DAG + assemble answer
28+
python3 recall.py --query "deploy process" --depth 2 # Limit expansion depth
29+
python3 recall.py --query "API keys" --top 5 # Return top 5 matching nodes
30+
python3 recall.py --expand s-d1-003 # Expand a specific node
31+
python3 recall.py --trace s-d0-012 # Show full ancestor chain
32+
python3 recall.py --recent --hours 48 # Recall from recent nodes only
33+
python3 recall.py --status # Last recall summary
34+
python3 recall.py --format json # Machine-readable output
35+
```
36+
37+
## Recall algorithm
38+
39+
1. **Search** — FTS5 query across all DAG node summaries
40+
2. **Rank** — Score by relevance × recency × depth (deeper = more detailed = higher score for recall)
41+
3. **Expand** — For each top-N match, walk to children (lower depth = more detail)
42+
4. **Assemble** — Combine expanded content into a coherent answer with node citations
43+
5. **Cache** — Store the assembled answer for fast re-retrieval
44+
45+
### Expansion strategy
46+
47+
```
48+
Query: "auth migration"
49+
50+
d3 node: "Infrastructure & Auth overhaul Q1" (score: 0.72)
51+
→ expand d2: "Auth migration week of Feb 10" (score: 0.89)
52+
→ expand d1: "Migrated JWT signing from HS256 to RS256" (score: 0.95)
53+
→ expand d0: [raw operational detail — returned as-is]
54+
```
55+
56+
Expansion stops when:
57+
- Target depth reached (default: expand to d0)
58+
- Token budget exhausted (default: 4000 tokens)
59+
- No children exist (leaf node)
60+
61+
## DAG structure expected
62+
63+
Reads from `~/.openclaw/lcm-dag/` (same directory as memory-dag-compactor):
64+
65+
```
66+
~/.openclaw/lcm-dag/
67+
├── index.json # Node metadata: id, depth, summary, children, created_at
68+
├── nodes/
69+
│ ├── s-d0-001.md # Leaf node (operational detail)
70+
│ ├── s-d1-001.md # Condensed summary
71+
│ ├── s-d2-001.md # Arc summary
72+
│ └── s-d3-001.md # Durable summary
73+
└── fts.db # FTS5 index over node summaries
74+
```
75+
76+
## Procedure
77+
78+
**Step 1 — Query the DAG**
79+
80+
```bash
81+
python3 recall.py --query "how did we handle the database migration"
82+
```
83+
84+
Searches the FTS5 index, ranks results, expands top matches, and assembles a cited answer:
85+
86+
```
87+
Recall: "how did we handle the database migration" — 3 sources
88+
89+
We migrated the database schema using Alembic with a blue-green
90+
deployment strategy. The key decisions were:
91+
92+
1. Zero-downtime migration using shadow tables [s-d1-003]
93+
2. Rollback script tested against staging first [s-d0-012]
94+
3. Data backfill ran as async job over 2 hours [s-d0-015]
95+
96+
Sources:
97+
[s-d1-003] "Database migration — shadow table approach" (Feb 12)
98+
[s-d0-012] "Alembic rollback script for users table" (Feb 12)
99+
[s-d0-015] "Async backfill job for legacy records" (Feb 13)
100+
```
101+
102+
**Step 2 — Expand a specific node**
103+
104+
```bash
105+
python3 recall.py --expand s-d1-003
106+
```
107+
108+
Shows the full content of a node and lists its children for further expansion.
109+
110+
**Step 3 — Trace lineage**
111+
112+
```bash
113+
python3 recall.py --trace s-d0-012
114+
```
115+
116+
Shows the full ancestor chain from leaf to root, revealing how detail connects to high-level themes.
117+
118+
## Integration with other skills
119+
120+
- **memory-dag-compactor**: Produces the DAG that this skill reads — must be run first
121+
- **session-persistence**: Alternative data source — recall can fall back to SQLite search when DAG nodes are insufficient
122+
- **context-assembly-scorer**: Recall results feed into context assembly scoring
123+
- **memory-integrity-checker**: Ensures DAG is structurally sound before recall walks it
124+
125+
## State
126+
127+
Recall history and cache stored in `~/.openclaw/skill-state/dag-recall/state.yaml`.
128+
129+
Fields: `last_query`, `last_query_at`, `cache_size`, `total_recalls`, `recall_history`.
130+
131+
## Notes
132+
133+
- Uses Python's built-in `sqlite3` and `json` modules — no external dependencies
134+
- FTS5 used for search when available; falls back to substring matching
135+
- Token budget prevents runaway expansion on large DAGs
136+
- Cache is LRU with configurable max size (default: 50 entries)
137+
- If DAG doesn't exist yet, prints a helpful message pointing to memory-dag-compactor
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
version: "1.0"
2+
description: Recall query history, cache stats, and expansion tracking.
3+
fields:
4+
last_query:
5+
type: string
6+
description: Most recent recall query text
7+
last_query_at:
8+
type: datetime
9+
cache_size:
10+
type: integer
11+
description: Number of cached recall results
12+
total_recalls:
13+
type: integer
14+
description: Lifetime recall count
15+
avg_sources_per_recall:
16+
type: number
17+
description: Average number of DAG nodes cited per recall
18+
recall_history:
19+
type: list
20+
description: Rolling log of recent recalls (last 20)
21+
items:
22+
query: { type: string }
23+
recalled_at: { type: datetime }
24+
sources_used: { type: integer }
25+
tokens_assembled: { type: integer }
26+
cache_hit: { type: boolean }
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Example runtime state for dag-recall
2+
last_query: "how did we handle the auth migration"
3+
last_query_at: "2026-03-16T10:32:15.000000"
4+
cache_size: 12
5+
total_recalls: 47
6+
avg_sources_per_recall: 3.2
7+
recall_history:
8+
- query: "how did we handle the auth migration"
9+
recalled_at: "2026-03-16T10:32:15.000000"
10+
sources_used: 4
11+
tokens_assembled: 1820
12+
cache_hit: false
13+
- query: "deploy process"
14+
recalled_at: "2026-03-16T09:15:03.000000"
15+
sources_used: 3
16+
tokens_assembled: 1240
17+
cache_hit: false
18+
- query: "deploy process"
19+
recalled_at: "2026-03-16T09:45:22.000000"
20+
sources_used: 3
21+
tokens_assembled: 1240
22+
cache_hit: true
23+
# ── Walkthrough ──────────────────────────────────────────────────────────────
24+
# python3 recall.py --query "how did we handle the auth migration"
25+
#
26+
# Recall: "how did we handle the auth migration" — 4 sources
27+
#
28+
# [s-d1-003] (summary) Migrated JWT signing from HS256 to RS256
29+
# with key rotation plan...
30+
# [s-d0-012] (detail) Created migration script for auth_keys table...
31+
# [s-d0-015] (detail) Updated environment variables for RS256 public...
32+
# [s-d0-018] (detail) Added rollback procedure in deploy/auth-rollback.sh...
33+
#
34+
# Sources:
35+
# [s-d1-003] "Migrated JWT signing from HS256 to RS2..." (2026-02-10)
36+
# [s-d0-012] "Created migration script for auth_keys..." (2026-02-10)
37+
# [s-d0-015] "Updated environment variables for RS25..." (2026-02-11)
38+
# [s-d0-018] "Added rollback procedure in deploy/aut..." (2026-02-11)
39+
#
40+
# python3 recall.py --trace s-d0-012
41+
#
42+
# Trace: s-d0-012 → root (3 nodes)
43+
#
44+
# s-d0-012 (d0 — detail)
45+
# Created migration script for auth_keys table
46+
# Created: 2026-02-10
47+
# └── s-d1-003 (d1 — summary)
48+
# JWT signing migration HS256 → RS256
49+
# Created: 2026-02-10
50+
# └── s-d2-001 (d2 — arc)
51+
# Auth & Infrastructure overhaul Feb 2026
52+
# Created: 2026-02-14
53+
#
54+
# python3 recall.py --status
55+
#
56+
# DAG Recall Status
57+
# ──────────────────────────────────────────────────
58+
# Last query: how did we handle the auth migration
59+
# Last query at: 2026-03-16T10:32:15.000000
60+
# Total recalls: 47
61+
# Cache size: 12 / 50
62+
# DAG nodes: 24

0 commit comments

Comments
 (0)