total-recall-brain 3.8.1 → 3.10.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 (45) hide show
  1. package/package.json +6 -5
  2. package/scaffold/.agent/skills/total-recall/SKILL.md +1 -0
  3. package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/SKILL.md +3 -2
  4. package/scaffold/.agent/skills/total-recall/skills/{research → tr-research}/SKILL.md +2 -1
  5. package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/SKILL.md +3 -2
  6. package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/evals/evals.json +3 -3
  7. package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/hooks/on-skill-add.sh +1 -1
  8. package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/hooks/on-skill-delete.sh +1 -1
  9. package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/scripts/create-skill.sh +3 -3
  10. package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/scripts/find-skills.mjs +25 -1
  11. package/scaffold/.agent/skills/total-recall/skills/tr-skill/scripts/install-skill.mjs +117 -0
  12. package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/scripts/scan-skill.mjs +20 -0
  13. package/scaffold/.agent/skills/total-recall/skills/{ssss → tr-ssss}/SKILL.md +58 -15
  14. package/src/cli/connect.mjs +47 -5
  15. package/src/cli/init.mjs +42 -2
  16. package/src/cli/skill-projection.mjs +214 -0
  17. package/src/cli/skill.mjs +44 -18
  18. package/src/core/daemon-loop.mjs +13 -2
  19. package/src/core/operation-validator.mjs +19 -1
  20. package/src/core/research.mjs +47 -9
  21. package/src/core/runtime.mjs +14 -7
  22. package/src/core/schema.mjs +23 -1
  23. package/src/server/api.mjs +2 -2
  24. package/src/server/rest.mjs +3 -3
  25. package/src/server/routes/skills.mjs +25 -4
  26. /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/agents.yml +0 -0
  27. /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/evals/.gitkeep +0 -0
  28. /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/references/antigravity.txt +0 -0
  29. /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/references/claude.txt +0 -0
  30. /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/references/codex.txt +0 -0
  31. /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/references/gemini.txt +0 -0
  32. /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/scripts/.gitkeep +0 -0
  33. /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/subagents/.gitkeep +0 -0
  34. /package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/assets/skill-template/SKILL.md +0 -0
  35. /package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/learnings/.gitkeep +0 -0
  36. /package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/references/.gitkeep +0 -0
  37. /package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/scripts/.gitkeep +0 -0
  38. /package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/scripts/enforce-skill-optimization.mjs +0 -0
  39. /package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/scripts/skill-watcher.mjs +0 -0
  40. /package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/subagents/audit-all-skills.md +0 -0
  41. /package/scaffold/.agent/skills/total-recall/skills/{ssss → tr-ssss}/evals/evals.json +0 -0
  42. /package/scaffold/.agent/skills/total-recall/skills/{ssss → tr-ssss}/references/CHANGELOG.md +0 -0
  43. /package/scaffold/.agent/skills/total-recall/skills/{ssss → tr-ssss}/references/ssss-spec.md +0 -0
  44. /package/scaffold/.agent/skills/total-recall/skills/{ssss → tr-ssss}/scripts/validate-schema.mjs +0 -0
  45. /package/scaffold/.agent/skills/total-recall/skills/{ssss → tr-ssss}/subagents/audit-ssss-node.md +0 -0
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "total-recall-brain",
3
- "version": "3.8.1",
3
+ "version": "3.10.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": {
7
- "total-recall": "./bin/total-recall.mjs",
8
- "antigravity": "./bin/antigravity.mjs"
7
+ "total-recall": "bin/total-recall.mjs",
8
+ "antigravity": "bin/antigravity.mjs"
9
9
  },
10
10
  "files": [
11
11
  "bin/",
@@ -56,6 +56,7 @@
56
56
  },
57
57
  "homepage": "https://github.com/gregiteen/total-recall#readme",
58
58
  "dependencies": {
59
+ "@ssss/cli": "github:gregiteen/ssss#v0.4.0",
59
60
  "bcrypt": "^6.0.0",
60
61
  "cookie-parser": "^1.4.7",
61
62
  "cors": "^2.8.6",
@@ -64,9 +65,9 @@
64
65
  "gray-matter": "^4.0.3",
65
66
  "jsonwebtoken": "^9.0.3",
66
67
  "natural": "^8.1.1",
68
+ "ws": "^8.18.0",
67
69
  "yaml": "^2.9.0",
68
- "zod": "^4.4.3",
69
- "ws": "^8.18.0"
70
+ "zod": "^4.4.3"
70
71
  },
