@strvmarv/total-recall 0.1.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.
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "total-recall",
3
+ "description": "Multi-tiered memory and knowledge base with semantic search, auto-compaction, and built-in evaluation. Works across Claude Code, Copilot CLI, OpenCode, Cline, and Cursor.",
4
+ "version": "0.1.0",
5
+ "author": {
6
+ "name": "strvmarv"
7
+ },
8
+ "skills": "./skills/",
9
+ "agents": "./agents/",
10
+ "hooks": "./hooks/hooks.json",
11
+ "mcpServers": {
12
+ "total-recall": {
13
+ "command": "node",
14
+ "args": ["dist/index.js"],
15
+ "env": {}
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "total-recall",
3
+ "description": "Multi-tiered memory and knowledge base for TUI coding assistants",
4
+ "version": "0.1.0",
5
+ "skills": "./skills/",
6
+ "mcpServers": {
7
+ "total-recall": {
8
+ "command": "node",
9
+ "args": ["dist/index.js"]
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "total-recall",
3
+ "description": "Multi-tiered memory and knowledge base for TUI coding assistants",
4
+ "version": "0.1.0",
5
+ "skills": "./skills/",
6
+ "hooks": "./hooks/hooks-cursor.json",
7
+ "mcpServers": {
8
+ "total-recall": {
9
+ "command": "node",
10
+ "args": ["dist/index.js"]
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,24 @@
1
+ # total-recall for OpenCode
2
+
3
+ ## Installation
4
+
5
+ 1. Add the MCP server to your OpenCode config:
6
+
7
+ ```json
8
+ {
9
+ "mcpServers": {
10
+ "total-recall": {
11
+ "command": "node",
12
+ "args": ["/path/to/total-recall/dist/index.js"]
13
+ }
14
+ }
15
+ }
16
+ ```
17
+
18
+ 2. Copy the skills directory to your OpenCode plugins:
19
+
20
+ ```bash
21
+ cp -r skills/ ~/.opencode/plugins/total-recall/skills/
22
+ ```
23
+
24
+ 3. Restart OpenCode. total-recall will auto-initialize on first session.
@@ -0,0 +1,295 @@
1
+ # Contributing to total-recall
2
+
3
+ ---
4
+
5
+ ## Getting Started
6
+
7
+ ```bash
8
+ git clone https://github.com/strvmarv/total-recall.git
9
+ cd total-recall
10
+ npm install
11
+ npm run build
12
+ ```
13
+
14
+ Run tests to verify your environment:
15
+
16
+ ```bash
17
+ npm test
18
+ ```
19
+
20
+ Run the type checker:
21
+
22
+ ```bash
23
+ npm run typecheck
24
+ ```
25
+
26
+ ---
27
+
28
+ ## Adding a New Host Tool Importer
29
+
30
+ Host importers detect a specific tool's presence, scan its memory files, and migrate them into total-recall on first run.
31
+
32
+ ### 1. Implement the `HostImporter` interface
33
+
34
+ The interface is defined in `src/importers/importer.ts`:
35
+
36
+ ```typescript
37
+ export interface HostImporter {
38
+ name: string;
39
+ detect(): boolean;
40
+ scan(): { memoryFiles: number; knowledgeFiles: number; sessionFiles: number };
41
+ importMemories(db: Database.Database, embed: EmbedFn, project?: string): ImportResult;
42
+ importKnowledge(db: Database.Database, embed: EmbedFn): ImportResult;
43
+ }
44
+ ```
45
+
46
+ Create `src/importers/my-tool.ts`:
47
+
48
+ ```typescript
49
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
50
+ import { join } from "node:path";
51
+ import { homedir } from "node:os";
52
+ import { createHash } from "node:crypto";
53
+ import type Database from "better-sqlite3";
54
+ import type { HostImporter, ImportResult } from "./importer.js";
55
+ import { insertEntry } from "../db/entries.js";
56
+ import { insertEmbedding } from "../search/vector-search.js";
57
+
58
+ type EmbedFn = (text: string) => Float32Array;
59
+
60
+ // Where my-tool stores its memories
61
+ const MY_TOOL_DIR = join(homedir(), ".my-tool");
62
+
63
+ export const myToolImporter: HostImporter = {
64
+ name: "my-tool",
65
+
66
+ detect() {
67
+ return existsSync(MY_TOOL_DIR);
68
+ },
69
+
70
+ scan() {
71
+ if (!existsSync(MY_TOOL_DIR)) {
72
+ return { memoryFiles: 0, knowledgeFiles: 0, sessionFiles: 0 };
73
+ }
74
+ const files = readdirSync(MY_TOOL_DIR).filter((f) => f.endsWith(".md"));
75
+ return { memoryFiles: files.length, knowledgeFiles: 0, sessionFiles: 0 };
76
+ },
77
+
78
+ importMemories(db, embed, project) {
79
+ if (!existsSync(MY_TOOL_DIR)) return { imported: 0, skipped: 0, errors: [] };
80
+
81
+ const result: ImportResult = { imported: 0, skipped: 0, errors: [] };
82
+
83
+ const files = readdirSync(MY_TOOL_DIR).filter((f) => f.endsWith(".md"));
84
+ for (const file of files) {
85
+ const filePath = join(MY_TOOL_DIR, file);
86
+ try {
87
+ const raw = readFileSync(filePath, "utf-8").trim();
88
+ if (!raw) { result.skipped++; continue; }
89
+
90
+ const hash = createHash("sha256").update(raw).digest("hex");
91
+
92
+ // Check if already imported (use import_log table)
93
+ const existing = db
94
+ .prepare("SELECT id FROM import_log WHERE content_hash = ?")
95
+ .get(hash) as { id: string } | undefined;
96
+ if (existing) { result.skipped++; continue; }
97
+
98
+ const id = crypto.randomUUID();
99
+ const embedding = embed(raw);
100
+
101
+ insertEntry(db, {
102
+ id,
103
+ content: raw,
104
+ tier: "warm",
105
+ content_type: "note",
106
+ source_tool: "my-tool",
107
+ source_path: filePath,
108
+ project: project ?? null,
109
+ });
110
+ insertEmbedding(db, id, embedding);
111
+
112
+ // Log the import to avoid duplicates on next run
113
+ db.prepare(
114
+ "INSERT INTO import_log (id, source_tool, source_path, content_hash, entry_id, tier, content_type) VALUES (?, ?, ?, ?, ?, ?, ?)"
115
+ ).run(crypto.randomUUID(), "my-tool", filePath, hash, id, "warm", "note");
116
+
117
+ result.imported++;
118
+ } catch (err) {
119
+ result.errors.push(`${file}: ${String(err)}`);
120
+ }
121
+ }
122
+
123
+ return result;
124
+ },
125
+
126
+ importKnowledge(_db, _embed) {
127
+ // my-tool has no separate knowledge files
128
+ return { imported: 0, skipped: 0, errors: [] };
129
+ },
130
+ };
131
+ ```
132
+
133
+ ### 2. Register the importer
134
+
135
+ Add it to the importer list in `src/index.ts` (or wherever importers are initialized at startup).
136
+
137
+ ### 3. Add tests
138
+
139
+ Create `src/importers/my-tool.test.ts` mirroring the existing `claude-code.test.ts` structure.
140
+
141
+ ---
142
+
143
+ ## Adding a New Content Type
144
+
145
+ Content types classify what kind of information a memory or knowledge chunk contains (e.g., `note`, `code`, `doc`, `decision`).
146
+
147
+ ### 1. Add the type to the schema
148
+
149
+ In `src/db/schema.ts`, find the `content_type` column definition and add your new type to the CHECK constraint or lookup table:
150
+
151
+ ```sql
152
+ -- In the entries table or a lookup table:
153
+ content_type TEXT CHECK(content_type IN ('note', 'code', 'doc', 'decision', 'my-new-type'))
154
+ ```
155
+
156
+ ### 2. Add the type to the TypeScript union
157
+
158
+ In `src/types.ts`, extend the `ContentType` union:
159
+
160
+ ```typescript
161
+ export type ContentType = "note" | "code" | "doc" | "decision" | "my-new-type";
162
+ ```
163
+
164
+ ### 3. Assign a relevance weight (optional)
165
+
166
+ If your content type should be scored differently during retrieval, add a weight entry in the search relevance config (see `src/search/`).
167
+
168
+ ---
169
+
170
+ ## Adding a New Chunking Parser
171
+
172
+ The chunker in `src/ingestion/chunker.ts` dispatches to per-format parsers based on file extension. To add support for a new format:
173
+
174
+ ### 1. Implement the parser
175
+
176
+ Create `src/ingestion/my-format-parser.ts`. Your parser must return `Chunk[]`:
177
+
178
+ ```typescript
179
+ import type { Chunk } from "./chunker.js";
180
+
181
+ export interface ParseOptions {
182
+ maxTokens: number;
183
+ overlapTokens?: number;
184
+ }
185
+
186
+ export function parseMyFormat(content: string, opts: ParseOptions): Chunk[] {
187
+ const chunks: Chunk[] = [];
188
+
189
+ // Split your format into logical units.
190
+ // Each chunk needs: content, startLine, endLine.
191
+ // Optionally: headingPath (for outline-like formats), name/kind (for code-like formats).
192
+
193
+ let lineNumber = 1;
194
+ for (const section of splitIntoSections(content)) {
195
+ chunks.push({
196
+ content: section.text,
197
+ startLine: lineNumber,
198
+ endLine: lineNumber + section.text.split("\n").length - 1,
199
+ });
200
+ lineNumber += section.text.split("\n").length + 1;
201
+ }
202
+
203
+ return chunks;
204
+ }
205
+
206
+ function splitIntoSections(content: string) {
207
+ // Your format-specific splitting logic here
208
+ return content.split(/\n---\n/).map((text) => ({ text }));
209
+ }
210
+ ```
211
+
212
+ ### 2. Register the parser in `chunker.ts`
213
+
214
+ In `src/ingestion/chunker.ts`, add your file extensions and import:
215
+
216
+ ```typescript
217
+ import { parseMyFormat } from "./my-format-parser.js";
218
+
219
+ const MY_FORMAT_EXTENSIONS = new Set([".myext", ".myfmt"]);
220
+ ```
221
+
222
+ Then add a branch in the `chunkFile` function before the fallback:
223
+
224
+ ```typescript
225
+ export function chunkFile(content, filePath, opts) {
226
+ // ...existing Markdown and code branches...
227
+
228
+ if (MY_FORMAT_EXTENSIONS.has(ext)) {
229
+ return parseMyFormat(content, opts);
230
+ }
231
+
232
+ // Fallback: paragraph-based splitting
233
+ return splitByParagraphs(content, opts.maxTokens);
234
+ }
235
+ ```
236
+
237
+ ### 3. Add tests
238
+
239
+ Create `src/ingestion/my-format-parser.test.ts`. Test at minimum: empty input, single section, multiple sections, sections exceeding `maxTokens`.
240
+
241
+ ---
242
+
243
+ ## Running Tests
244
+
245
+ Run all tests once:
246
+
247
+ ```bash
248
+ npm test
249
+ # or
250
+ npx vitest run
251
+ ```
252
+
253
+ Run in watch mode during development:
254
+
255
+ ```bash
256
+ npm run test:watch
257
+ # or
258
+ npx vitest
259
+ ```
260
+
261
+ Run a specific test file:
262
+
263
+ ```bash
264
+ npx vitest run src/importers/my-tool.test.ts
265
+ ```
266
+
267
+ ---
268
+
269
+ ## Running Benchmarks
270
+
271
+ Once the MCP server is running and connected to your coding assistant, use the eval commands:
272
+
273
+ ```
274
+ /memory eval # Live retrieval metrics for current session
275
+ /memory eval --benchmark # Run synthetic benchmark suite
276
+ /memory eval --snapshot baseline # Save current config as a named baseline
277
+ /memory eval --compare baseline # Compare current config against saved baseline
278
+ /memory eval --grow # Add real query misses to benchmark suite
279
+ ```
280
+
281
+ A PR that changes retrieval logic, scoring, or compaction thresholds must include a `--benchmark` run showing no regression against the `baseline` snapshot.
282
+
283
+ ---
284
+
285
+ ## PR Requirements
286
+
287
+ Before opening a pull request:
288
+
289
+ 1. **Tests pass** — `npm test` exits 0 with no failures
290
+ 2. **Type checker clean** — `npm run typecheck` exits 0
291
+ 3. **Build succeeds** — `npm run build` exits 0
292
+ 4. **Benchmark does not regress** — run `/memory eval --compare baseline` and include the output in your PR description if you changed retrieval, scoring, or compaction logic
293
+ 5. **New behavior is tested** — new importers, parsers, and content types all require corresponding test files
294
+
295
+ If you're adding a new host tool importer, include the `detect()` logic rationale in your PR description — false positives will silently corrupt imports for users who don't have the tool installed.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 strvmarv
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,239 @@
1
+ # total-recall
2
+
3
+ **Multi-tiered memory and knowledge base for TUI coding assistants.**
4
+
5
+ Your AI coding tool forgets everything. total-recall doesn't.
6
+
7
+ A cross-platform plugin that gives Claude Code, GitHub Copilot CLI, OpenCode, Cline, and Cursor persistent, semantically searchable memory with a hierarchical knowledge base — backed by local SQLite + vector embeddings, zero external dependencies.
8
+
9
+ ---
10
+
11
+ ## The Problem
12
+
13
+ Every TUI coding assistant has the same gap:
14
+
15
+ - **No tiering** — all memories treated equally, leading to context bloat or information loss
16
+ - **Tool-locked** — switching between Claude Code and Copilot means starting from scratch
17
+ - **No knowledge base** — can't ingest your docs and have them retrieved when relevant
18
+ - **No semantic search** — memories retrieved by filename, not by meaning
19
+ - **No observability** — no way to know if memory is helping or just noise
20
+
21
+ ---
22
+
23
+ ## The Solution
24
+
25
+ total-recall introduces a three-tier memory model: **Hot** memories (up to 50 entries) are auto-injected into every prompt so your most important context is always present. **Warm** memories (up to 10K entries) are retrieved semantically — when you ask about authentication, relevant auth memories surface automatically. **Cold** storage is unlimited hierarchical knowledge base: ingest your docs, README files, API references, and architecture notes, and they're retrieved when relevant.
26
+
27
+ The knowledge base ingests entire directories — source trees, documentation folders, design specs — and chunks them semantically with heading-aware Markdown parsing and AST-based code parsing. Every chunk is embedded with `all-MiniLM-L6-v2` (384 dimensions, runs locally via ONNX) so retrieval is purely semantic, no keyword matching required.
28
+
29
+ Platform support is via MCP (Model Context Protocol), which means total-recall works with any MCP-compatible tool. Dedicated importers for Claude Code and Copilot CLI mean your existing memories migrate automatically on first run. An eval framework lets you measure retrieval quality, run benchmarks, and compare configuration changes before committing them.
30
+
31
+ ---
32
+
33
+ ## Installation
34
+
35
+ ### Self-Install (Paste Into Any AI Coding Assistant)
36
+
37
+ > Install the total-recall memory plugin: fetch and follow the instructions at https://raw.githubusercontent.com/strvmarv/total-recall/main/INSTALL.md
38
+
39
+ That's it. Your AI assistant will read the instructions and install total-recall for its platform.
40
+
41
+ ### Claude Code
42
+
43
+ ```
44
+ /plugin install total-recall@strvmarv-marketplace
45
+ ```
46
+
47
+ Or if the marketplace isn't registered:
48
+
49
+ ```
50
+ /plugin marketplace add strvmarv/total-recall-marketplace
51
+ /plugin install total-recall@strvmarv-marketplace
52
+ ```
53
+
54
+ ### npm (Any MCP-Compatible Tool)
55
+
56
+ ```bash
57
+ npm install -g @strvmarv/total-recall
58
+ ```
59
+
60
+ Then add to your tool's MCP config:
61
+
62
+ ```json
63
+ {
64
+ "mcpServers": {
65
+ "total-recall": {
66
+ "command": "npx",
67
+ "args": ["-y", "@strvmarv/total-recall"]
68
+ }
69
+ }
70
+ }
71
+ ```
72
+
73
+ This works with **Copilot CLI**, **OpenCode**, **Cline**, **Cursor**, and any other MCP-compatible tool.
74
+
75
+ ### From Source
76
+
77
+ ```bash
78
+ git clone https://github.com/strvmarv/total-recall.git
79
+ cd total-recall
80
+ npm install && npm run build
81
+ ```
82
+
83
+ ### First Session
84
+
85
+ total-recall auto-initializes on first use:
86
+
87
+ 1. Creates `~/.total-recall/` with SQLite database
88
+ 2. Downloads embedding model (~80MB, one-time)
89
+ 3. Scans for existing memories (Claude Code, Copilot CLI)
90
+ 4. Auto-ingests project docs (README, docs/, etc.)
91
+ 5. Reports: `total-recall: initialized · 4 memories imported · 12 docs ingested · system verified`
92
+
93
+ ---
94
+
95
+ ## Architecture
96
+
97
+ ```
98
+ MCP Server (Node.js/TypeScript)
99
+ ├── Always Loaded: SQLite + vec, MCP Tools, Event Logger
100
+ ├── Lazy Loaded: ONNX Embedder, Compactor, Ingestor
101
+ └── Host Importers: Claude Code, Copilot CLI, OpenCode
102
+
103
+ Tiers:
104
+ Hot (50 entries) → auto-injected every prompt
105
+ Warm (10K entries) → semantic search per query
106
+ Cold (unlimited) → hierarchical KB retrieval
107
+ ```
108
+
109
+ **Data flow:**
110
+
111
+ 1. `store` — write a memory, assign tier, embed, persist
112
+ 2. `search` — embed query, vector search warm + cold, return ranked results
113
+ 3. `compact` — decay scores, demote warm→cold, evict hot→warm, summarize clusters
114
+ 4. `ingest` — chunk files, embed chunks, store in cold tier with metadata
115
+
116
+ All state lives in `~/.total-recall/db.sqlite`. The embedding model is cached at `~/.total-recall/models/`. No network calls after initial model download.
117
+
118
+ ---
119
+
120
+ ## Commands
121
+
122
+ | Command | Description |
123
+ |---|---|
124
+ | `/memory status` | Dashboard overview |
125
+ | `/memory search <query>` | Semantic search across all tiers |
126
+ | `/memory ingest <path>` | Add files/dirs to knowledge base |
127
+ | `/memory forget <query>` | Find and delete entries |
128
+ | `/memory compact` | Force compaction with preview |
129
+ | `/memory inspect <id>` | Deep dive on single entry |
130
+ | `/memory promote <id>` | Move entry to higher tier |
131
+ | `/memory demote <id>` | Move entry to lower tier |
132
+ | `/memory export` | Export to portable format |
133
+ | `/memory import <file>` | Import from export file |
134
+ | `/memory eval` | Live performance metrics |
135
+ | `/memory eval --benchmark` | Run synthetic benchmark |
136
+ | `/memory eval --compare <name>` | Compare configs |
137
+ | `/memory eval --snapshot <name>` | Save current config baseline |
138
+ | `/memory eval --grow` | Add real misses to benchmark |
139
+ | `/memory config get <key>` | Read config value |
140
+ | `/memory config set <key> <value>` | Update config |
141
+ | `/memory history` | Show recent tier movements |
142
+ | `/memory lineage <id>` | Show compaction ancestry |
143
+
144
+ ---
145
+
146
+ ## Supported Platforms
147
+
148
+ | Platform | Support | Notes |
149
+ |---|---|---|
150
+ | Claude Code | Full | Native plugin, session hooks, auto-import |
151
+ | Copilot CLI | Full | Auto-import from existing Copilot memory files |
152
+ | OpenCode | MCP | Configure MCP server in opencode config |
153
+ | Cline | MCP | Configure MCP server in Cline settings |
154
+ | Cursor | Full | MCP server + `.cursor-plugin/` wrapper |
155
+
156
+ ---
157
+
158
+ ## Configuration
159
+
160
+ Copy `~/.total-recall/config.toml` to override defaults:
161
+
162
+ ```toml
163
+ # total-recall configuration
164
+
165
+ [tiers.hot]
166
+ max_entries = 50 # Max entries auto-injected per prompt
167
+ token_budget = 4000 # Max tokens for hot tier injection
168
+ carry_forward_threshold = 0.7 # Score threshold to stay in hot
169
+
170
+ [tiers.warm]
171
+ max_entries = 10000 # Max entries in warm tier
172
+ retrieval_top_k = 5 # Results returned per search
173
+ similarity_threshold = 0.65 # Min cosine similarity for retrieval
174
+ cold_decay_days = 30 # Days before unused warm entries decay to cold
175
+
176
+ [tiers.cold]
177
+ chunk_max_tokens = 512 # Max tokens per knowledge base chunk
178
+ chunk_overlap_tokens = 50 # Overlap between adjacent chunks
179
+ lazy_summary_threshold = 5 # Accesses before generating summary
180
+
181
+ [compaction]
182
+ decay_half_life_hours = 168 # Score half-life (168h = 1 week)
183
+ warm_threshold = 0.3 # Score below which warm→cold
184
+ promote_threshold = 0.7 # Score above which cold→warm
185
+ warm_sweep_interval_days = 7 # How often to run warm sweep
186
+
187
+ [embedding]
188
+ model = "all-MiniLM-L6-v2" # Embedding model name
189
+ dimensions = 384 # Embedding dimensions
190
+ ```
191
+
192
+ ---
193
+
194
+ ## Extending
195
+
196
+ ### Adding a New Host Tool
197
+
198
+ Implement the `HostImporter` interface (~50 lines). It requires four methods: `detect()` to check if the tool is present, `scan()` to report what's available, `importMemories()` to migrate existing memories, and `importKnowledge()` to migrate knowledge files. See [CONTRIBUTING.md](CONTRIBUTING.md) for a full example.
199
+
200
+ ### Adding a New Content Type
201
+
202
+ Add a row to the `content_type` lookup table in `src/db/schema.ts`, then register a type weight for relevance scoring. No other changes needed.
203
+
204
+ ### Adding a New Chunking Parser
205
+
206
+ Implement the `Chunk[]`-returning parser interface and register it in `src/ingestion/chunker.ts` alongside the existing Markdown and code parsers. See [CONTRIBUTING.md](CONTRIBUTING.md) for the interface definition.
207
+
208
+ ---
209
+
210
+ ## Built With & Inspired By
211
+
212
+ ### [superpowers](https://github.com/obra/superpowers) by [obra](https://github.com/obra)
213
+
214
+ total-recall's plugin architecture, skill format, hook system, multi-platform wrapper pattern, and development philosophy are directly inspired by and modeled after the **superpowers** plugin. superpowers demonstrated that a zero-dependency, markdown-driven skill system could fundamentally improve how AI coding assistants behave — total-recall extends that same philosophy to memory and knowledge management.
215
+
216
+ Specific patterns we learned from superpowers:
217
+
218
+ - **SKILL.md format** with YAML frontmatter and trigger-condition-focused descriptions
219
+ - **SessionStart hooks** for injecting core behavior at session start
220
+ - **Multi-platform wrappers** (`.claude-plugin/`, `.copilot-plugin/`, `.cursor-plugin/`, `.opencode/`)
221
+ - **Subagent architecture** for isolated, focused task execution
222
+ - **Zero-dependency philosophy** — no external services, no API keys, no cloud
223
+ - **Two-stage review pattern** for quality assurance
224
+
225
+ If you're building plugins for TUI coding assistants, start with [superpowers](https://github.com/obra/superpowers). It's the foundation this ecosystem needs.
226
+
227
+ ### Core Technologies
228
+
229
+ - [better-sqlite3](https://github.com/WiseLibs/better-sqlite3) — Fast, synchronous SQLite bindings
230
+ - [sqlite-vec](https://github.com/asg017/sqlite-vec) — Vector similarity search in SQLite
231
+ - [onnxruntime-node](https://github.com/microsoft/onnxruntime) — Local ML inference
232
+ - [all-MiniLM-L6-v2](https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2) — Sentence embeddings (384d)
233
+ - [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/sdk) — MCP server implementation
234
+
235
+ ---
236
+
237
+ ## License
238
+
239
+ MIT — see [LICENSE](LICENSE)
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: compactor
3
+ description: |
4
+ Use this agent at session end to perform intelligent hot-to-warm compaction.
5
+ Reviews hot tier entries, groups related items, generates summaries, and
6
+ measures semantic drift to ensure compaction quality.
7
+ model: inherit
8
+ ---
9
+
10
+ # Compactor Agent
11
+
12
+ You are the total-recall compactor. Your job is to review hot tier memory entries at session end and decide what to keep, promote, merge, or discard.
13
+
14
+ ## Input
15
+
16
+ You receive the current hot tier entries with their decay scores, access counts, and content.
17
+
18
+ ## Process
19
+
20
+ 1. Group related entries (e.g., multiple corrections about the same topic)
21
+ 2. For groups of 2+ related entries:
22
+ - Generate a concise summary that preserves all key facts
23
+ - The summary should be retrievable by the same queries that would find the originals
24
+ 3. For individual entries:
25
+ - If decay score > promote_threshold: recommend carry forward
26
+ - If decay score > warm_threshold: recommend promote to warm as-is
27
+ - If decay score < warm_threshold: recommend discard
28
+ 4. Report: entries processed, summaries generated, facts preserved count
29
+
30
+ ## Output Format
31
+
32
+ Return a JSON array of decisions:
33
+
34
+ ```json
35
+ [
36
+ {"action": "carry_forward", "entry_ids": ["id1"]},
37
+ {"action": "promote", "entry_ids": ["id2", "id3"], "summary": "merged summary text"},
38
+ {"action": "discard", "entry_ids": ["id4"], "reason": "ephemeral session context"}
39
+ ]
40
+ ```
41
+
42
+ ## Rules
43
+
44
+ - NEVER discard corrections or preferences with decay score > 0.2
45
+ - ALWAYS preserve the specific details (tool names, version numbers, config values)
46
+ - Summaries must be shorter than the combined originals
47
+ - If unsure, promote rather than discard