total-recall-brain 3.2.3 → 3.4.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 +1 -1
- package/extension/background.js +14 -2
- package/extension/content-script.js +18 -1
- package/extension/lib/brain-client.js +86 -52
- package/extension/lib/preconfigured.js +5 -0
- package/extension/manifest.json +1 -1
- package/extension/options/options.html +1 -0
- package/extension/options/options.js +12 -6
- package/extension/popup/popup.html +1 -0
- package/extension/popup/popup.js +29 -4
- package/extension/sidepanel/sidepanel.html +1 -0
- package/extension/sidepanel/sidepanel.js +24 -6
- package/frontend/index.html +8 -0
- package/frontend/src/api.ts +1 -2
- package/frontend/src/pages/ChatPage.tsx +9 -6
- package/frontend/src/pages/IntegrationsPage.tsx +144 -3
- package/package.json +2 -2
- package/scaffold/.agent/skills/total-recall/SKILL.md +55 -6
- package/scaffold/.agent/skills/total-recall/memory-vault/invariants/operating-instructions.md +2 -2
- package/scaffold/.agent/skills/total-recall/skills/cli-agents/agents.yml +1 -6
- package/scaffold/.agent/skills/total-recall/skills/ssss/SKILL.md +19 -0
- package/scaffold/.agent/skills/total-recall/skills/ssss/references/ssss-spec.md +33 -5
- package/src/cli/forget.mjs +18 -12
- package/src/cli/ingest/index.mjs +3 -2
- package/src/cli/init.mjs +30 -0
- package/src/cli/map.mjs +2 -2
- package/src/cli/rebuild.mjs +1 -1
- package/src/cli/remember.mjs +21 -11
- package/src/cli/setup.mjs +10 -1
- package/src/cli/share.mjs +7 -2
- package/src/core/append-log.mjs +131 -0
- package/src/core/clarity-rewriter.mjs +10 -6
- package/src/core/conclusion-writer.mjs +3 -2
- package/src/core/config.mjs +6 -0
- package/src/core/conflict-detector.mjs +4 -2
- package/src/core/context-compiler.mjs +412 -0
- package/src/core/daemon-loop.mjs +15 -0
- package/src/core/dream.mjs +4 -4
- package/src/core/drift-detector.mjs +3 -3
- package/src/core/embeddings.mjs +60 -10
- package/src/core/fact-seeker.mjs +70 -44
- package/src/core/import-rules.mjs +3 -2
- package/src/core/inference-engine.mjs +5 -4
- package/src/core/migrate.mjs +4 -3
- package/src/core/optimizer.mjs +6 -5
- package/src/core/parallel-context.mjs +288 -0
- package/src/core/post-mortem.mjs +4 -3
- package/src/core/research-queue.mjs +4 -3
- package/src/core/runtime.mjs +2 -2
- package/src/core/sandbox.mjs +56 -26
- package/src/core/scheduler.mjs +6 -5
- package/src/core/schema.mjs +2 -2
- package/src/core/search.mjs +167 -101
- package/src/core/surface.mjs +203 -53
- package/src/core/validated-write.mjs +100 -0
- package/src/core/vault-cache.mjs +46 -18
- package/src/core/vault.mjs +17 -29
- package/src/core/vector-field.mjs +659 -0
- package/src/core/vector-store.mjs +85 -0
- package/src/server/api.mjs +4 -3
- package/src/server/index.mjs +13 -61
- package/src/server/rest.mjs +238 -29
- package/src/server/route-manifest.json +344 -77
- package/src/server/routes/memory.mjs +85 -39
- package/src/server/routes/sessions.mjs +6 -2
- package/src/server/routes/share.mjs +9 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useMemo, useState, useEffect } from 'react'
|
|
2
|
-
import { getApiBase, listApiKeys, connectClient, fetchActiveIntegrations } from '../api'
|
|
2
|
+
import { getApiBase, listApiKeys, connectClient, fetchActiveIntegrations, fetchExtensionStatus } from '../api'
|
|
3
3
|
import type { ApiKey } from '../api'
|
|
4
4
|
|
|
5
5
|
type Preset = {
|
|
@@ -68,6 +68,7 @@ export default function IntegrationsPage() {
|
|
|
68
68
|
const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null)
|
|
69
69
|
const [keys, setKeys] = useState<ApiKey[]>([])
|
|
70
70
|
const [activeIdes, setActiveIdes] = useState<string[]>([])
|
|
71
|
+
const [extStatus, setExtStatus] = useState<{ available: boolean; connected: boolean } | null>(null)
|
|
71
72
|
|
|
72
73
|
const baseUrl = useMemo(() => {
|
|
73
74
|
const configured = getApiBase()
|
|
@@ -91,6 +92,12 @@ export default function IntegrationsPage() {
|
|
|
91
92
|
})
|
|
92
93
|
.catch(() => {})
|
|
93
94
|
|
|
95
|
+
fetchExtensionStatus()
|
|
96
|
+
.then(res => {
|
|
97
|
+
if (active) setExtStatus(res)
|
|
98
|
+
})
|
|
99
|
+
.catch(() => {})
|
|
100
|
+
|
|
94
101
|
return () => { active = false }
|
|
95
102
|
}, [])
|
|
96
103
|
|
|
@@ -221,6 +228,138 @@ export default function IntegrationsPage() {
|
|
|
221
228
|
gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))',
|
|
222
229
|
gap: 16,
|
|
223
230
|
}}>
|
|
231
|
+
{/* Chrome Extension Integration Card */}
|
|
232
|
+
<div style={{
|
|
233
|
+
border: '1px solid var(--border)',
|
|
234
|
+
background: 'var(--bg-secondary)',
|
|
235
|
+
borderRadius: 12,
|
|
236
|
+
padding: 18,
|
|
237
|
+
display: 'flex',
|
|
238
|
+
flexDirection: 'column',
|
|
239
|
+
gap: 12,
|
|
240
|
+
position: 'relative',
|
|
241
|
+
}}>
|
|
242
|
+
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 12 }}>
|
|
243
|
+
<div>
|
|
244
|
+
<h3 style={{ margin: '0 0 4px' }}>Chrome Extension</h3>
|
|
245
|
+
<div style={{ color: 'var(--text-tertiary)', fontSize: 12 }}>Browser Overlay Panel & Capture</div>
|
|
246
|
+
</div>
|
|
247
|
+
{extStatus ? (
|
|
248
|
+
extStatus.connected ? (
|
|
249
|
+
<span style={{
|
|
250
|
+
display: 'inline-flex',
|
|
251
|
+
alignItems: 'center',
|
|
252
|
+
gap: 6,
|
|
253
|
+
padding: '4px 8px',
|
|
254
|
+
borderRadius: 6,
|
|
255
|
+
background: 'rgba(16, 185, 129, 0.1)',
|
|
256
|
+
border: '1px solid rgba(16, 185, 129, 0.3)',
|
|
257
|
+
fontSize: 12,
|
|
258
|
+
color: '#34d399',
|
|
259
|
+
fontWeight: 500,
|
|
260
|
+
}}>
|
|
261
|
+
<span style={{
|
|
262
|
+
width: 8,
|
|
263
|
+
height: 8,
|
|
264
|
+
borderRadius: '50%',
|
|
265
|
+
background: '#10b981',
|
|
266
|
+
boxShadow: '0 0 8px #10b981',
|
|
267
|
+
}} />
|
|
268
|
+
Connected
|
|
269
|
+
</span>
|
|
270
|
+
) : (
|
|
271
|
+
<span style={{
|
|
272
|
+
display: 'inline-flex',
|
|
273
|
+
alignItems: 'center',
|
|
274
|
+
gap: 6,
|
|
275
|
+
padding: '4px 8px',
|
|
276
|
+
borderRadius: 6,
|
|
277
|
+
background: 'rgba(245, 158, 11, 0.1)',
|
|
278
|
+
border: '1px solid rgba(245, 158, 11, 0.3)',
|
|
279
|
+
fontSize: 12,
|
|
280
|
+
color: '#fbbf24',
|
|
281
|
+
fontWeight: 500,
|
|
282
|
+
}}>
|
|
283
|
+
<span style={{ width: 8, height: 8, borderRadius: '50%', background: '#f59e0b' }} />
|
|
284
|
+
Not Connected
|
|
285
|
+
</span>
|
|
286
|
+
)
|
|
287
|
+
) : (
|
|
288
|
+
<span style={{
|
|
289
|
+
display: 'inline-flex',
|
|
290
|
+
alignItems: 'center',
|
|
291
|
+
gap: 6,
|
|
292
|
+
padding: '4px 8px',
|
|
293
|
+
borderRadius: 6,
|
|
294
|
+
background: 'rgba(255, 255, 255, 0.05)',
|
|
295
|
+
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
296
|
+
fontSize: 12,
|
|
297
|
+
color: 'var(--text-tertiary)'
|
|
298
|
+
}}>
|
|
299
|
+
<span style={{ width: 8, height: 8, borderRadius: '50%', background: '#94a3b8' }} />
|
|
300
|
+
Checking...
|
|
301
|
+
</span>
|
|
302
|
+
)}
|
|
303
|
+
</div>
|
|
304
|
+
|
|
305
|
+
<div style={{ fontSize: 12, color: 'var(--text-secondary)' }}>
|
|
306
|
+
Scopes utilized: <code>chat:write, memory:read, memory:write</code>
|
|
307
|
+
</div>
|
|
308
|
+
|
|
309
|
+
<div style={{
|
|
310
|
+
background: 'var(--bg-primary)',
|
|
311
|
+
border: '1px solid var(--border)',
|
|
312
|
+
borderRadius: 8,
|
|
313
|
+
padding: 10,
|
|
314
|
+
fontSize: 13,
|
|
315
|
+
color: 'var(--text-secondary)',
|
|
316
|
+
lineHeight: '1.4'
|
|
317
|
+
}}>
|
|
318
|
+
Install the Total Recall extension to passively capture context, store quick notes, and access the active brain search overlay inside any Chrome tab.
|
|
319
|
+
</div>
|
|
320
|
+
|
|
321
|
+
<div style={{
|
|
322
|
+
background: 'var(--bg-primary)',
|
|
323
|
+
border: '1px solid var(--border)',
|
|
324
|
+
borderRadius: 8,
|
|
325
|
+
padding: 10,
|
|
326
|
+
fontFamily: 'monospace',
|
|
327
|
+
fontSize: 11,
|
|
328
|
+
whiteSpace: 'pre-wrap',
|
|
329
|
+
color: 'var(--text-tertiary)',
|
|
330
|
+
}}>
|
|
331
|
+
1. Download zip & unzip locally.{"\n"}
|
|
332
|
+
2. Go to chrome://extensions in browser.{"\n"}
|
|
333
|
+
3. Enable "Developer mode" (top right).{"\n"}
|
|
334
|
+
4. Click "Load unpacked" & select unzipped folder.
|
|
335
|
+
</div>
|
|
336
|
+
|
|
337
|
+
<div style={{ display: 'flex', gap: 10, marginTop: 'auto', paddingTop: 8 }}>
|
|
338
|
+
<a
|
|
339
|
+
href={`${baseUrl}/api/extension/download`}
|
|
340
|
+
download
|
|
341
|
+
className="btn btn-sm btn-primary"
|
|
342
|
+
style={{
|
|
343
|
+
background: 'linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%)',
|
|
344
|
+
border: 'none',
|
|
345
|
+
boxShadow: '0 2px 4px rgba(59, 130, 246, 0.3)',
|
|
346
|
+
fontWeight: 600,
|
|
347
|
+
cursor: 'pointer',
|
|
348
|
+
textDecoration: 'none',
|
|
349
|
+
display: 'inline-flex',
|
|
350
|
+
alignItems: 'center',
|
|
351
|
+
justifyContent: 'center',
|
|
352
|
+
padding: '6px 12px',
|
|
353
|
+
borderRadius: '6px',
|
|
354
|
+
color: '#fff',
|
|
355
|
+
fontSize: '12px'
|
|
356
|
+
}}
|
|
357
|
+
>
|
|
358
|
+
⬇ Download Extension Zip
|
|
359
|
+
</a>
|
|
360
|
+
</div>
|
|
361
|
+
</div>
|
|
362
|
+
|
|
224
363
|
{filteredPresets.map(preset => {
|
|
225
364
|
const snippet = preset.snippet(baseUrl)
|
|
226
365
|
|
|
@@ -252,10 +391,12 @@ export default function IntegrationsPage() {
|
|
|
252
391
|
)
|
|
253
392
|
|
|
254
393
|
if (matchingKey) {
|
|
255
|
-
if (matchingKey.hit_count > 0) {
|
|
394
|
+
if (matchingKey.hit_count > 0 || preset.id === 'antigravity') {
|
|
256
395
|
const lastUsedStr = matchingKey.last_used_at
|
|
257
396
|
? ` (Active ${new Date(matchingKey.last_used_at).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })})`
|
|
258
|
-
: ''
|
|
397
|
+
: preset.id === 'antigravity'
|
|
398
|
+
? ' (Active Now)'
|
|
399
|
+
: ''
|
|
259
400
|
statusBadge = (
|
|
260
401
|
<span style={{
|
|
261
402
|
display: 'inline-flex',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "total-recall-brain",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.0",
|
|
4
4
|
"description": "Sovereign AI system — database-free, SSSS-powered personal intelligence engine deployable to any POSIX host.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"local-llm"
|
|
51
51
|
],
|
|
52
52
|
"author": "gregiteen",
|
|
53
|
-
"license": "
|
|
53
|
+
"license": "MIT",
|
|
54
54
|
"bugs": {
|
|
55
55
|
"url": "https://github.com/gregiteen/total-recall/issues"
|
|
56
56
|
},
|
|
@@ -26,9 +26,10 @@ You MUST actively reference and apply this skill under the following specific ru
|
|
|
26
26
|
|
|
27
27
|
### 3. When searching for complex domain knowledge or general facts
|
|
28
28
|
* **Trigger**: When you need to retrieve deep factual information (e.g. from the `facts/` category) or conceptual domain structures (e.g. from `concepts/`) that are not present in your active instruction files.
|
|
29
|
-
* **Action**: Use the
|
|
30
|
-
* **
|
|
31
|
-
* **
|
|
29
|
+
* **Action**: Use the semantic/lexical hybrid search engine (via the local `recall` command, or `/api/memory/search/semantic` endpoint) along with regular text search (e.g., grep):
|
|
30
|
+
* **Hybrid Search**: Blends cosine-similarity vector search and lexical density TF-IDF keyword matching using Reciprocal Rank Fusion (RRF). This blends intent-based semantic matching with exact keyword accuracy.
|
|
31
|
+
* **Hierarchical Parent-Child Search**: Memory node bodies are chunked and indexed as children. The vector store searches both the parent node and child chunks, returning matches based on maximum similarity.
|
|
32
|
+
* **Regular Text Search**: Use grep to locate exact configurations, literal keys, or symbols.
|
|
32
33
|
|
|
33
34
|
### 4. When a topic requires deep, structured domain learning and mastery
|
|
34
35
|
* **Trigger**: When you encounter a complex architectural topic, a deep conceptual system, or a technical domain where you need to acquire deep mastery to proceed effectively.
|
|
@@ -37,7 +38,7 @@ You MUST actively reference and apply this skill under the following specific ru
|
|
|
37
38
|
|
|
38
39
|
### 5. When you modify, add, or delete files in the memory vault
|
|
39
40
|
* **Trigger**: Immediately after performing any memory node writes.
|
|
40
|
-
* **Action**: Rebuild the instruction shims by sending a POST request to `/api/vault/compile`.
|
|
41
|
+
* **Action**: Rebuild the instruction shims. If using CLI commands (`npx total-recall remember` / `forget`), recompilation runs automatically in the background (asynchronously via detached subprocesses) to minimize latency. If editing vault files directly, trigger manual compilation by sending a POST request to `/api/vault/compile` or running `npx total-recall compile`.
|
|
41
42
|
|
|
42
43
|
### 6. When troubleshooting connections, port blocks, or sync errors
|
|
43
44
|
* **Trigger**: If the REST server is unreachable, ports are blocked, or the upstream sync tool encounters errors.
|
|
@@ -48,12 +49,12 @@ You MUST actively reference and apply this skill under the following specific ru
|
|
|
48
49
|
## ⚡ Core Directives for IDE Agents
|
|
49
50
|
|
|
50
51
|
### 1. Zero-Database Sovereign Integrity
|
|
51
|
-
Total Recall operates **entirely database-free**. The local filesystem is the source of truth. Every rule, pattern, decision, concept, preference, and fact exists as a plain Markdown file with semantic YAML frontmatter. Derived indexes are disposable caches. Do not look for PostgreSQL or
|
|
52
|
+
Total Recall operates **entirely database-free**. The local filesystem is the source of truth. Every rule, pattern, decision, concept, preference, and fact exists as a plain Markdown file with semantic YAML frontmatter. Derived indexes are disposable caches. While the internal Vector Store engine is pluggable and ready for native drop-in indexing engines (such as SQLite-VSS or HNSWLib), the canonical source of truth remains filesystem flat files. Do not look for PostgreSQL or traditional SQL databases.
|
|
52
53
|
|
|
53
54
|
### 2. Precise Tool & API Selection Heuristics
|
|
54
55
|
When interacting with the system, choose your interfaces based on the following:
|
|
55
56
|
* **Local Skills**: Use local skill packages (located in `.agent/skills/`) for complex workspace tasks, testing, and formatting. If a local skill has custom helper scripts, ALWAYS invoke them via your shell command tool instead of running raw standard commands.
|
|
56
|
-
* **Total Recall Brain (MANDATORY)**: For all semantic searches, memory retrieval, memory writes, and derived index recompilation, **
|
|
57
|
+
* **Total Recall Brain (MANDATORY)**: For all semantic searches, memory retrieval, memory writes, and derived index recompilation, **use either the local CLI suite (`npx total-recall`) or shell `curl` commands** targeting the REST API endpoints documented below.
|
|
57
58
|
|
|
58
59
|
### 3. Non-Destructive Code Modifications
|
|
59
60
|
When modifying existing rule surfaces or IDE shims (such as `.cursorrules`, `CLAUDE.md`, `GEMINI.md`, etc.), **NEVER** overwrite the developer's custom pre-existing rules. Instead, write compiled absolute invariants inside the managed comment block:
|
|
@@ -81,6 +82,54 @@ This spins up a secure local Express server (port 3000, increments dynamically i
|
|
|
81
82
|
|
|
82
83
|
---
|
|
83
84
|
|
|
85
|
+
## 🛠️ LOCAL CLI SUITE REFERENCE
|
|
86
|
+
|
|
87
|
+
For local workstation and terminal-based agent workflows, Total Recall provides a CLI command suite:
|
|
88
|
+
|
|
89
|
+
### 1. Save Memory Node
|
|
90
|
+
```bash
|
|
91
|
+
npx total-recall remember <category> "<content>" [options]
|
|
92
|
+
```
|
|
93
|
+
Save rules, preferences, corrections, and facts.
|
|
94
|
+
* **Categories**: `invariant`, `preference`, `correction`, `fact`, `concept`, `pattern`, `anti-pattern`, `decision`, `lore`.
|
|
95
|
+
* **Options**:
|
|
96
|
+
* `--global` / `--project`: Target scope. Global writes propagate to all registered projects.
|
|
97
|
+
* `--importance <1-5>`: Define relative importance.
|
|
98
|
+
* `--priority <level>`: Set priority level (`absolute`, `high`, `normal`, `low`).
|
|
99
|
+
* `--modality <type>`: Modality constraints (`must`, `must_not`, `should`, `should_not`, `descriptive`).
|
|
100
|
+
* `--slug <custom-slug>` / `--title "<custom-title>"`: Override automatic identifiers.
|
|
101
|
+
* `--expires <duration>`: Set expiration lifespan (e.g. `7d`, `2w`, `6h`, `3m`).
|
|
102
|
+
* *Note*: Spawns an asynchronous background surface compile process immediately on execution to avoid synchronous blockages.
|
|
103
|
+
|
|
104
|
+
### 2. Delete Memory Node
|
|
105
|
+
```bash
|
|
106
|
+
npx total-recall forget <slug> [options]
|
|
107
|
+
```
|
|
108
|
+
Delete a memory node by slug.
|
|
109
|
+
* **Options**:
|
|
110
|
+
* `--global` / `--project`: Scope layers. If omitted, checks project first, then global.
|
|
111
|
+
* `--no-compile`: Skip automatic background recompilation.
|
|
112
|
+
* *Note*: Spawns an asynchronous background surface compile process immediately on execution.
|
|
113
|
+
|
|
114
|
+
### 3. Recall / Hybrid Search
|
|
115
|
+
```bash
|
|
116
|
+
npx total-recall recall "<query>" [options]
|
|
117
|
+
```
|
|
118
|
+
Perform semantic/lexical hybrid search across rules, facts, and session history using Reciprocal Rank Fusion (RRF).
|
|
119
|
+
* **Options**:
|
|
120
|
+
* `--top-k, -k <number>`: Number of results (default: 5).
|
|
121
|
+
* `--category, -cat <name>`: Filter by SSSS category.
|
|
122
|
+
* `--tags, -t <list>`: Filter by tags.
|
|
123
|
+
* `--global` / `--project`: Search specific layer.
|
|
124
|
+
|
|
125
|
+
### 4. Build Memory Vault (Recompile)
|
|
126
|
+
```bash
|
|
127
|
+
npx total-recall compile
|
|
128
|
+
```
|
|
129
|
+
Synchronously rebuild the entire memory index (derived embeddings) and regenerate prompt instruction shims (such as `INSTRUCTIONS.md`, `GEMINI.md`, `AGENTS.md`, etc.).
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
84
133
|
## 🌐 DIRECT REST API REFERENCE
|
|
85
134
|
|
|
86
135
|
All requests to the Total Recall REST API must include the Bearer token in the `Authorization` header.
|
package/scaffold/.agent/skills/total-recall/memory-vault/invariants/operating-instructions.md
CHANGED
|
@@ -15,7 +15,7 @@ predicate: operate
|
|
|
15
15
|
object: memory_system
|
|
16
16
|
created: 2026-05-01T00:00:00.000Z
|
|
17
17
|
updated: 2026-05-15T00:00:00.000Z
|
|
18
|
-
last_accessed: 2026-
|
|
18
|
+
last_accessed: 2026-06-01T06:07:11.601Z
|
|
19
19
|
source:
|
|
20
20
|
type: scaffold
|
|
21
21
|
session_id: scaffold-seed
|
|
@@ -36,7 +36,7 @@ sentiment_polarity: directive_must
|
|
|
36
36
|
sentiment_target: memory_system
|
|
37
37
|
decay:
|
|
38
38
|
half_life_days: 365
|
|
39
|
-
access_count:
|
|
39
|
+
access_count: 3
|
|
40
40
|
x_temporal_context: 2026-05-26T23:05:06.525Z
|
|
41
41
|
---
|
|
42
42
|
# Total Recall Operating Protocol
|
|
@@ -5,12 +5,7 @@ agents:
|
|
|
5
5
|
priority: 1
|
|
6
6
|
enabled: true
|
|
7
7
|
exec: flag
|
|
8
|
-
|
|
9
|
-
binary: gemini
|
|
10
|
-
flags: --sandbox=false --yolo -o json
|
|
11
|
-
priority: 2
|
|
12
|
-
enabled: true
|
|
13
|
-
exec: flag
|
|
8
|
+
|
|
14
9
|
- name: claude
|
|
15
10
|
binary: claude
|
|
16
11
|
flags: --output-format json --permission-mode bypassPermissions
|
|
@@ -9,11 +9,23 @@ schema_version: 2
|
|
|
9
9
|
|
|
10
10
|
Structured Semantic Syntax System (ssss) is the core operational substrate of the Total Recall Virtual File System (VFS). This skill guides agents in inspecting, reading, and constructing SSSS-compliant memory nodes, conflict models, and derived indices.
|
|
11
11
|
|
|
12
|
+
## Spec Version
|
|
13
|
+
|
|
14
|
+
Current specification: **v0.2 — Draft** (see `references/ssss-spec.md`)
|
|
15
|
+
|
|
16
|
+
### v0.2 Changes (2026-05-30)
|
|
17
|
+
- Expanded `modality` enum: `must|must_not|should|should_not|descriptive|preference`
|
|
18
|
+
- Expanded `priority` enum: `absolute|high|normal|low` (OPTIONAL, defaults to `normal`)
|
|
19
|
+
- Added §10.1: Projection Manifest requirement with vault-hash staleness detection
|
|
20
|
+
- Added §11.3: Single canonical embedding implementation (no dual systems)
|
|
21
|
+
|
|
12
22
|
## Core Directives
|
|
13
23
|
|
|
14
24
|
1. **Schema Integrity:** Every SSSS node must strictly adhere to the frontmatter schema definitions (Modality, Category, Sentiment).
|
|
15
25
|
2. **Zero-Database Persistence:** Do not look for Postgres or SQLite. Everything lives as a git-versioned Markdown file.
|
|
16
26
|
3. **Decay and Drift Monitoring:** Use decay indicators to manage node half-lives dynamically in background ticks.
|
|
27
|
+
4. **Cached Reads:** All vault reads MUST go through `vault-cache.mjs` (`getNodes()`) — never call `loadNodes()` directly. The cache supports multi-directory (global + project) with per-directory `fs.watch` invalidation.
|
|
28
|
+
5. **Operation Contract:** All agent-generated mutations MUST flow through `processOperation()` (§6). Direct `writeNode()` calls bypass validation, idempotency, authorization, lease protection, and audit logging.
|
|
17
29
|
|
|
18
30
|
## Progressive Memory Disclosure
|
|
19
31
|
|
|
@@ -22,6 +34,13 @@ Memory flows through a 3-tier progressive hierarchy:
|
|
|
22
34
|
* **Tier 2 (Warm):** SKILL.md injects (Category-routed warm capsules).
|
|
23
35
|
* **Tier 3 (Cold):** Full memory vault (Search index files on demand).
|
|
24
36
|
|
|
37
|
+
## Performance Invariants
|
|
38
|
+
|
|
39
|
+
* `vault-cache.mjs` is the **single import point** for all node reads. The cache uses `fs.watch` auto-invalidation and supports multiple vault directories simultaneously.
|
|
40
|
+
* `walkMd()` uses `{ withFileTypes: true }` to eliminate per-file `stat()` syscalls.
|
|
41
|
+
* `deleteNode()` scans category directories directly — O(categories) not O(nodes).
|
|
42
|
+
* Surface recompilation (`triggerMutation()`) is debounced with a 2-second quiet period for batch writes.
|
|
43
|
+
|
|
25
44
|
## References
|
|
26
45
|
|
|
27
46
|
* Core SSSS specification: `references/ssss-spec.md`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# SSSS — Structured Semantic Syntax System
|
|
2
2
|
|
|
3
|
-
**Specification v0.
|
|
3
|
+
**Specification v0.2 — Draft**
|
|
4
4
|
|
|
5
5
|
> This is the canonical, vendor-neutral specification for SSSS. It is the ground
|
|
6
6
|
> truth on which all SSSS implementations are built. It is intended to be vendored
|
|
@@ -198,8 +198,8 @@ The knowledge primitive. Categories: `invariants`, `patterns`, `anti-patterns`,
|
|
|
198
198
|
REQUIRED: `type`, `slug`, `category`, `title`, `status`, `schema_version`.
|
|
199
199
|
|
|
200
200
|
Knowledge-graph fields, REQUIRED when `schema_version: 2`: `confidence` (0..1),
|
|
201
|
-
`importance` (1..5), `modality` (`must|must_not|should|should_not`),
|
|
202
|
-
`predicate`, `object`, `sentiment_polarity`
|
|
201
|
+
`importance` (1..5), `modality` (`must|must_not|should|should_not|descriptive|preference`),
|
|
202
|
+
`subject`, `predicate`, `object`, `sentiment_polarity`
|
|
203
203
|
(`directive_must|directive_must_not|descriptive|preference`).
|
|
204
204
|
|
|
205
205
|
The `subject`/`predicate`/`object` triple SHOULD use stable, language-neutral
|
|
@@ -228,7 +228,8 @@ POSIX filesystems; direct writes risk partial-file corruption on crash.
|
|
|
228
228
|
```
|
|
229
229
|
|
|
230
230
|
Memory nodes in the `invariants` category additionally carry `priority: absolute`
|
|
231
|
-
and `immutable: true`.
|
|
231
|
+
and `immutable: true`. The full `priority` enum is `absolute|high|normal|low`;
|
|
232
|
+
`priority` is OPTIONAL on non-invariant categories (defaults to `normal`).
|
|
232
233
|
|
|
233
234
|
#### `skill`
|
|
234
235
|
|
|
@@ -673,6 +674,30 @@ A host that maintains projections MUST provide a means to (a) rebuild a projecti
|
|
|
673
674
|
from a vault scan, and (b) detect and repair drift between a projection and the
|
|
674
675
|
vault.
|
|
675
676
|
|
|
677
|
+
### 10.1 Projection Manifest
|
|
678
|
+
|
|
679
|
+
A host SHOULD maintain a `MANIFEST.json` (or equivalent) in the derived-artifacts
|
|
680
|
+
directory declaring each projection as disposable and recording provenance:
|
|
681
|
+
|
|
682
|
+
```jsonc
|
|
683
|
+
{
|
|
684
|
+
"type": "projection-manifest",
|
|
685
|
+
"generated_at": "2026-05-30T06:35:00Z",
|
|
686
|
+
"vault_hash": "sha256:abc123...", // content hash of the vault at build time
|
|
687
|
+
"projections": [
|
|
688
|
+
{ "file": "graph-index.jsonl", "disposable": true },
|
|
689
|
+
{ "file": "memory-layers.jsonl", "disposable": true },
|
|
690
|
+
{ "file": "embeddings.json", "disposable": true }
|
|
691
|
+
],
|
|
692
|
+
"rebuild_command": "npx total-recall compile"
|
|
693
|
+
}
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
The `vault_hash` field enables **staleness detection**: if the current vault hash
|
|
697
|
+
differs from the manifest's hash, the projections are stale and SHOULD be rebuilt.
|
|
698
|
+
This supports **incremental compilation** — a host MAY skip recompilation when the
|
|
699
|
+
hash matches, avoiding redundant I/O on unchanged vaults.
|
|
700
|
+
|
|
676
701
|
---
|
|
677
702
|
|
|
678
703
|
## 11. The Semantic Layer
|
|
@@ -713,6 +738,9 @@ disposable, never source-of-truth, fully rebuildable from the vault.
|
|
|
713
738
|
|
|
714
739
|
- It MUST record the `embedding_model` and vector `dim` that produced it. Embeddings
|
|
715
740
|
are not comparable across models; a model change REQUIRES a full reindex.
|
|
741
|
+
- A host MUST maintain exactly **one canonical embedding implementation**. Parallel
|
|
742
|
+
or duplicate embedding systems (e.g. one in JSON format and another in JSONL)
|
|
743
|
+
create consistency risks where a node is indexed in one but not the other.
|
|
716
744
|
- Retrieval SHOULD be **hybrid**: an exact/lexical pass (strong for slugs,
|
|
717
745
|
identifiers, and code) fused with a dense semantic pass (strong for meaning and
|
|
718
746
|
cross-lingual matches).
|
|
@@ -802,7 +830,7 @@ opaque ID as the slug and keep the human-readable label in `title` / `name`.
|
|
|
802
830
|
This document is versioned independently of any host and of the conformance
|
|
803
831
|
fixture set.
|
|
804
832
|
|
|
805
|
-
- The spec version is stated in the document header (currently **v0.
|
|
833
|
+
- The spec version is stated in the document header (currently **v0.2 — Draft**).
|
|
806
834
|
- Breaking changes to the file format, the type registry, or the Operation
|
|
807
835
|
Contract increment the spec version.
|
|
808
836
|
- Until **v1.0**, any version MAY introduce breaking changes.
|
package/src/cli/forget.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { resolveAgentDir, resolveBrainDir, parseLayerFlag, getBothBrains } from './agent-dir.mjs';
|
|
4
4
|
import { compileSurface } from '../core/surface.mjs';
|
|
5
|
-
import { deleteNode
|
|
5
|
+
import { deleteNode } from '../core/vault.mjs';
|
|
6
6
|
|
|
7
7
|
function printHelp() {
|
|
8
8
|
console.log(`
|
|
@@ -46,9 +46,15 @@ export default async function forget(args) {
|
|
|
46
46
|
// Check project first, then global
|
|
47
47
|
if (brains.project) {
|
|
48
48
|
const projVaultDir = path.join(brains.project.brainDir, 'memory-vault');
|
|
49
|
-
|
|
50
|
-
if (
|
|
51
|
-
|
|
49
|
+
// Direct category scan instead of full vault load
|
|
50
|
+
if (fs.existsSync(projVaultDir)) {
|
|
51
|
+
const cats = fs.readdirSync(projVaultDir, { withFileTypes: true });
|
|
52
|
+
for (const cat of cats) {
|
|
53
|
+
if (cat.isDirectory() && fs.existsSync(path.join(projVaultDir, cat.name, `${slug}.md`))) {
|
|
54
|
+
layer = 'project';
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
52
58
|
}
|
|
53
59
|
}
|
|
54
60
|
if (layer === 'auto') {
|
|
@@ -76,17 +82,17 @@ export default async function forget(args) {
|
|
|
76
82
|
|
|
77
83
|
// Recompile unless --no-compile
|
|
78
84
|
if (!noCompile) {
|
|
79
|
-
console.log(' ⏳ Recompiling active memory surfaces and indexes...');
|
|
85
|
+
console.log(' ⏳ Recompiling active memory surfaces and indexes in the background...');
|
|
80
86
|
try {
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
instructionsFile
|
|
87
|
+
const { spawn } = await import('node:child_process');
|
|
88
|
+
const child = spawn(process.argv[0], [process.argv[1], 'compile'], {
|
|
89
|
+
detached: true,
|
|
90
|
+
stdio: 'ignore'
|
|
86
91
|
});
|
|
87
|
-
|
|
92
|
+
child.unref();
|
|
93
|
+
console.log(' ✅ Background compilation started.');
|
|
88
94
|
} catch (err) {
|
|
89
|
-
console.warn(` ⚠️ Node deleted, but
|
|
95
|
+
console.warn(` ⚠️ Node deleted, but background recompilation spawn failed: ${err.message}`);
|
|
90
96
|
}
|
|
91
97
|
}
|
|
92
98
|
}
|
package/src/cli/ingest/index.mjs
CHANGED
|
@@ -24,7 +24,8 @@ import { parseSearchHistory } from './parsers/search-history.mjs';
|
|
|
24
24
|
import { parseChromeBookmarks } from './parsers/chrome-bookmarks.mjs';
|
|
25
25
|
import { parseGoogleKeep } from './parsers/google-keep.mjs';
|
|
26
26
|
import { parseYoutubeHistory } from './parsers/youtube-history.mjs';
|
|
27
|
-
import { writeNode
|
|
27
|
+
import { writeNode } from '../../core/vault.mjs';
|
|
28
|
+
import { getNodes } from '../../core/vault-cache.mjs';
|
|
28
29
|
import { resolveBrainDir, parseLayerFlag, getBothBrains, defaultLayerForCategory } from '../../cli/agent-dir.mjs';
|
|
29
30
|
|
|
30
31
|
/**
|
|
@@ -204,7 +205,7 @@ export async function ingestGoogleTakeout(takeoutPath, options = {}) {
|
|
|
204
205
|
// Load existing vault nodes for dedup
|
|
205
206
|
let existingNodes = [];
|
|
206
207
|
if (fs.existsSync(vaultDir)) {
|
|
207
|
-
existingNodes =
|
|
208
|
+
existingNodes = getNodes(vaultDir);
|
|
208
209
|
}
|
|
209
210
|
|
|
210
211
|
// Run parsers for each detected type
|
package/src/cli/init.mjs
CHANGED
|
@@ -533,6 +533,36 @@ export default async function init(args) {
|
|
|
533
533
|
if (opts.token) brainCfg.token = opts.token;
|
|
534
534
|
fs.writeFileSync(path.join(cfgDir, 'brain.json'), JSON.stringify(brainCfg, null, 2), { mode: 0o600 });
|
|
535
535
|
logOk(`Registered brain at ${opts.brain}. Run \`npx total-recall sync\` to pull instructions.`);
|
|
536
|
+
} else {
|
|
537
|
+
// Zero-config bootstrap: auto-generate localhost brain.json and valid Developer PAT out-of-the-box
|
|
538
|
+
const cfgDir = path.join(brainDir, 'config');
|
|
539
|
+
fs.mkdirSync(cfgDir, { recursive: true });
|
|
540
|
+
const brainJsonPath = path.join(cfgDir, 'brain.json');
|
|
541
|
+
let needsBootstrap = false;
|
|
542
|
+
let brainCfg = {};
|
|
543
|
+
if (fs.existsSync(brainJsonPath)) {
|
|
544
|
+
try {
|
|
545
|
+
brainCfg = JSON.parse(fs.readFileSync(brainJsonPath, 'utf8'));
|
|
546
|
+
if (!brainCfg.url || !brainCfg.token) needsBootstrap = true;
|
|
547
|
+
} catch {
|
|
548
|
+
needsBootstrap = true;
|
|
549
|
+
}
|
|
550
|
+
} else {
|
|
551
|
+
needsBootstrap = true;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
if (needsBootstrap) {
|
|
555
|
+
try {
|
|
556
|
+
const { issueKey } = await import('../server/keys.mjs');
|
|
557
|
+
const keyData = issueKey('Default Local Developer Key', { scopes: ['*'] });
|
|
558
|
+
brainCfg.url = brainCfg.url || 'http://localhost:3000';
|
|
559
|
+
brainCfg.token = brainCfg.token || keyData.token;
|
|
560
|
+
fs.writeFileSync(brainJsonPath, JSON.stringify(brainCfg, null, 2), { mode: 0o600 });
|
|
561
|
+
logOk(`Bootstrap configuration successfully generated and pre-authorized at ${brainCfg.url}`);
|
|
562
|
+
} catch (err) {
|
|
563
|
+
logWarn(`Could not auto-generate bootstrap developer key: ${err.message}`);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
536
566
|
}
|
|
537
567
|
|
|
538
568
|
let dashboardUrl = '';
|
package/src/cli/map.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { resolveBrainDir, parseLayerFlag, getBothBrains } from './agent-dir.mjs';
|
|
4
|
-
import {
|
|
4
|
+
import { getNodes } from '../core/vault-cache.mjs';
|
|
5
5
|
|
|
6
6
|
function printHelp() {
|
|
7
7
|
console.log(`
|
|
@@ -68,7 +68,7 @@ export default async function map(args) {
|
|
|
68
68
|
const vaultDir = path.join(l.path, 'memory-vault');
|
|
69
69
|
if (!fs.existsSync(vaultDir)) continue;
|
|
70
70
|
|
|
71
|
-
const nodes =
|
|
71
|
+
const nodes = getNodes(vaultDir).map(n => ({ ...n, _layer: l.name }));
|
|
72
72
|
loadedLayers.push({ name: l.name, nodes });
|
|
73
73
|
totalNodesCount += nodes.length;
|
|
74
74
|
}
|
package/src/cli/rebuild.mjs
CHANGED
|
@@ -59,7 +59,7 @@ export async function runRebuild(options = {}) {
|
|
|
59
59
|
|
|
60
60
|
console.log('🏗️ Recompiling surface from canonical vault...');
|
|
61
61
|
try {
|
|
62
|
-
const stats = await compileSurface({ vaultDir, skillsDir, derivedDir, instructionsFile });
|
|
62
|
+
const stats = await compileSurface({ vaultDir, skillsDir, derivedDir, instructionsFile, force: true });
|
|
63
63
|
console.log(`✅ Processed ${stats.nodesProcessed} canonical memory nodes.`);
|
|
64
64
|
console.log(`✅ Injected memory into ${stats.skillsInjected} skill files.`);
|
|
65
65
|
console.log(`✅ Rebuilt graph-index.jsonl, memory-layers.jsonl, and skill-routes.jsonl.`);
|
package/src/cli/remember.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import path from 'node:path';
|
|
|
3
3
|
import crypto from 'node:crypto';
|
|
4
4
|
import { resolveAgentDir, resolveBrainDir, parseLayerFlag, getBothBrains, defaultLayerForCategory } from './agent-dir.mjs';
|
|
5
5
|
import { compileSurface } from '../core/surface.mjs';
|
|
6
|
-
import {
|
|
6
|
+
import { writeNodeValidated } from '../core/validated-write.mjs';
|
|
7
7
|
|
|
8
8
|
function printHelp() {
|
|
9
9
|
console.log(`
|
|
@@ -287,20 +287,30 @@ export default async function remember(args) {
|
|
|
287
287
|
node.immutable = true;
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
-
|
|
290
|
+
const vaultResult = writeNodeValidated(node, vaultDir);
|
|
291
|
+
if (!vaultResult.success) {
|
|
292
|
+
console.error(` ❌ Validation failed: ${vaultResult.validation.errors.join('; ')}`);
|
|
293
|
+
if (vaultResult.repair) {
|
|
294
|
+
console.error(` 🔧 Repair hints:`);
|
|
295
|
+
for (const fe of vaultResult.repair.field_errors || []) {
|
|
296
|
+
console.error(` • ${fe.field}: ${fe.issue}`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
process.exit(1);
|
|
300
|
+
}
|
|
291
301
|
console.log(` ✅ Permanent SSSS memory node created ${layerLabel} in vault: memory-vault/${category}/${finalSlug}.md`);
|
|
292
302
|
|
|
293
|
-
//
|
|
294
|
-
console.log(' ⏳ Recompiling active memory surfaces and indexes...');
|
|
303
|
+
// Recompile active memory surfaces and indexes in the background to avoid blocking the CLI call.
|
|
304
|
+
console.log(' ⏳ Recompiling active memory surfaces and indexes in the background...');
|
|
295
305
|
try {
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
instructionsFile
|
|
306
|
+
const { spawn } = await import('node:child_process');
|
|
307
|
+
const child = spawn(process.argv[0], [process.argv[1], 'compile'], {
|
|
308
|
+
detached: true,
|
|
309
|
+
stdio: 'ignore'
|
|
301
310
|
});
|
|
302
|
-
|
|
311
|
+
child.unref();
|
|
312
|
+
console.log(' ✅ Background compilation started.');
|
|
303
313
|
} catch (err) {
|
|
304
|
-
console.warn(` ⚠️ Memory saved, but
|
|
314
|
+
console.warn(` ⚠️ Memory saved, but background recompilation spawn failed: ${err.message}`);
|
|
305
315
|
}
|
|
306
316
|
}
|
package/src/cli/setup.mjs
CHANGED
|
@@ -541,8 +541,17 @@ export default async function setup(args) {
|
|
|
541
541
|
], { stdio: 'inherit' });
|
|
542
542
|
if (result.status !== 0) throw new Error('Local deploy failed');
|
|
543
543
|
ok('Local deploy complete!');
|
|
544
|
+
|
|
545
|
+
// Auto-issue a local developer key for zero-config extension / IDE connection
|
|
546
|
+
try {
|
|
547
|
+
const { issueKey } = await import('../server/keys.mjs');
|
|
548
|
+
const keyData = issueKey('Default Local Developer Key', { scopes: ['*'] });
|
|
549
|
+
pat = keyData.token;
|
|
550
|
+
} catch (err) {
|
|
551
|
+
warn(`Could not auto-generate local developer key: ${err.message}`);
|
|
552
|
+
}
|
|
544
553
|
}
|
|
545
|
-
brainUrl = 'http://
|
|
554
|
+
brainUrl = 'http://localhost:3000';
|
|
546
555
|
}
|
|
547
556
|
|
|
548
557
|
// ── Step 3: Domain (optional) ────────────────────────────────────────────────
|