71
72
  "devDependencies": {
72
73
  "skills": "^1.5.7",
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: total-recall
3
+ provenance: total-recall
3
4
  description: "Use this skill as the master guide to understand the entire Total Recall Sovereign AI OS setup, VFS topologies, SSSS protocol, CLI parameter reference, troubleshooting, and automated upstream repository sync. MANDATORY: Read this file before attempting major setup modifications or diagnoses."
4
5
  ---
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
- name: cli-agents
2
+ name: tr-cli-agents
3
+ provenance: total-recall
3
4
  description: "Orchestrate headlessly spawned CLI agents from the central registry."
4
5
  ---
5
6
 
@@ -12,7 +13,7 @@ This system skill governs the discovery, configuration, and execution of headles
12
13
  ## 🎯 SYSTEM OVERVIEW
13
14
 
14
15
  The CLI Agent Dispatch Engine parses agent profiles from the central registry file:
15
- `.agent/skills/total-recall/skills/cli-agents/agents.yml`
16
+ `.agent/skills/total-recall/skills/tr-cli-agents/agents.yml`
16
17
 
17
18
  ```mermaid
18
19
  flowchart TD
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  type: skill
3
- name: research
3
+ name: tr-research
4
+ provenance: total-recall
4
5
  description: "Use this skill when queueing, searching, and managing long-horizon background research projects via the Total Recall REST API."
5
6
  ---
6
7
 
@@ -1,5 +1,6 @@
1
1
  ---
2
- name: skill
2
+ name: tr-skill
3
+ provenance: total-recall
3
4
  description: "Use this skill when creating, auditing, or modifying any skill in the .agent/skills/ ecosystem. MANDATORY: You MUST read the full SKILL.md file before executing."
4
5
  ---
5
6
 
@@ -186,7 +187,7 @@ Contains standalone prompt files for subtasks that can be delegated to parallel
186
187
 
187
188
  ### Quick method (script):
188
189
  ```bash
189
- bash .agent/skills/skill/scripts/create-skill.sh my-new-skill
190
+ bash .agent/skills/tr-skill/scripts/create-skill.sh my-new-skill
190
191
  ```
191
192
 
192
193
  ### Manual method:
@@ -2,19 +2,19 @@
2
2
  {
3
3
  "id": "skill-eval-1",
4
4
  "description": "SKILL.md exists",
5
- "command": "test -f .agent/skills/skill/SKILL.md",
5
+ "command": "test -f .agent/skills/tr-skill/SKILL.md",
6
6
  "expected_exit_code": 0
7
7
  },
8
8
  {
9
9
  "id": "skill-eval-2",
10
10
  "description": "Evals validation",
11
- "command": "test -f .agent/skills/skill/scripts/run-evals.mjs",
11
+ "command": "test -f .agent/skills/tr-skill/scripts/run-evals.mjs",
12
12
  "expected_exit_code": 0
13
13
  },
14
14
  {
15
15
  "id": "skill-eval-3",
16
16
  "description": "Optimization enforcement",
17
- "command": "test -f .agent/skills/skill/scripts/enforce-skill-optimization.mjs",
17
+ "command": "test -f .agent/skills/tr-skill/scripts/enforce-skill-optimization.mjs",
18
18
  "expected_exit_code": 0
19
19
  }
20
20
  ]
@@ -10,5 +10,5 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
10
10
  ROOT="$(cd "$SCRIPT_DIR/../../../.." && pwd)"
11
11
 
12
12
  echo "🔄 OnSkillAdd hook triggered — regenerating skill index..."
13
- node "$ROOT/.agent/skills/skill/scripts/update-skill-index.mjs"
13
+ node "$ROOT/.agent/skills/tr-skill/scripts/update-skill-index.mjs"
14
14
  echo "✅ Routing table and INSTRUCTIONS.md updated."
@@ -10,5 +10,5 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
10
10
  ROOT="$(cd "$SCRIPT_DIR/../../../.." && pwd)"
11
11
 
12
12
  echo "🧹 OnSkillDelete hook triggered — cleaning skill index..."
13
- node "$ROOT/.agent/skills/skill/scripts/update-skill-index.mjs"
13
+ node "$ROOT/.agent/skills/tr-skill/scripts/update-skill-index.mjs"
14
14
  echo "✅ Routing table and INSTRUCTIONS.md cleaned."
@@ -1,8 +1,8 @@
1
1
  #!/bin/bash
2
2
  # create-skill.sh — Scaffold a new Dev Skill from the template
3
3
  #
4
- # Usage: bash .agent/skills/skill/scripts/create-skill.sh <skill-name>
5
- # Example: bash .agent/skills/skill/scripts/create-skill.sh my-new-skill
4
+ # Usage: bash .agent/skills/tr-skill/scripts/create-skill.sh <skill-name>
5
+ # Example: bash .agent/skills/tr-skill/scripts/create-skill.sh my-new-skill
6
6
 
7
7
  set -euo pipefail
8
8
 
@@ -60,6 +60,6 @@ echo ""
60
60
  echo "📝 Next steps:"
61
61
  echo " 1. Edit $TARGET/SKILL.md with real instructions"
62
62
  echo " 2. Write a trigger-optimized description in the frontmatter"
63
- echo " 3. Run: node .agent/skills/skill/scripts/update-skill-index.mjs"
63
+ echo " 3. Run: node .agent/skills/tr-skill/scripts/update-skill-index.mjs"
64
64
  echo ""
65
65
  echo "🏁 Done."
@@ -77,6 +77,7 @@ export function parseFindOutput(rawOutput) {
77
77
 
78
78
  const name = skillMatch[1];
79
79
  const installs = parseInstalls(skillMatch[2], skillMatch[3] || '');
80
+ const installsStr = `${skillMatch[2]}${skillMatch[3] || ''}`;
80
81
 
81
82
  // Next non-empty line should be the URL (prefixed with └ or similar box-drawing chars)
82
83
  let url = '';
@@ -92,12 +93,19 @@ export function parseFindOutput(rawOutput) {
92
93
  break; // only check the very next non-empty line
93
94
  }
94
95
 
95
- results.push({ name, installs, url });
96
+ results.push({ name, installs, installsStr, url });
96
97
  }
97
98
 
98
99
  return results;
99
100
  }
100
101
 
102
+ function formatInstalls(installs) {
103
+ if (installs >= 1_000_000_000) return `${(installs / 1_000_000_000).toFixed(1).replace(/\.0$/, '')}B`;
104
+ if (installs >= 1_000_000) return `${(installs / 1_000_000).toFixed(1).replace(/\.0$/, '')}M`;
105
+ if (installs >= 1_000) return `${(installs / 1_000).toFixed(1).replace(/\.0$/, '')}K`;
106
+ return String(installs);
107
+ }
108
+
101
109
  // ─── Live Registry Search ───────────────────────────────────────────────────
102
110
 
103
111
  /**
@@ -122,3 +130,19 @@ export function searchRegistry(query, { timeoutMs = 15_000 } = {}) {
122
130
  return [];
123
131
  }
124
132
  }
133
+
134
+ /**
135
+ * Search skills.sh and sort by absolute install count, highest first.
136
+ *
137
+ * @param {string} query
138
+ * @param {object} [options]
139
+ * @returns {Array<{ name: string, installs: number, installsStr: string, url: string }>}
140
+ */
141
+ export function searchAndSort(query, options = {}) {
142
+ return searchRegistry(query, options)
143
+ .map(result => ({
144
+ ...result,
145
+ installsStr: result.installsStr || formatInstalls(result.installs || 0),
146
+ }))
147
+ .sort((a, b) => (b.installs || 0) - (a.installs || 0));
148
+ }
@@ -0,0 +1,117 @@
1
+ /**
2
+ * install-skill.mjs — safe wrapper around the Skills CLI installer.
3
+ */
4
+
5
+ import fs from 'node:fs';
6
+ import path from 'node:path';
7
+ import { spawnSync } from 'node:child_process';
8
+ import { scanDirectory, formatReport } from './scan-skill.mjs';
9
+
10
+ const BLOCKED_SOURCE_CHARS = /[\0\r\n;&|<>`$]/;
11
+
12
+ export function validateSkillSource(source) {
13
+ if (typeof source !== 'string') return false;
14
+ const trimmed = source.trim();
15
+ if (!trimmed || trimmed.length > 500) return false;
16
+ return !BLOCKED_SOURCE_CHARS.test(trimmed);
17
+ }
18
+
19
+ export function inferSkillName(source) {
20
+ const trimmed = String(source || '').trim().replace(/\/+$/, '');
21
+ if (!trimmed) return null;
22
+ if (!trimmed.startsWith('git@') && trimmed.includes('@')) {
23
+ return trimmed.split('@').pop() || null;
24
+ }
25
+ const last = trimmed.split('/').filter(Boolean).pop();
26
+ return last ? last.replace(/\.git$/i, '') : null;
27
+ }
28
+
29
+ function uniqueExistingDirs(paths) {
30
+ const seen = new Set();
31
+ const dirs = [];
32
+ for (const candidate of paths) {
33
+ if (!candidate) continue;
34
+ const resolved = path.resolve(candidate);
35
+ if (seen.has(resolved) || !fs.existsSync(resolved)) continue;
36
+ seen.add(resolved);
37
+ dirs.push(resolved);
38
+ }
39
+ return dirs;
40
+ }
41
+
42
+ export function installedSkillCandidates(source, { cwd = process.cwd(), agentDir = path.join(cwd, '.agent') } = {}) {
43
+ const skillName = inferSkillName(source);
44
+ if (!skillName) return [];
45
+ return [
46
+ path.join(agentDir, 'skills', skillName),
47
+ path.join(cwd, '.agent', 'skills', skillName),
48
+ path.join(cwd, '.agents', 'skills', skillName),
49
+ path.join(cwd, '.claude', 'skills', skillName),
50
+ ];
51
+ }
52
+
53
+ /**
54
+ * Install a skill with the Skills CLI, then scan installed script files.
55
+ *
56
+ * @param {string} source skills add source, e.g. owner/repo@skill or URL
57
+ * @param {object} [options]
58
+ * @param {string} [options.cwd]
59
+ * @param {string} [options.agentDir]
60
+ * @param {boolean} [options.dryRun=false]
61
+ * @returns {{ success: boolean, source: string, command?: string[], findings?: Array, error?: string }}
62
+ */
63
+ export function installSkill(source, options = {}) {
64
+ const cwd = options.cwd || process.cwd();
65
+ const agentDir = options.agentDir || path.join(cwd, '.agent');
66
+ const normalized = String(source || '').trim();
67
+
68
+ if (!validateSkillSource(normalized)) {
69
+ const error = 'Invalid skill source. Use a repository, URL, git source, local path, or owner/repo@skill without shell metacharacters.';
70
+ console.error(`❌ ${error}`);
71
+ return { success: false, source: normalized, error };
72
+ }
73
+
74
+ const command = ['npx', '-y', 'skills', 'add', normalized, '-y'];
75
+ if (options.dryRun) {
76
+ return { success: true, source: normalized, command };
77
+ }
78
+
79
+ console.log(`📦 Installing skill: ${normalized}`);
80
+ const child = spawnSync(command[0], command.slice(1), {
81
+ cwd,
82
+ encoding: 'utf8',
83
+ stdio: ['ignore', 'pipe', 'pipe'],
84
+ });
85
+
86
+ if (child.stdout) process.stdout.write(child.stdout);
87
+ if (child.stderr) process.stderr.write(child.stderr);
88
+
89
+ if (child.error || child.status !== 0) {
90
+ const error = child.error?.message || `skills CLI exited with status ${child.status}`;
91
+ console.error(`❌ Skill installation failed: ${error}`);
92
+ return { success: false, source: normalized, command, error };
93
+ }
94
+
95
+ const installedDirs = uniqueExistingDirs(installedSkillCandidates(normalized, { cwd, agentDir }));
96
+ const findings = installedDirs.flatMap(dir => scanDirectory(dir));
97
+ const report = formatReport(findings);
98
+ console.log(report.trimEnd());
99
+
100
+ if (findings.some(f => f.severity === 'CRITICAL')) {
101
+ const error = 'Installed skill contains critical scanner findings.';
102
+ console.error(`❌ ${error}`);
103
+ return { success: false, source: normalized, command, findings, error };
104
+ }
105
+
106
+ const compile = spawnSync('npx', ['total-recall', 'compile'], {
107
+ cwd,
108
+ encoding: 'utf8',
109
+ stdio: ['ignore', 'pipe', 'pipe'],
110
+ env: { ...process.env, AGENT_DIR: agentDir },
111
+ });
112
+ if (compile.status !== 0) {
113
+ console.warn('⚠️ Skill installed, but surface recompilation returned a warning.');
114
+ }
115
+
116
+ return { success: true, source: normalized, command, findings };
117
+ }
@@ -205,3 +205,23 @@ export function formatReport(findings) {
205
205
 
206
206
  return report;
207
207
  }
