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.
Files changed (66) hide show
  1. package/README.md +1 -1
  2. package/extension/background.js +14 -2
  3. package/extension/content-script.js +18 -1
  4. package/extension/lib/brain-client.js +86 -52
  5. package/extension/lib/preconfigured.js +5 -0
  6. package/extension/manifest.json +1 -1
  7. package/extension/options/options.html +1 -0
  8. package/extension/options/options.js +12 -6
  9. package/extension/popup/popup.html +1 -0
  10. package/extension/popup/popup.js +29 -4
  11. package/extension/sidepanel/sidepanel.html +1 -0
  12. package/extension/sidepanel/sidepanel.js +24 -6
  13. package/frontend/index.html +8 -0
  14. package/frontend/src/api.ts +1 -2
  15. package/frontend/src/pages/ChatPage.tsx +9 -6
  16. package/frontend/src/pages/IntegrationsPage.tsx +144 -3
  17. package/package.json +2 -2
  18. package/scaffold/.agent/skills/total-recall/SKILL.md +55 -6
  19. package/scaffold/.agent/skills/total-recall/memory-vault/invariants/operating-instructions.md +2 -2
  20. package/scaffold/.agent/skills/total-recall/skills/cli-agents/agents.yml +1 -6
  21. package/scaffold/.agent/skills/total-recall/skills/ssss/SKILL.md +19 -0
  22. package/scaffold/.agent/skills/total-recall/skills/ssss/references/ssss-spec.md +33 -5
  23. package/src/cli/forget.mjs +18 -12
  24. package/src/cli/ingest/index.mjs +3 -2
  25. package/src/cli/init.mjs +30 -0
  26. package/src/cli/map.mjs +2 -2
  27. package/src/cli/rebuild.mjs +1 -1
  28. package/src/cli/remember.mjs +21 -11
  29. package/src/cli/setup.mjs +10 -1
  30. package/src/cli/share.mjs +7 -2
  31. package/src/core/append-log.mjs +131 -0
  32. package/src/core/clarity-rewriter.mjs +10 -6
  33. package/src/core/conclusion-writer.mjs +3 -2
  34. package/src/core/config.mjs +6 -0
  35. package/src/core/conflict-detector.mjs +4 -2
  36. package/src/core/context-compiler.mjs +412 -0
  37. package/src/core/daemon-loop.mjs +15 -0
  38. package/src/core/dream.mjs +4 -4
  39. package/src/core/drift-detector.mjs +3 -3
  40. package/src/core/embeddings.mjs +60 -10
  41. package/src/core/fact-seeker.mjs +70 -44
  42. package/src/core/import-rules.mjs +3 -2
  43. package/src/core/inference-engine.mjs +5 -4
  44. package/src/core/migrate.mjs +4 -3
  45. package/src/core/optimizer.mjs +6 -5
  46. package/src/core/parallel-context.mjs +288 -0
  47. package/src/core/post-mortem.mjs +4 -3
  48. package/src/core/research-queue.mjs +4 -3
  49. package/src/core/runtime.mjs +2 -2
  50. package/src/core/sandbox.mjs +56 -26
  51. package/src/core/scheduler.mjs +6 -5
  52. package/src/core/schema.mjs +2 -2
  53. package/src/core/search.mjs +167 -101
  54. package/src/core/surface.mjs +203 -53
  55. package/src/core/validated-write.mjs +100 -0
  56. package/src/core/vault-cache.mjs +46 -18
  57. package/src/core/vault.mjs +17 -29
  58. package/src/core/vector-field.mjs +659 -0
  59. package/src/core/vector-store.mjs +85 -0
  60. package/src/server/api.mjs +4 -3
  61. package/src/server/index.mjs +13 -61
  62. package/src/server/rest.mjs +238 -29
  63. package/src/server/route-manifest.json +344 -77
  64. package/src/server/routes/memory.mjs +85 -39
  65. package/src/server/routes/sessions.mjs +6 -2
  66. 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.2.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": "ISC",
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 two complementary search modes:
30
- * **Regular Text Search** (e.g. filesystem grep / literal matching): Use this when searching for specific literal keywords, exact config keys, exact filenames, or exact slugs.
31
- * **Semantic Search (REST API POST `/api/memory/search/semantic`)**: Use this when searching for conceptual matching, high-level intent, design patterns, or user preferences. Do NOT rely on only one search mode; combine both to ensure absolute coverage.
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 SQLite databases.
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, **ALWAYS use shell `curl` commands** targeting the REST API endpoints documented below.
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.
@@ -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-05-15T00:00:00.000Z
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: 1
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
- - name: gemini
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.1 — Draft**
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`), `subject`,
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.1 — Draft**).
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.
@@ -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, loadNodes } from '../core/vault.mjs';
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
- const projNodes = loadNodes(projVaultDir);
50
- if (projNodes.some(n => n.slug === slug)) {
51
- layer = 'project';
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 compileResult = await compileSurface({
82
- vaultDir,
83
- skillsDir,
84
- derivedDir,
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
- console.log(` ✅ Recompilation successful! Processed ${compileResult.nodesProcessed} SSSS nodes.`);
92
+ child.unref();
93
+ console.log(' ✅ Background compilation started.');
88
94
  } catch (err) {
89
- console.warn(` ⚠️ Node deleted, but surface recompilation failed: ${err.message}`);
95
+ console.warn(` ⚠️ Node deleted, but background recompilation spawn failed: ${err.message}`);
90
96
  }
91
97
  }
92
98
  }
@@ -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, loadNodes } from '../../core/vault.mjs';
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 = loadNodes(vaultDir);
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 { loadNodes } from '../core/vault.mjs';
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 = loadNodes(vaultDir).map(n => ({ ...n, _layer: l.name }));
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
  }
@@ -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.`);
@@ -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 { writeNode } from '../core/vault.mjs';
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
- writeNode(node, vaultDir);
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
- // Instantly recompile instructions and vector indexes in the exact same turn!
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 compileResult = await compileSurface({
297
- vaultDir,
298
- skillsDir,
299
- derivedDir,
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
- console.log(` ✅ Recompilation successful! Processed ${compileResult.nodesProcessed} SSSS nodes.`);
311
+ child.unref();
312
+ console.log(' ✅ Background compilation started.');
303
313
  } catch (err) {
304
- console.warn(` ⚠️ Memory saved, but surface recompilation failed: ${err.message}`);
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://127.0.0.1:3000';
554
+ brainUrl = 'http://localhost:3000';
546
555
  }
547
556
 
548
557
  // ── Step 3: Domain (optional) ────────────────────────────────────────────────