create-claude-cabinet 0.7.5 → 0.8.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/lib/cli.js +26 -1
- package/lib/omega-setup.js +153 -0
- package/lib/settings-merge.js +36 -3
- package/package.json +1 -1
- package/templates/hooks/memory-post-compact.sh +43 -0
- package/templates/hooks/memory-session-start.sh +59 -0
- package/templates/rules/memory-capture.md +57 -0
- package/templates/scripts/__pycache__/cabinet-memory-adapter.cpython-313.pyc +0 -0
- package/templates/scripts/cabinet-memory-adapter.py +259 -0
- package/templates/skills/cabinet-cc-health/SKILL.md +46 -1
- package/templates/skills/cabinet-historian/SKILL.md +26 -0
- package/templates/skills/debrief/SKILL.md +20 -0
- package/templates/skills/debrief/phases/record-lessons.md +29 -30
- package/templates/skills/orient/phases/context.md +32 -0
package/lib/cli.js
CHANGED
|
@@ -7,6 +7,7 @@ const { copyTemplates } = require('./copy');
|
|
|
7
7
|
const { mergeSettings } = require('./settings-merge');
|
|
8
8
|
const { create: createMetadata, read: readMetadata } = require('./metadata');
|
|
9
9
|
const { setupDb } = require('./db-setup');
|
|
10
|
+
const { setupOmega } = require('./omega-setup');
|
|
10
11
|
const { reset } = require('./reset');
|
|
11
12
|
|
|
12
13
|
const VERSION = require('../package.json').version;
|
|
@@ -95,6 +96,15 @@ const MODULES = {
|
|
|
95
96
|
lean: false,
|
|
96
97
|
templates: ['skills/validate'],
|
|
97
98
|
},
|
|
99
|
+
'memory': {
|
|
100
|
+
name: 'Semantic Memory (omega)',
|
|
101
|
+
description: 'Rich session memory via omega-memory. Captures decisions, reasoning chains, and lessons between sessions. Requires Python 3.11+.',
|
|
102
|
+
mandatory: false,
|
|
103
|
+
default: true,
|
|
104
|
+
lean: false,
|
|
105
|
+
needsOmega: true,
|
|
106
|
+
templates: ['hooks/memory-session-start.sh', 'hooks/memory-post-compact.sh', 'scripts/cabinet-memory-adapter.py', 'rules/memory-capture.md'],
|
|
107
|
+
},
|
|
98
108
|
};
|
|
99
109
|
|
|
100
110
|
// Signals that a directory contains a real project (not just empty)
|
|
@@ -532,7 +542,8 @@ async function run() {
|
|
|
532
542
|
|
|
533
543
|
// --- Merge hooks into settings.json ---
|
|
534
544
|
if (selectedModules.includes('hooks') && !flags.dryRun) {
|
|
535
|
-
const
|
|
545
|
+
const includeMemory = selectedModules.includes('memory');
|
|
546
|
+
const settingsPath = mergeSettings(projectDir, { includeDb, includeMemory });
|
|
536
547
|
console.log(` ⚙️ Merged hooks into ${path.relative(projectDir, settingsPath)}`);
|
|
537
548
|
}
|
|
538
549
|
|
|
@@ -547,6 +558,20 @@ async function run() {
|
|
|
547
558
|
}
|
|
548
559
|
}
|
|
549
560
|
|
|
561
|
+
// --- Set up omega memory ---
|
|
562
|
+
const needsOmega = selectedModules.some(m => MODULES[m].needsOmega);
|
|
563
|
+
if (needsOmega && !flags.dryRun) {
|
|
564
|
+
try {
|
|
565
|
+
console.log('');
|
|
566
|
+
const omegaResults = setupOmega();
|
|
567
|
+
for (const r of omegaResults) console.log(` 🧠 ${r}`);
|
|
568
|
+
} catch (err) {
|
|
569
|
+
console.log(` ⚠ Omega memory setup skipped: ${err.message}`);
|
|
570
|
+
console.log(' Memory module will be inactive until Python 3.11+ is available.');
|
|
571
|
+
console.log(' Re-run the installer after installing Python to enable it.');
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
550
575
|
// --- Clean up files removed upstream ---
|
|
551
576
|
// Phase files are excluded from the manifest (they're user-customized),
|
|
552
577
|
// so skip them during cleanup even if they were in the old manifest.
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
const { execSync } = require('child_process');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
|
|
6
|
+
const OMEGA_HOME = path.join(os.homedir(), '.claude-cabinet');
|
|
7
|
+
const VENV_DIR = path.join(OMEGA_HOME, 'omega-venv');
|
|
8
|
+
const VENV_PYTHON = path.join(VENV_DIR, 'bin', 'python3');
|
|
9
|
+
|
|
10
|
+
// Ordered by preference: stable Cellar symlinks first, newest Python first.
|
|
11
|
+
// Apple Silicon paths, then Intel Mac paths, then PATH fallback.
|
|
12
|
+
const PYTHON_CANDIDATES = [
|
|
13
|
+
'/opt/homebrew/opt/python@3.14/bin/python3.14',
|
|
14
|
+
'/opt/homebrew/opt/python@3.13/bin/python3.13',
|
|
15
|
+
'/opt/homebrew/opt/python@3.12/bin/python3.12',
|
|
16
|
+
'/opt/homebrew/opt/python@3.11/bin/python3.11',
|
|
17
|
+
'/usr/local/opt/python@3.14/bin/python3.14',
|
|
18
|
+
'/usr/local/opt/python@3.13/bin/python3.13',
|
|
19
|
+
'/usr/local/opt/python@3.12/bin/python3.12',
|
|
20
|
+
'/usr/local/opt/python@3.11/bin/python3.11',
|
|
21
|
+
'/opt/homebrew/bin/python3',
|
|
22
|
+
'/usr/local/bin/python3',
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Find a Python >= 3.11 on this system.
|
|
27
|
+
* Returns the absolute path or null if none found.
|
|
28
|
+
*/
|
|
29
|
+
function findPython() {
|
|
30
|
+
for (const candidate of PYTHON_CANDIDATES) {
|
|
31
|
+
if (!fs.existsSync(candidate)) continue;
|
|
32
|
+
try {
|
|
33
|
+
const version = execSync(`"${candidate}" --version 2>&1`, { encoding: 'utf8' }).trim();
|
|
34
|
+
const match = version.match(/Python (\d+)\.(\d+)/);
|
|
35
|
+
if (match) {
|
|
36
|
+
const major = parseInt(match[1], 10);
|
|
37
|
+
const minor = parseInt(match[2], 10);
|
|
38
|
+
if (major === 3 && minor >= 11) return candidate;
|
|
39
|
+
}
|
|
40
|
+
} catch { /* skip */ }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Last resort: bare python3 on PATH
|
|
44
|
+
try {
|
|
45
|
+
const version = execSync('python3 --version 2>&1', { encoding: 'utf8' }).trim();
|
|
46
|
+
const match = version.match(/Python (\d+)\.(\d+)/);
|
|
47
|
+
if (match) {
|
|
48
|
+
const major = parseInt(match[1], 10);
|
|
49
|
+
const minor = parseInt(match[2], 10);
|
|
50
|
+
if (major === 3 && minor >= 11) {
|
|
51
|
+
const which = execSync('which python3', { encoding: 'utf8' }).trim();
|
|
52
|
+
return which;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
} catch { /* skip */ }
|
|
56
|
+
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Set up the omega-memory venv and download the embedding model.
|
|
62
|
+
*
|
|
63
|
+
* Steps:
|
|
64
|
+
* 1. Find Python 3.11+
|
|
65
|
+
* 2. Create venv at ~/.claude-cabinet/omega-venv/
|
|
66
|
+
* 3. pip install omega-memory
|
|
67
|
+
* 4. Run omega setup --download-model (downloads ONNX model at install time)
|
|
68
|
+
*
|
|
69
|
+
* Returns an array of status messages (like db-setup.js).
|
|
70
|
+
* Throws on failure.
|
|
71
|
+
*/
|
|
72
|
+
function setupOmega() {
|
|
73
|
+
const results = [];
|
|
74
|
+
|
|
75
|
+
// 1. Find Python
|
|
76
|
+
const pythonPath = findPython();
|
|
77
|
+
if (!pythonPath) {
|
|
78
|
+
throw new Error(
|
|
79
|
+
'Python 3.11+ not found. Install via Homebrew: brew install python@3.13\n' +
|
|
80
|
+
' On Debian/Ubuntu: sudo apt install python3.13 python3.13-venv'
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
results.push(`Found Python: ${pythonPath}`);
|
|
84
|
+
|
|
85
|
+
// 2. Check ensurepip (Debian/Ubuntu strips it)
|
|
86
|
+
try {
|
|
87
|
+
execSync(`"${pythonPath}" -c "import ensurepip"`, { stdio: 'pipe' });
|
|
88
|
+
} catch {
|
|
89
|
+
const version = execSync(`"${pythonPath}" --version`, { encoding: 'utf8' }).trim();
|
|
90
|
+
const match = version.match(/Python (\d+)\.(\d+)/);
|
|
91
|
+
const pkg = match ? `python${match[1]}.${match[2]}-venv` : 'python3-venv';
|
|
92
|
+
throw new Error(
|
|
93
|
+
`Python venv module not found. On Debian/Ubuntu, install it:\n` +
|
|
94
|
+
` sudo apt install ${pkg}`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// 3. Create or verify venv
|
|
99
|
+
if (!fs.existsSync(OMEGA_HOME)) {
|
|
100
|
+
fs.mkdirSync(OMEGA_HOME, { recursive: true });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (fs.existsSync(VENV_PYTHON)) {
|
|
104
|
+
// Venv already exists — verify it works
|
|
105
|
+
try {
|
|
106
|
+
execSync(`"${VENV_PYTHON}" -c "import omega"`, { stdio: 'pipe' });
|
|
107
|
+
results.push('Existing omega venv is valid');
|
|
108
|
+
return results;
|
|
109
|
+
} catch {
|
|
110
|
+
// Venv is broken — nuke and rebuild (D5)
|
|
111
|
+
results.push('Existing venv broken, rebuilding...');
|
|
112
|
+
fs.rmSync(VENV_DIR, { recursive: true, force: true });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
console.log(' Creating Python venv...');
|
|
117
|
+
execSync(`"${pythonPath}" -m venv "${VENV_DIR}"`, { stdio: 'pipe' });
|
|
118
|
+
results.push('Created venv at ~/.claude-cabinet/omega-venv/');
|
|
119
|
+
|
|
120
|
+
// 4. Install omega-memory
|
|
121
|
+
console.log(' Installing omega-memory...');
|
|
122
|
+
execSync(`"${VENV_PYTHON}" -m pip install --quiet omega-memory`, {
|
|
123
|
+
stdio: 'pipe',
|
|
124
|
+
timeout: 120000,
|
|
125
|
+
});
|
|
126
|
+
results.push('Installed omega-memory');
|
|
127
|
+
|
|
128
|
+
// 5. Download embedding model at install time (D4)
|
|
129
|
+
console.log(' Downloading embedding model...');
|
|
130
|
+
execSync(`"${VENV_PYTHON}" -m omega.cli setup --download-model`, {
|
|
131
|
+
stdio: 'pipe',
|
|
132
|
+
timeout: 120000,
|
|
133
|
+
env: { ...process.env, OMEGA_TELEMETRY: '0' },
|
|
134
|
+
});
|
|
135
|
+
results.push('Downloaded ONNX embedding model (bge-small-en-v1.5)');
|
|
136
|
+
|
|
137
|
+
return results;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Check if omega is already set up and functional.
|
|
142
|
+
*/
|
|
143
|
+
function isOmegaReady() {
|
|
144
|
+
if (!fs.existsSync(VENV_PYTHON)) return false;
|
|
145
|
+
try {
|
|
146
|
+
execSync(`"${VENV_PYTHON}" -c "import omega"`, { stdio: 'pipe' });
|
|
147
|
+
return true;
|
|
148
|
+
} catch {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
module.exports = { setupOmega, isOmegaReady, findPython, VENV_DIR, VENV_PYTHON };
|
package/lib/settings-merge.js
CHANGED
|
@@ -1,6 +1,31 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
|
|
4
|
+
const MEMORY_HOOKS = {
|
|
5
|
+
SessionStart: [
|
|
6
|
+
{
|
|
7
|
+
matcher: 'startup|resume|compact',
|
|
8
|
+
hooks: [
|
|
9
|
+
{
|
|
10
|
+
type: 'command',
|
|
11
|
+
command: '.claude/hooks/memory-session-start.sh',
|
|
12
|
+
},
|
|
13
|
+
],
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
PostCompact: [
|
|
17
|
+
{
|
|
18
|
+
matcher: '',
|
|
19
|
+
hooks: [
|
|
20
|
+
{
|
|
21
|
+
type: 'command',
|
|
22
|
+
command: '.claude/hooks/memory-post-compact.sh',
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
};
|
|
28
|
+
|
|
4
29
|
const DEFAULT_HOOKS = {
|
|
5
30
|
PreToolUse: [
|
|
6
31
|
{
|
|
@@ -50,7 +75,7 @@ const DEFAULT_HOOKS = {
|
|
|
50
75
|
* Merge PIB hooks into the project's .claude/settings.json.
|
|
51
76
|
* Creates the file if it doesn't exist. Preserves existing hooks.
|
|
52
77
|
*/
|
|
53
|
-
function mergeSettings(projectDir, { includeDb = true } = {}) {
|
|
78
|
+
function mergeSettings(projectDir, { includeDb = true, includeMemory = false } = {}) {
|
|
54
79
|
const settingsDir = path.join(projectDir, '.claude');
|
|
55
80
|
const settingsPath = path.join(settingsDir, 'settings.json');
|
|
56
81
|
|
|
@@ -65,8 +90,16 @@ function mergeSettings(projectDir, { includeDb = true } = {}) {
|
|
|
65
90
|
|
|
66
91
|
if (!settings.hooks) settings.hooks = {};
|
|
67
92
|
|
|
93
|
+
// Build the complete hook set for this install
|
|
94
|
+
const allHooks = { ...DEFAULT_HOOKS };
|
|
95
|
+
if (includeMemory) {
|
|
96
|
+
for (const [event, hooks] of Object.entries(MEMORY_HOOKS)) {
|
|
97
|
+
allHooks[event] = [...(allHooks[event] || []), ...hooks];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
68
101
|
// Merge each hook event type
|
|
69
|
-
for (const [event, newHooks] of Object.entries(
|
|
102
|
+
for (const [event, newHooks] of Object.entries(allHooks)) {
|
|
70
103
|
if (!settings.hooks[event]) {
|
|
71
104
|
settings.hooks[event] = newHooks;
|
|
72
105
|
} else {
|
|
@@ -90,4 +123,4 @@ function mergeSettings(projectDir, { includeDb = true } = {}) {
|
|
|
90
123
|
return settingsPath;
|
|
91
124
|
}
|
|
92
125
|
|
|
93
|
-
module.exports = { mergeSettings, DEFAULT_HOOKS };
|
|
126
|
+
module.exports = { mergeSettings, DEFAULT_HOOKS, MEMORY_HOOKS };
|
package/package.json
CHANGED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# PostCompact hook — capture session context before it's lost
|
|
3
|
+
#
|
|
4
|
+
# Fires on: manual (/compact) and auto (context limit) compaction
|
|
5
|
+
# Output: read-only (observability only, 10K char cap)
|
|
6
|
+
# Design: D1 (absolute venv path), D2 (never block), D3 (graceful degradation)
|
|
7
|
+
|
|
8
|
+
VENV_PYTHON="$HOME/.claude-cabinet/omega-venv/bin/python3"
|
|
9
|
+
ADAPTER="scripts/cabinet-memory-adapter.py"
|
|
10
|
+
|
|
11
|
+
# D3: graceful degradation — if venv or adapter missing, exit silently
|
|
12
|
+
if [ ! -x "$VENV_PYTHON" ] || [ ! -f "$ADAPTER" ]; then
|
|
13
|
+
exit 0
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
# Read hook input from stdin (includes compact_summary)
|
|
17
|
+
INPUT=$(cat)
|
|
18
|
+
|
|
19
|
+
# Call adapter — pipe hook input as stdin for capture
|
|
20
|
+
RESULT=$(echo "$INPUT" | "$VENV_PYTHON" "$ADAPTER" capture 2>/dev/null)
|
|
21
|
+
|
|
22
|
+
# Log result for observability (PostCompact output is read-only)
|
|
23
|
+
STORED=$(echo "$RESULT" | "$VENV_PYTHON" -c "
|
|
24
|
+
import sys, json
|
|
25
|
+
try:
|
|
26
|
+
data = json.load(sys.stdin)
|
|
27
|
+
if data.get('ok'):
|
|
28
|
+
count = data.get('stored', 0)
|
|
29
|
+
if count:
|
|
30
|
+
print(f'cabinet-memory: captured {count} memories from compaction')
|
|
31
|
+
else:
|
|
32
|
+
print('cabinet-memory: no memories captured (nothing noteworthy)')
|
|
33
|
+
else:
|
|
34
|
+
print(f'cabinet-memory: {data.get(\"error\", \"unknown error\")}')
|
|
35
|
+
except:
|
|
36
|
+
pass
|
|
37
|
+
" 2>/dev/null)
|
|
38
|
+
|
|
39
|
+
if [ -n "$STORED" ]; then
|
|
40
|
+
echo "$STORED"
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
exit 0
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# SessionStart hook — surface relevant memories via omega
|
|
3
|
+
#
|
|
4
|
+
# Fires on: startup, resume, compact (not clear — fresh context)
|
|
5
|
+
# Output: relevant memories injected into session context
|
|
6
|
+
# Design: D1 (absolute venv path), D2 (never block), D3 (graceful degradation)
|
|
7
|
+
|
|
8
|
+
VENV_PYTHON="$HOME/.claude-cabinet/omega-venv/bin/python3"
|
|
9
|
+
ADAPTER="scripts/cabinet-memory-adapter.py"
|
|
10
|
+
|
|
11
|
+
# D3: graceful degradation — if venv or adapter missing, warn but don't block
|
|
12
|
+
if [ ! -x "$VENV_PYTHON" ] || [ ! -f "$ADAPTER" ]; then
|
|
13
|
+
echo ""
|
|
14
|
+
echo "**Note:** Memory module is installed but omega is not available."
|
|
15
|
+
echo "Semantic memory (decisions, lessons, preferences) is not being captured or recalled."
|
|
16
|
+
echo "Run \`npx create-claude-cabinet\` to set up the omega venv."
|
|
17
|
+
exit 0
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
# Read hook input from stdin
|
|
21
|
+
INPUT=$(cat)
|
|
22
|
+
|
|
23
|
+
# Extract source field to skip /clear (fresh context, no memories needed)
|
|
24
|
+
SOURCE=$(echo "$INPUT" | "$VENV_PYTHON" -c "
|
|
25
|
+
import sys, json
|
|
26
|
+
try:
|
|
27
|
+
data = json.load(sys.stdin)
|
|
28
|
+
print(data.get('source', 'startup'))
|
|
29
|
+
except:
|
|
30
|
+
print('startup')
|
|
31
|
+
" 2>/dev/null)
|
|
32
|
+
|
|
33
|
+
if [ "$SOURCE" = "clear" ]; then
|
|
34
|
+
exit 0
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# Call adapter — pipe hook input as stdin
|
|
38
|
+
RESULT=$(echo "$INPUT" | "$VENV_PYTHON" "$ADAPTER" welcome 2>/dev/null)
|
|
39
|
+
|
|
40
|
+
# Extract context from result
|
|
41
|
+
CONTEXT=$(echo "$RESULT" | "$VENV_PYTHON" -c "
|
|
42
|
+
import sys, json
|
|
43
|
+
try:
|
|
44
|
+
data = json.load(sys.stdin)
|
|
45
|
+
if data.get('ok') and data.get('context'):
|
|
46
|
+
print(data['context'])
|
|
47
|
+
except:
|
|
48
|
+
pass
|
|
49
|
+
" 2>/dev/null)
|
|
50
|
+
|
|
51
|
+
# Output context to stdout — SessionStart hook stdout becomes session context
|
|
52
|
+
if [ -n "$CONTEXT" ]; then
|
|
53
|
+
echo ""
|
|
54
|
+
echo "## Recalled Memories (omega)"
|
|
55
|
+
echo ""
|
|
56
|
+
echo "$CONTEXT"
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
exit 0
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Memory Capture Rules
|
|
2
|
+
|
|
3
|
+
When omega memory is active (check: `~/.claude-cabinet/omega-venv/bin/python3`
|
|
4
|
+
exists and `scripts/cabinet-memory-adapter.py` exists), these rules govern
|
|
5
|
+
what gets captured and when.
|
|
6
|
+
|
|
7
|
+
## During Sessions — What to Capture
|
|
8
|
+
|
|
9
|
+
Capture to omega when you observe any of these during a session:
|
|
10
|
+
|
|
11
|
+
**Decisions with reasoning.** When the user makes a non-obvious choice
|
|
12
|
+
(architecture, naming, tradeoffs, tool selection), capture the decision
|
|
13
|
+
AND the reasoning. "Chose SQLite over Postgres because single-user,
|
|
14
|
+
no server dependency" — not just "uses SQLite."
|
|
15
|
+
|
|
16
|
+
**Discovered constraints.** When something that seemed possible turns
|
|
17
|
+
out to have a limitation, gotcha, or prerequisite. "Python venv on
|
|
18
|
+
Debian requires separate python3-venv package" — the kind of thing
|
|
19
|
+
that wastes 30 minutes if you don't know it.
|
|
20
|
+
|
|
21
|
+
**User preferences revealed through correction.** When the user says
|
|
22
|
+
"no, not like that" or redirects your approach, capture what they
|
|
23
|
+
actually want. "User prefers single bundled PRs for refactors, not
|
|
24
|
+
many small ones."
|
|
25
|
+
|
|
26
|
+
**Pattern establishment.** When a convention is established for the
|
|
27
|
+
first time — naming pattern, file organization, workflow step. Not
|
|
28
|
+
the convention itself (that's in the code), but that it was a
|
|
29
|
+
deliberate choice.
|
|
30
|
+
|
|
31
|
+
## How to Capture
|
|
32
|
+
|
|
33
|
+
Use the adapter — never call omega directly from shell:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
echo '{"text": "the memory", "type": "decision"}' | \
|
|
37
|
+
~/.claude-cabinet/omega-venv/bin/python3 scripts/cabinet-memory-adapter.py store
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Memory types: `decision`, `lesson`, `preference`, `constraint`, `pattern`
|
|
41
|
+
|
|
42
|
+
## What NOT to Capture
|
|
43
|
+
|
|
44
|
+
- Code patterns visible by reading current files
|
|
45
|
+
- Git history (use `git log`)
|
|
46
|
+
- Anything already in CLAUDE.md or briefing files
|
|
47
|
+
- Ephemeral debugging details
|
|
48
|
+
- Information that changes frequently (use state files instead)
|
|
49
|
+
|
|
50
|
+
## Capture Cadence
|
|
51
|
+
|
|
52
|
+
Do NOT capture after every interaction. Capture when something worth
|
|
53
|
+
remembering actually happens. Most messages in a session produce nothing
|
|
54
|
+
worth storing. A typical session might generate 0-3 memories.
|
|
55
|
+
|
|
56
|
+
Over-capturing degrades retrieval quality. When in doubt, don't capture.
|
|
57
|
+
The debrief sweep catches anything important that was missed.
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Cabinet Memory Adapter — single Python file wrapping all omega interaction.
|
|
4
|
+
|
|
5
|
+
Called by hook scripts via the venv Python. All omega calls go through here.
|
|
6
|
+
Designed for D2 (never block Claude Code) and D3 (graceful degradation).
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
cabinet-memory-adapter.py <command> [options]
|
|
10
|
+
|
|
11
|
+
Commands:
|
|
12
|
+
welcome Surface relevant memories for session start
|
|
13
|
+
capture Store a memory from hook input (PostCompact)
|
|
14
|
+
store Store a memory directly (called by debrief)
|
|
15
|
+
query Query memories by text
|
|
16
|
+
status Check omega health
|
|
17
|
+
|
|
18
|
+
All commands read JSON from stdin when applicable.
|
|
19
|
+
All commands output JSON to stdout.
|
|
20
|
+
All commands exit 0 even on failure (D2: never block).
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
import json
|
|
24
|
+
import os
|
|
25
|
+
import sys
|
|
26
|
+
|
|
27
|
+
# Disable omega telemetry (PB2: opt-in only, we opt out)
|
|
28
|
+
os.environ["OMEGA_TELEMETRY"] = "0"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _output(data):
|
|
32
|
+
"""Write JSON to stdout and exit cleanly."""
|
|
33
|
+
print(json.dumps(data))
|
|
34
|
+
sys.exit(0)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _error(msg):
|
|
38
|
+
"""Log error to stderr, output empty result, exit 0 (D2: never block)."""
|
|
39
|
+
print(f"cabinet-memory: {msg}", file=sys.stderr)
|
|
40
|
+
_output({"ok": False, "error": msg})
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _read_stdin():
|
|
44
|
+
"""Read JSON from stdin, return dict or empty dict on failure."""
|
|
45
|
+
try:
|
|
46
|
+
return json.load(sys.stdin)
|
|
47
|
+
except Exception:
|
|
48
|
+
return {}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _import_omega():
|
|
52
|
+
"""Import omega, returning the module or None on failure."""
|
|
53
|
+
try:
|
|
54
|
+
import omega
|
|
55
|
+
return omega
|
|
56
|
+
except ImportError:
|
|
57
|
+
return None
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def cmd_welcome():
|
|
61
|
+
"""Surface relevant memories for session start.
|
|
62
|
+
|
|
63
|
+
Reads session context from stdin (session_id, cwd, source).
|
|
64
|
+
Calls omega.welcome() to get relevant memories.
|
|
65
|
+
Outputs memories as context text for SessionStart hook stdout.
|
|
66
|
+
"""
|
|
67
|
+
data = _read_stdin()
|
|
68
|
+
omega = _import_omega()
|
|
69
|
+
if not omega:
|
|
70
|
+
_error("omega not available")
|
|
71
|
+
return
|
|
72
|
+
|
|
73
|
+
try:
|
|
74
|
+
cwd = data.get("cwd", os.getcwd())
|
|
75
|
+
project_name = os.path.basename(cwd)
|
|
76
|
+
|
|
77
|
+
result = omega.welcome(project=project_name)
|
|
78
|
+
if not result:
|
|
79
|
+
_output({"ok": True, "context": ""})
|
|
80
|
+
return
|
|
81
|
+
|
|
82
|
+
# welcome() returns a dict with memory count, recent memories, etc.
|
|
83
|
+
if isinstance(result, dict):
|
|
84
|
+
context = (
|
|
85
|
+
result.get("observation_prefix", "")
|
|
86
|
+
or result.get("summary", "")
|
|
87
|
+
or result.get("context", "")
|
|
88
|
+
)
|
|
89
|
+
if not context and result.get("memory_count", 0) == 0:
|
|
90
|
+
_output({"ok": True, "context": ""})
|
|
91
|
+
return
|
|
92
|
+
if not context:
|
|
93
|
+
context = json.dumps(result, indent=2)
|
|
94
|
+
_output({"ok": True, "context": context})
|
|
95
|
+
elif isinstance(result, str):
|
|
96
|
+
_output({"ok": True, "context": result})
|
|
97
|
+
else:
|
|
98
|
+
_output({"ok": True, "context": str(result)})
|
|
99
|
+
except Exception as e:
|
|
100
|
+
_error(f"welcome failed: {e}")
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def cmd_capture():
|
|
104
|
+
"""Capture context from PostCompact summary.
|
|
105
|
+
|
|
106
|
+
Reads compact_summary from stdin.
|
|
107
|
+
Extracts key decisions, lessons, and reasoning chains.
|
|
108
|
+
Stores them in omega.
|
|
109
|
+
"""
|
|
110
|
+
data = _read_stdin()
|
|
111
|
+
omega = _import_omega()
|
|
112
|
+
if not omega:
|
|
113
|
+
_error("omega not available")
|
|
114
|
+
return
|
|
115
|
+
|
|
116
|
+
summary = data.get("compact_summary", "")
|
|
117
|
+
if not summary:
|
|
118
|
+
_output({"ok": True, "stored": 0, "reason": "no summary"})
|
|
119
|
+
return
|
|
120
|
+
|
|
121
|
+
session_id = data.get("session_id", "unknown")
|
|
122
|
+
cwd = data.get("cwd", os.getcwd())
|
|
123
|
+
project_name = os.path.basename(cwd)
|
|
124
|
+
|
|
125
|
+
try:
|
|
126
|
+
result = omega.auto_capture(
|
|
127
|
+
summary,
|
|
128
|
+
event_type="compaction",
|
|
129
|
+
session_id=session_id,
|
|
130
|
+
project=project_name,
|
|
131
|
+
)
|
|
132
|
+
count = 0
|
|
133
|
+
if isinstance(result, dict):
|
|
134
|
+
count = result.get("stored", 0)
|
|
135
|
+
elif isinstance(result, (list, tuple)):
|
|
136
|
+
count = len(result)
|
|
137
|
+
|
|
138
|
+
_output({"ok": True, "stored": count})
|
|
139
|
+
except Exception as e:
|
|
140
|
+
_error(f"capture failed: {e}")
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def cmd_store():
|
|
144
|
+
"""Store a memory directly.
|
|
145
|
+
|
|
146
|
+
Reads JSON from stdin with fields:
|
|
147
|
+
text: the memory content (required)
|
|
148
|
+
type: event_type for omega (default: "lesson")
|
|
149
|
+
tags: list of tags (stored in metadata, optional)
|
|
150
|
+
"""
|
|
151
|
+
data = _read_stdin()
|
|
152
|
+
omega = _import_omega()
|
|
153
|
+
if not omega:
|
|
154
|
+
_error("omega not available")
|
|
155
|
+
return
|
|
156
|
+
|
|
157
|
+
text = data.get("text", "")
|
|
158
|
+
if not text:
|
|
159
|
+
_error("no text provided")
|
|
160
|
+
return
|
|
161
|
+
|
|
162
|
+
try:
|
|
163
|
+
event_type = data.get("type", "lesson")
|
|
164
|
+
metadata = {}
|
|
165
|
+
if data.get("tags"):
|
|
166
|
+
metadata["tags"] = data["tags"]
|
|
167
|
+
result = omega.store(
|
|
168
|
+
text,
|
|
169
|
+
event_type=event_type,
|
|
170
|
+
metadata=metadata if metadata else None,
|
|
171
|
+
)
|
|
172
|
+
_output({"ok": True, "id": result if isinstance(result, str) else None})
|
|
173
|
+
except Exception as e:
|
|
174
|
+
_error(f"store failed: {e}")
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def cmd_query():
|
|
178
|
+
"""Query memories by text.
|
|
179
|
+
|
|
180
|
+
Reads JSON from stdin with fields:
|
|
181
|
+
text: the query text (required)
|
|
182
|
+
limit: max results (default: 5)
|
|
183
|
+
"""
|
|
184
|
+
data = _read_stdin()
|
|
185
|
+
omega = _import_omega()
|
|
186
|
+
if not omega:
|
|
187
|
+
_error("omega not available")
|
|
188
|
+
return
|
|
189
|
+
|
|
190
|
+
text = data.get("text", "")
|
|
191
|
+
if not text:
|
|
192
|
+
_error("no query text provided")
|
|
193
|
+
return
|
|
194
|
+
|
|
195
|
+
try:
|
|
196
|
+
limit = data.get("limit", 5)
|
|
197
|
+
event_type = data.get("type")
|
|
198
|
+
results = omega.query(
|
|
199
|
+
text,
|
|
200
|
+
limit=limit,
|
|
201
|
+
event_type=event_type,
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
# query() returns a formatted string of results
|
|
205
|
+
if isinstance(results, str):
|
|
206
|
+
_output({"ok": True, "results": results})
|
|
207
|
+
elif isinstance(results, (list, tuple)):
|
|
208
|
+
memories = []
|
|
209
|
+
for r in results:
|
|
210
|
+
if isinstance(r, dict):
|
|
211
|
+
memories.append({
|
|
212
|
+
"text": r.get("content", r.get("text", str(r))),
|
|
213
|
+
"type": r.get("event_type", "unknown"),
|
|
214
|
+
"score": r.get("score", 0),
|
|
215
|
+
})
|
|
216
|
+
else:
|
|
217
|
+
memories.append({"text": str(r)})
|
|
218
|
+
_output({"ok": True, "memories": memories})
|
|
219
|
+
else:
|
|
220
|
+
_output({"ok": True, "results": str(results)})
|
|
221
|
+
except Exception as e:
|
|
222
|
+
_error(f"query failed: {e}")
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def cmd_status():
|
|
226
|
+
"""Check omega health status."""
|
|
227
|
+
omega = _import_omega()
|
|
228
|
+
if not omega:
|
|
229
|
+
_output({"ok": False, "status": "omega not available"})
|
|
230
|
+
return
|
|
231
|
+
|
|
232
|
+
try:
|
|
233
|
+
result = omega.status()
|
|
234
|
+
if isinstance(result, dict):
|
|
235
|
+
_output({"ok": True, **result})
|
|
236
|
+
else:
|
|
237
|
+
_output({"ok": True, "status": str(result)})
|
|
238
|
+
except Exception as e:
|
|
239
|
+
_error(f"status failed: {e}")
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
COMMANDS = {
|
|
243
|
+
"welcome": cmd_welcome,
|
|
244
|
+
"capture": cmd_capture,
|
|
245
|
+
"store": cmd_store,
|
|
246
|
+
"query": cmd_query,
|
|
247
|
+
"status": cmd_status,
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if __name__ == "__main__":
|
|
251
|
+
if len(sys.argv) < 2 or sys.argv[1] not in COMMANDS:
|
|
252
|
+
cmds = ", ".join(COMMANDS.keys())
|
|
253
|
+
_error(f"usage: cabinet-memory-adapter.py <{cmds}>")
|
|
254
|
+
else:
|
|
255
|
+
try:
|
|
256
|
+
COMMANDS[sys.argv[1]]()
|
|
257
|
+
except Exception as e:
|
|
258
|
+
# Outermost catch — D2: never block, never crash
|
|
259
|
+
_error(f"unexpected error: {e}")
|
|
@@ -384,7 +384,52 @@ directory structure:
|
|
|
384
384
|
and the expected state. These are typically easy fixes but indicate an
|
|
385
385
|
incomplete migration.
|
|
386
386
|
|
|
387
|
-
### 8.
|
|
387
|
+
### 8. Memory System Health
|
|
388
|
+
|
|
389
|
+
If the memory module is installed (check `.ccrc.json` modules list for
|
|
390
|
+
`"memory"`), verify the omega memory infrastructure:
|
|
391
|
+
|
|
392
|
+
- **Venv integrity.** Does `~/.claude-cabinet/omega-venv/bin/python3`
|
|
393
|
+
exist? Can it import omega? Run:
|
|
394
|
+
```bash
|
|
395
|
+
~/.claude-cabinet/omega-venv/bin/python3 -c "import omega; print('ok')"
|
|
396
|
+
```
|
|
397
|
+
A broken venv means all memory hooks silently degrade.
|
|
398
|
+
|
|
399
|
+
- **Adapter availability.** Does `scripts/cabinet-memory-adapter.py`
|
|
400
|
+
exist in the project? Without it, hooks have nothing to call.
|
|
401
|
+
|
|
402
|
+
- **Hook registration.** Check `.claude/settings.json` for:
|
|
403
|
+
- `memory-session-start.sh` in `SessionStart` hooks
|
|
404
|
+
- `memory-post-compact.sh` in `PostCompact` hooks
|
|
405
|
+
Missing hooks mean omega was installed but never wired in.
|
|
406
|
+
|
|
407
|
+
- **Omega database.** Run the adapter's `status` command:
|
|
408
|
+
```bash
|
|
409
|
+
echo '{}' | ~/.claude-cabinet/omega-venv/bin/python3 \
|
|
410
|
+
scripts/cabinet-memory-adapter.py status
|
|
411
|
+
```
|
|
412
|
+
Check: is the database growing? Zero memories after multiple sessions
|
|
413
|
+
suggests capture isn't working.
|
|
414
|
+
|
|
415
|
+
- **ONNX model presence.** Check `~/.cache/omega/models/` for the
|
|
416
|
+
embedding model directory. Missing model means semantic search falls
|
|
417
|
+
back to hash-based pseudo-embeddings (much lower quality).
|
|
418
|
+
|
|
419
|
+
- **Rules file.** Does `.claude/rules/memory-capture.md` exist? Without
|
|
420
|
+
it, in-session capture guidance is missing.
|
|
421
|
+
|
|
422
|
+
**What to report:** Infrastructure gaps (broken venv, missing hooks,
|
|
423
|
+
missing model), capture failures (zero memories after active sessions),
|
|
424
|
+
configuration mismatches (module installed but hooks not registered).
|
|
425
|
+
|
|
426
|
+
**Severity guidance:**
|
|
427
|
+
- Broken venv or missing adapter → **warn** (all memory silently disabled)
|
|
428
|
+
- Missing hooks → **warn** (capture not happening)
|
|
429
|
+
- Missing ONNX model → **info** (degraded but functional)
|
|
430
|
+
- Zero memories after 3+ sessions → **warn** (capture failing silently)
|
|
431
|
+
|
|
432
|
+
### 9. Anti-Bloat
|
|
388
433
|
|
|
389
434
|
Apply `_lifecycle.md` retirement criteria proactively. A lean cabinet is
|
|
390
435
|
better than a comprehensive one with dead weight:
|
|
@@ -61,6 +61,20 @@ to help you do your job.
|
|
|
61
61
|
|
|
62
62
|
### Sources of Institutional Memory (check in this order)
|
|
63
63
|
|
|
64
|
+
0. **Omega semantic memory** — if `~/.claude-cabinet/omega-venv/bin/python3`
|
|
65
|
+
and `scripts/cabinet-memory-adapter.py` both exist, query omega FIRST.
|
|
66
|
+
It stores decisions, lessons, preferences, and constraints with semantic
|
|
67
|
+
retrieval — meaning you can search by concept, not just keyword.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
echo '{"text": "your query here", "limit": 10}' | \
|
|
71
|
+
~/.claude-cabinet/omega-venv/bin/python3 scripts/cabinet-memory-adapter.py query
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Omega returns memories ranked by relevance. This is the richest source
|
|
75
|
+
of institutional memory when available. If omega is not available, skip
|
|
76
|
+
to source 1.
|
|
77
|
+
|
|
64
78
|
1. **Memory files** — `.claude/memory/*.md` and any project-level memory
|
|
65
79
|
index (e.g., `MEMORY.md`). These are the distilled, catalogued lessons.
|
|
66
80
|
Check here first. Read the index for orientation, then read relevant
|
|
@@ -142,6 +156,18 @@ what was about to happen next. This is the historian's moment.
|
|
|
142
156
|
in a session should survive compaction because it's been written
|
|
143
157
|
down *during* the session, not just summarized after truncation.
|
|
144
158
|
|
|
159
|
+
**Omega and compaction:** If omega memory is active, the PostCompact
|
|
160
|
+
hook (`memory-post-compact.sh`) automatically captures key context from
|
|
161
|
+
the compaction summary. After compaction, query omega to see what was
|
|
162
|
+
preserved:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
echo '{"text": "session context before compaction", "limit": 5}' | \
|
|
166
|
+
~/.claude-cabinet/omega-venv/bin/python3 scripts/cabinet-memory-adapter.py query
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
This supplements (not replaces) the manual recovery protocol above.
|
|
170
|
+
|
|
145
171
|
**The meta-lesson:** Compaction is an entropy event. The historian's
|
|
146
172
|
job is to ensure the memory system is robust enough that compaction
|
|
147
173
|
merely loses conversational tone, not institutional knowledge. If
|
|
@@ -205,6 +205,26 @@ anything that future sessions need to know? A new pattern, a gotcha,
|
|
|
205
205
|
a process gap, a user preference? Lessons are perishable — capture
|
|
206
206
|
them now while context is fresh.
|
|
207
207
|
|
|
208
|
+
**Omega-primary:** If `~/.claude-cabinet/omega-venv/bin/python3` and
|
|
209
|
+
`scripts/cabinet-memory-adapter.py` both exist, write lessons to omega
|
|
210
|
+
as the primary destination — not flat markdown. Use the adapter:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
echo '{"text": "the lesson", "type": "lesson"}' | \
|
|
214
|
+
~/.claude-cabinet/omega-venv/bin/python3 scripts/cabinet-memory-adapter.py store
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Types: `decision`, `lesson`, `preference`, `constraint`, `pattern`.
|
|
218
|
+
Fall back to flat markdown memory only if omega is unavailable.
|
|
219
|
+
|
|
220
|
+
**Omega broken:** If the memory module is installed (check `.ccrc.json`
|
|
221
|
+
for `"memory": true`) but the venv or adapter is missing, surface this
|
|
222
|
+
in the debrief report:
|
|
223
|
+
|
|
224
|
+
> **⚠ Memory module is installed but omega is not working.**
|
|
225
|
+
> Lessons from this session were saved to flat markdown instead of omega.
|
|
226
|
+
> Run `npx create-claude-cabinet` to rebuild the omega venv.
|
|
227
|
+
|
|
208
228
|
> **Debrief lessons vs audit findings:** Debrief captures session-specific
|
|
209
229
|
> learnings — what was discovered while doing this work, what surprised
|
|
210
230
|
> you, what should change. Audit captures systematic observations from
|
|
@@ -12,19 +12,34 @@ Lessons are perishable. A lesson captured while context is fresh is worth
|
|
|
12
12
|
ten captured from memory next week. This is why recording happens during
|
|
13
13
|
debrief, not "sometime later."
|
|
14
14
|
|
|
15
|
-
##
|
|
15
|
+
## Where to Record — Omega Primary
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
- **What NOT to record** — ephemeral details, things derivable from code
|
|
17
|
+
Check whether omega memory is available:
|
|
18
|
+
- `~/.claude-cabinet/omega-venv/bin/python3` exists AND
|
|
19
|
+
- `scripts/cabinet-memory-adapter.py` exists
|
|
21
20
|
|
|
22
|
-
|
|
21
|
+
**When omega is available (primary path):** Write lessons to omega via
|
|
22
|
+
the adapter. This is the durable, semantic memory store that persists
|
|
23
|
+
across sessions and supports retrieval by meaning, not just keyword.
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
```bash
|
|
26
|
+
echo '{"text": "the lesson", "type": "lesson", "tags": ["tag1"]}' | \
|
|
27
|
+
~/.claude-cabinet/omega-venv/bin/python3 scripts/cabinet-memory-adapter.py store
|
|
28
|
+
```
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
Memory types to use:
|
|
31
|
+
- `decision` — architectural choices, tradeoff resolutions
|
|
32
|
+
- `lesson` — gotchas, discoveries, things that surprised
|
|
33
|
+
- `preference` — user corrections, style choices, workflow preferences
|
|
34
|
+
- `constraint` — limitations discovered, prerequisites found
|
|
35
|
+
- `pattern` — conventions established, recurring solutions
|
|
36
|
+
|
|
37
|
+
**When omega is NOT available (fallback):** Use the flat markdown memory
|
|
38
|
+
system (auto-memory in `~/.claude/projects/` memory directory). This is
|
|
39
|
+
the same system Claude Code uses natively. It works, but lacks semantic
|
|
40
|
+
retrieval.
|
|
41
|
+
|
|
42
|
+
## What to Look For
|
|
28
43
|
|
|
29
44
|
Review the session and ask:
|
|
30
45
|
- Did we learn something future sessions need to know?
|
|
@@ -36,32 +51,16 @@ Review the session and ask:
|
|
|
36
51
|
of problem keeps recurring, the lesson is "create a prevention mechanism"
|
|
37
52
|
not just "remember this."
|
|
38
53
|
- Did the session's work contradict any existing recorded knowledge?
|
|
39
|
-
If so, update or remove the stale record
|
|
40
|
-
|
|
41
|
-
### Where to Record
|
|
42
|
-
|
|
43
|
-
**Feedback patterns** (corrections, confirmations):
|
|
44
|
-
Write to memory/patterns/ if it matches an existing pattern; write to
|
|
45
|
-
memory/archive/ as a raw observation if it's new. If 3+ raw observations
|
|
46
|
-
accumulate around a theme, consolidate into a pattern.
|
|
47
|
-
|
|
48
|
-
**Project state** (decisions, milestones, architecture changes):
|
|
49
|
-
Update the relevant project memory file or create one.
|
|
50
|
-
|
|
51
|
-
**User context** (preferences, role changes, domain knowledge):
|
|
52
|
-
Update the user context memory file.
|
|
53
|
-
|
|
54
|
-
**References** (external resources, tool URLs, account details):
|
|
55
|
-
Create or update a reference memory file.
|
|
54
|
+
If so, update or remove the stale record (in omega: use `query` to
|
|
55
|
+
find it, then note the contradiction in the new memory).
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
## What NOT to Record
|
|
58
58
|
- Code patterns derivable by reading current files
|
|
59
59
|
- Git history (use git log)
|
|
60
60
|
- Debugging solutions (the fix is in the code)
|
|
61
61
|
- Anything already in CLAUDE.md files
|
|
62
62
|
- Ephemeral task details only relevant to this session
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
## Report What Was Recorded
|
|
65
65
|
Tell the user what memories were created or updated so they know what
|
|
66
|
-
the system will remember next time.
|
|
67
|
-
-->
|
|
66
|
+
the system will remember next time. Include the count and types.
|
|
@@ -39,6 +39,38 @@ but know they exist — if work in this session touches something that
|
|
|
39
39
|
relates to another project, mention it. "This API change might affect
|
|
40
40
|
your investor-reports project too."
|
|
41
41
|
|
|
42
|
+
### Omega Semantic Memory
|
|
43
|
+
|
|
44
|
+
If `~/.claude-cabinet/omega-venv/bin/python3` and
|
|
45
|
+
`scripts/cabinet-memory-adapter.py` both exist, surface relevant
|
|
46
|
+
memories from omega at session start:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
echo '{}' | ~/.claude-cabinet/omega-venv/bin/python3 \
|
|
50
|
+
scripts/cabinet-memory-adapter.py welcome
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The `welcome` command returns memories relevant to the current project.
|
|
54
|
+
The SessionStart hook (`memory-session-start.sh`) also does this
|
|
55
|
+
automatically, but during orient you can query for specific context:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
echo '{"text": "recent decisions and lessons", "limit": 5}' | \
|
|
59
|
+
~/.claude-cabinet/omega-venv/bin/python3 \
|
|
60
|
+
scripts/cabinet-memory-adapter.py query
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
If omega is not available, check whether the memory module is installed
|
|
64
|
+
(look for `"memory": true` in `.ccrc.json`). If it IS installed but the
|
|
65
|
+
venv or adapter is missing, surface a warning:
|
|
66
|
+
|
|
67
|
+
> **⚠ Memory module is installed but omega is not available.**
|
|
68
|
+
> The venv at `~/.claude-cabinet/omega-venv/` may be missing or broken.
|
|
69
|
+
> Re-run `npx create-claude-cabinet` to rebuild it.
|
|
70
|
+
|
|
71
|
+
If the memory module is NOT installed, skip silently — the user opted
|
|
72
|
+
out. Fall back to flat markdown memory (MEMORY.md) either way.
|
|
73
|
+
|
|
42
74
|
## Additional Context Sources
|
|
43
75
|
|
|
44
76
|
Uncomment and adapt these for your project:
|