208
+
209
+ /**
210
+ * CLI-friendly scanner entrypoint.
211
+ *
212
+ * @param {string} targetDir
213
+ * @returns {{ success: boolean, findings: Array, report: string }}
214
+ */
215
+ export function runScan(targetDir) {
216
+ if (!targetDir || !fs.existsSync(targetDir)) {
217
+ const report = `Skill directory not found: ${targetDir}\n`;
218
+ console.error(report.trim());
219
+ return { success: false, findings: [], report };
220
+ }
221
+
222
+ const findings = scanDirectory(targetDir);
223
+ const report = formatReport(findings);
224
+ const blocked = findings.some(f => f.severity === 'CRITICAL');
225
+ console.log(report.trimEnd());
226
+ return { success: !blocked, findings, report };
227
+ }
@@ -1,5 +1,6 @@
1
1
  ---
2
- name: ssss
2
+ name: tr-ssss
3
+ provenance: total-recall
3
4
  description: "Use this skill to inspect, validate, write, and manage SSSS primitives, memory nodes, operation envelopes, scope overlays, projections, and VFS specifications in the Total Recall reference kernel. MANDATORY: Read this file before editing SSSS files or code."
4
5
  ---
5
6
 
@@ -12,9 +13,16 @@ schema/reference files.
12
13
 
13
14
  ## Ground Truth
14
15
 
15
- The vendor-neutral contract is `references/ssss-spec.md`. If this skill conflicts
16
- with the spec, correct this skill unless the implementation has intentionally
17
- advanced beyond the vendored spec and the difference is documented here.
16
+ The vendor-neutral contract is now a published package, **`@ssss/cli`** (pinned to
17
+ **`v0.4.0`**; source <https://github.com/gregiteen/ssss>), declared in
18
+ `package.json`. `references/ssss-spec.md` is the local mirror. The canon owns the
19
+ spec (§5.5 portability, §6 Operation Contract incl. `delete`, §16 the `.ucw` bundle
20
+ format, §17 provisioning), the core registry (`@ssss/cli/registry/core.json`: 13
21
+ document + 5 contract primitives), the reference engine, and the conformance
22
+ fixtures. Total Recall's kernel was the engine the canon's reference implementation
23
+ was harvested from; keep them aligned. If this skill conflicts with the canon,
24
+ correct this skill unless the implementation has intentionally advanced beyond it
25
+ and the difference is documented here.
18
26
 
19
27
  Current local implementation entry points:
20
28
 
@@ -27,6 +35,32 @@ Current local implementation entry points:
27
35
  - `src/core/vector-store.mjs` and `src/core/semantic-index.mjs` — canonical
28
36
  search/index path.
29
37
 
38
+ ## Using the `@ssss/cli` CLI
39
+
40
+ `@ssss/cli` ships a `ssss` command (available via `npx`, since it's a dependency).
41
+ It operates on a **vault directory** of Markdown files and `.ucw` bundles, using
42
+ the canon's own reference engine — separate from this kernel's `processOperation`.
43
+ Use it for bundle/tenant tooling and conformance; for in-kernel memory writes keep
44
+ using `writeNodeValidated()` / `processOperation()`.
45
+
46
+ ```bash
47
+ npx ssss help # list doc topics; e.g. `ssss help portability|bundle|provisioning`
48
+ npx ssss <command> --help # flags for any command
49
+
50
+ # Vault → bundle → vault lifecycle (§16/§17)
51
+ npx ssss export <vault-dir> --profile sale --out pack.ucw.json # backup | template | sale
52
+ npx ssss validate pack.ucw.json # schema + portability + content hash
53
+ npx ssss inspect pack.ucw.json --files # manifest, inventory, params, steps
54
+ npx ssss provision pack.ucw.json --param domain=acme.live --out plan.json # pure: params + links → envelopes
55
+ npx ssss import pack.ucw.json --vault ./new-vault --param domain=acme.live # idempotent replay
56
+
57
+ npx ssss conformance --engine # replay the canonical fixtures + round-trip the reference bundle
58
+ ```
59
+
60
+ `export` is pure/deterministic and `template`/`sale` drop every `tenant_private`
61
+ file (§5.5). Note: the canon's `.ucw` bundle (§16) is distinct from §7.4's OKF
62
+ memory-vault `importBundle`/`exportBundle` in `repo-expert`.
63
+
30
64
  ## Current Contract
31
65
 
32
66
  All agent-generated mutations must flow through the SSSS operation pipeline:
@@ -45,17 +79,16 @@ processOperation(envelope, vaultRoot, options)
45
79
  Use `writeNodeValidated()` for Total Recall memory writes. Do not call raw
46
80
  `writeNode()` or write files directly when an agent is mutating an SSSS vault.
47
81
 
48
- Total Recall currently implements these envelope types in
82
+ Total Recall implements all four canonical envelope types in
49
83
  `processOperation()`:
50
84
 
51
85
  - `operation` — full file create/replace.
52
86
  - `patch` — partial frontmatter/body merge.
53
87
  - `event` — append-only JSON event payload.
54
-
55
- The UltraChat host also models a `delete` envelope. Do not claim or use `delete`
56
- inside the Total Recall kernel until `src/core/schema.mjs` and
57
- `src/core/operation-validator.mjs` implement and test it. For memory removal, use
58
- the CLI/API forget/archive flow.
88
+ - `delete` — remove a replace-type VFS file (SSSS spec §6.2). Refuses to delete
89
+ append-type documents (`conversation`, `run`), and emits an auditable deletion
90
+ event so history is never lost. Idempotent. For *memory* removal, still prefer
91
+ the CLI/API forget/archive flow over a raw `delete` envelope.
59
92
 
60
93
  Use `dry_run: true` for preflight validation when constructing writes from model
61
94
  output.
@@ -157,7 +190,7 @@ spec and tests are updated together.
157
190
  Validate an individual SSSS Markdown file with:
158
191
 
159
192
  ```bash
160
- node .agent/skills/ssss/scripts/validate-schema.mjs <path-to-node.md>
193
+ node .agent/skills/tr-ssss/scripts/validate-schema.mjs <path-to-node.md>
161
194
  ```
162
195
 
163
196
  Run focused kernel tests after changing the operation contract, schema registry,
@@ -168,9 +201,17 @@ npx vitest run \
168
201
  src/core/schema.spec.mjs \
169
202
  src/core/operation-validator.spec.mjs \
170
203
  src/core/total-recall-memory-validator.spec.mjs \
171
- src/core/vault-cache.spec.mjs
204
+ src/core/vault-cache.spec.mjs \
205
+ src/core/ssss-conformance.bridge.spec.mjs
172
206
  ```
173
207
 
208
+ The **conformance bridge** (`src/core/ssss-conformance.bridge.spec.mjs`) runs the
209
+ canonical fixtures from `@ssss/cli` through this kernel's `processOperation` and
210
+ asserts every canonical core primitive is present in `SSSS_SCHEMAS`. It proves the
211
+ kernel implements the *same* standard as the festech and UltraChat hosts. If you
212
+ change the operation contract or the registry, keep this green; to adopt a newer
213
+ standard, bump the `@ssss/cli` pin and re-run it.
214
+
174
215
  ## Do Not
175
216
 
176
217
  - Do not write agent mutations directly to vault files.
@@ -179,8 +220,7 @@ npx vitest run \
179
220
  - Do not collapse `global`/`project` or `system`/`account`/`workspace` scope
180
221
  boundaries.
181
222
  - Do not represent copied seeded skills as canonical system primitives.
182
- - Do not claim Total Recall supports `delete` envelopes until the implementation
183
- supports them.
223
+ - Do not delete append-type documents (`conversation`, `run`); they are immutable.
184
224
  - Do not add host-specific required fields to the vendor-neutral spec unless they
185
225
  are being standardized.
186
226
 
@@ -188,7 +228,10 @@ npx vitest run \
188
228
 
189
229
  | For | Read |
190
230
  | --- | --- |
191
- | SSSS standard | `references/ssss-spec.md` |
231
+ | Upstream canon (package) | `@ssss/cli` (`v0.4.0`, github:gregiteen/ssss) |
232
+ | Canonical core registry | `@ssss/cli/registry/core.json` |
233
+ | Conformance bridge | `src/core/ssss-conformance.bridge.spec.mjs` |
234
+ | SSSS standard (local mirror) | `references/ssss-spec.md` |
192
235
  | Implemented schemas | `src/core/schema.mjs` |
193
236
  | Operation pipeline | `src/core/operation-validator.mjs` |
194
237
  | Validated memory writes | `src/core/validated-write.mjs` |
@@ -4,6 +4,7 @@ import path from 'node:path';
4
4
  import { agentDir as configAgentDir, brainDir as configBrainDir, xdgConfigHome, trBrain, trPat } from '../core/config.mjs';
5
5
  import { fileURLToPath } from 'node:url';
6
6
  import { resolveAgentDir, getBothBrains, detectProjectBrain } from './agent-dir.mjs';
7
+ import { discoverRepoSkills, projectSkillsAsCommands } from './skill-projection.mjs';
7
8
 
8
9
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
10
  // Resolve templates dir relative to this file (src/cli/ → ../../templates/)
@@ -52,24 +53,37 @@ const CLIENTS = {
52
53
  label: 'Claude Code',
53
54
  mode: 'symlink',
54
55
  target: 'CLAUDE.md',
55
- writeSlashCommands: true
56
+ writeSlashCommands: true,
57
+ // Project-scoped: repo skills are repo-specific. Claude Code discovers
58
+ // these as native skills / slash commands under <project>/.claude/skills/.
59
+ skillsProjection: { scope: 'project', dir: path.join('.claude', 'skills') }
56
60
  },
57
61
  codex: {
58
62
  label: 'Codex',
59
63
  mode: 'symlink',
60
- target: 'AGENTS.md'
64
+ target: 'AGENTS.md',
65
+ // Codex only discovers skills globally under $CODEX_HOME/skills (~/.codex/skills).
66
+ // There is no project-local skills dir, so this projection is global by necessity.
67
+ skillsProjection: { scope: 'home', dir: path.join('.codex', 'skills') }
61
68
  },
62
69
  antigravity: {
63
70
  label: 'Antigravity',
64
71
  mode: 'symlink',
65
72
  target: '.agents/rules/AGENTS.md',
66
- writeSlashCommands: true
73
+ writeSlashCommands: true,
74
+ // Antigravity CLI (the Agent Skills standard) reads project workspace skills
75
+ // from <project>/.agents/skills/ and turns each into a /name slash command.
76
+ skillsProjection: { scope: 'project', dir: path.join('.agents', 'skills') }
67
77
  },
68
78
  gemini: {
69
79
  label: 'Gemini',
70
80
  mode: 'symlink',
71
81
  target: '.agents/rules/GEMINI.md',
72
- writeSlashCommands: true
82
+ writeSlashCommands: true,
83
+ // Gemini CLI reads project workspace skills from <project>/.agents/skills/
84
+ // (the same Agent Skills location Antigravity uses) and turns each into a
85
+ // /name slash command.
86
+ skillsProjection: { scope: 'project', dir: path.join('.agents', 'skills') }
73
87
  },
74
88
  aider: {
75
89
  label: 'Aider',
@@ -293,7 +307,12 @@ function writeSymlinkProjection(cwd, preset, opts) {
293
307
  fs.rmSync(targetPath, { force: true, recursive: true });
294
308
  }
295
309
  }
296
- fs.symlinkSync('INSTRUCTIONS.md', targetPath);
310
+ // Ensure the parent dir exists (nested targets like .agents/rules/AGENTS.md)
311
+ // and point the symlink at INSTRUCTIONS.md using a path relative to the
312
+ // link's own directory, so nested projections don't dangle.
313
+ fs.mkdirSync(path.dirname(targetPath), { recursive: true });
314
+ const linkTarget = path.relative(path.dirname(targetPath), instructionsPath);
315
+ fs.symlinkSync(linkTarget, targetPath);
297
316
  return { targetPath, action: 'symlinked' };
298
317
  }
299
318
 
@@ -844,6 +863,29 @@ export default async function connect(args) {
844
863
  }
845
864
  }
846
865
 
866
+ // Project repo skills as native slash commands via the Agent Skills standard.
867
+ // Each <agentDir>/skills/<name>/SKILL.md becomes /<name> in the target IDE.
868
+ if (preset.skillsProjection) {
869
+ const skills = discoverRepoSkills(agentDir);
870
+ if (skills.length > 0) {
871
+ const destDir = preset.skillsProjection.scope === 'home'
872
+ ? path.join(os.homedir(), preset.skillsProjection.dir)
873
+ : path.join(cwd, preset.skillsProjection.dir);
874
+ const skillResults = projectSkillsAsCommands(destDir, skills, opts);
875
+ result.skill_commands = skillResults;
876
+ const fresh = skillResults.filter(r => r.action === 'linked');
877
+ if (fresh.length > 0) {
878
+ const destLabel = preset.skillsProjection.scope === 'home'
879
+ ? destDir
880
+ : (path.relative(cwd, destDir) || destDir);
881
+ result.notes.push(
882
+ ` Repo skills projected as slash commands → ${destLabel}/:\n` +
883
+ fresh.map(r => ` /${r.name}`).join('\n')
884
+ );
885
+ }
886
+ }
887
+ }
888
+
847
889
  // Record this client in the registry so `status` can report freshness
848
890
  registerClient(brainDir, opts.client, preset, result.projection?.targetPath || null);
849
891
 
package/src/cli/init.mjs CHANGED
@@ -30,6 +30,7 @@ import path from 'node:path';
30
30
  import os from 'node:os';
31
31
  import { fileURLToPath } from 'node:url';
32
32
  import { exec, spawn, spawnSync } from 'node:child_process';
33
+ import { projectSkillsForScope, detectActiveSkillTargets } from './skill-projection.mjs';
33
34
 
34
35
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
35
36
  const ROOT = path.join(__dirname, '..', '..');
@@ -83,7 +84,8 @@ function parseArgs(args) {
83
84
  domain: null,
84
85
  tunnelName: null,
85
86
  tunnelCredentials: null,
86
- yes: false
87
+ yes: false,
88
+ force: false
87
89
  };
88
90
  for (let i = 0; i < args.length; i++) {
89
91
  const arg = args[i];
@@ -97,6 +99,7 @@ function parseArgs(args) {
97
99
  else if (arg === '--tunnel-name') opts.tunnelName = args[++i];
98
100
  else if (arg === '--tunnel-credentials') opts.tunnelCredentials = args[++i];
99
101
  else if (arg === '--yes' || arg === '-y') opts.yes = true;
102
+ else if (arg === '--force') opts.force = true;
100
103
  }
101
104
  return opts;
102
105
  }
@@ -474,7 +477,7 @@ export default async function init(args) {
474
477
  }
475
478
 
476
479
  // ── Symlink nested brain skills to top-level .agent/skills/ ──
477
- // Skills inside the brain (e.g. .agent/skills/total-recall/skills/ssss/) are
480
+ // Skills inside the brain (e.g. .agent/skills/total-recall/skills/tr-ssss/) are
478
481
  // invisible to IDEs because they only scan .agent/skills/<name>/ one level
479
482
  // deep. Create symlinks so they appear as slash commands.
480
483
  const nestedSkillsDir = path.join(brainDir, 'skills');
@@ -498,6 +501,43 @@ export default async function init(args) {
498
501
  }
499
502
  }
500
503
 
504
+ // ── Step 3.7: Project skills as slash commands into the IDEs in use ──
505
+ // Scope matches the brain: `init --project` projects PROJECT skills into the
506
+ // repo's IDE skill dirs for IDEs actually used here (.claude/, .agents/, or
507
+ // the current process); `init` projects GLOBAL skills into installed IDEs'
508
+ // global skill dirs. Codex (global-only) is opt-in for project skills.
509
+ const skillScope = isProject ? 'project' : 'global';
510
+ logStep('3.7/4', `Projecting ${skillScope} skills as slash commands (IDEs in use)`);
511
+ if (opts.dryRun) {
512
+ const targets = detectActiveSkillTargets({ scope: skillScope, cwd });
513
+ for (const t of targets.filter(t => t.supported)) {
514
+ const destLabel = t.destDir ? path.relative(cwd, t.destDir) || t.destDir : '(n/a)';
515
+ log(` ${t.active ? 'would wire' : 'available (opt-in)'}: ${t.label} → ${destLabel}/`);
516
+ }
517
+ } else {
518
+ try {
519
+ const { skills, wired, available } = projectSkillsForScope({
520
+ scope: skillScope, cwd, agentDir, opts: { force: opts.force }
521
+ });
522
+ if (skills.length === 0) {
523
+ log(' No skills found yet — author one under .agent/skills/<name>/SKILL.md');
524
+ } else if (wired.length === 0) {
525
+ log(` No in-use IDE detected for ${skillScope} skills — run \`npx total-recall connect <ide>\` to wire them.`);
526
+ } else {
527
+ for (const t of wired) {
528
+ const n = t.results.filter(r => ['linked', 'exists', 'source'].includes(r.action)).length;
529
+ logOk(`${t.label}: ${n} skill(s) → ${path.relative(cwd, t.destDir) || t.destDir}/`);
530
+ }
531
+ log(` Slash commands: ${skills.map(s => '/' + s.name).join(', ')}`);
532
+ if (available.length > 0) {
533
+ log(` Also available (opt-in): ${available.map(t => t.clients.join('/')).join(', ')} — \`npx total-recall connect <ide>\``);
534
+ }
535
+ }
536
+ } catch (err) {
537
+ logWarn(`Could not project skills into IDEs: ${err.message}`);
538
+ }
539
+ }
540
+
501
541
  // ── Step 4: Run compile to inject memory block into existing IDE files ──
502
542
  logStep('4/4', 'Compiling vault and injecting into IDE instruction files');
503
543