get-claudia 1.2.5 → 1.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -26
- package/bin/index.js +39 -17
- package/memory-daemon/scripts/install.sh +62 -11
- package/memory-daemon/scripts/migrate_markdown.py +35 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,39 +43,36 @@ Say hi. She'll introduce herself and set things up for you.
|
|
|
43
43
|
|
|
44
44
|
---
|
|
45
45
|
|
|
46
|
+
## What's New in v1.2.5
|
|
47
|
+
|
|
48
|
+
**Fully automatic memory system** - No more manual steps after install:
|
|
49
|
+
|
|
50
|
+
- **Works after reboot** - Ollama and the memory daemon auto-start on login (macOS LaunchAgent)
|
|
51
|
+
- **Python 3.13 support** - sqlite-vec now works on all Python versions
|
|
52
|
+
- **Boot resilience** - Daemon waits for Ollama to start instead of failing silently
|
|
53
|
+
- **Better diagnostics** - Run `~/.claudia/diagnose.sh` to check all services
|
|
54
|
+
|
|
55
|
+
The memory system just works now. Install, reboot, and everything comes back up.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
46
59
|
## Already Have Claudia? Add Memory.
|
|
47
60
|
|
|
48
|
-
If you installed Claudia before the memory system existed,
|
|
61
|
+
If you installed Claudia before the memory system existed, just run the installer again:
|
|
49
62
|
|
|
50
63
|
```bash
|
|
51
|
-
|
|
52
|
-
git clone https://github.com/kbanc/claudia.git
|
|
53
|
-
cd claudia/memory-daemon
|
|
54
|
-
|
|
55
|
-
# Run the installer
|
|
56
|
-
./scripts/install.sh
|
|
64
|
+
npx get-claudia
|
|
57
65
|
```
|
|
58
66
|
|
|
59
|
-
The installer will:
|
|
67
|
+
When prompted, say **yes** to install the memory system. The installer will:
|
|
60
68
|
- Set up the memory daemon at `~/.claudia/daemon/`
|
|
61
|
-
- Install Ollama for
|
|
62
|
-
- Configure auto-start so
|
|
63
|
-
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
```json
|
|
68
|
-
{
|
|
69
|
-
"mcpServers": {
|
|
70
|
-
"claudia-memory": {
|
|
71
|
-
"command": "~/.claudia/daemon/venv/bin/python",
|
|
72
|
-
"args": ["-m", "claudia_memory.mcp.server"]
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
```
|
|
69
|
+
- Install Ollama for semantic search (optional but recommended)
|
|
70
|
+
- Configure auto-start so everything runs on login
|
|
71
|
+
- Pull the embedding model automatically
|
|
72
|
+
- Verify all services are working
|
|
73
|
+
- Update your `.mcp.json` automatically
|
|
77
74
|
|
|
78
|
-
Restart Claude Code, and Claudia now has persistent memory.
|
|
75
|
+
Restart Claude Code in a new terminal, and Claudia now has persistent memory.
|
|
79
76
|
|
|
80
77
|
---
|
|
81
78
|
|
|
@@ -83,11 +80,12 @@ Restart Claude Code, and Claudia now has persistent memory.
|
|
|
83
80
|
|
|
84
81
|
| Traditional AI | Claudia |
|
|
85
82
|
|----------------|---------|
|
|
86
|
-
| Forgets everything between sessions | **Persistent memory** — SQLite + vector search,
|
|
83
|
+
| Forgets everything between sessions | **Persistent memory** — SQLite + vector search, survives reboots |
|
|
87
84
|
| Treats conversations as isolated | **Tracks relationships** — People files, not just tasks |
|
|
88
85
|
| Waits for instructions | **Proactive** — Surfaces risks before they become problems |
|
|
89
86
|
| One-size-fits-all | **Personalized** — Structure generated for your work style |
|
|
90
87
|
| Cloud-based, data harvested | **Local** — Runs on your machine, your context stays yours |
|
|
88
|
+
| Breaks after system updates | **Resilient** — Auto-starts on boot, retries on failure |
|
|
91
89
|
|
|
92
90
|
---
|
|
93
91
|
|
|
@@ -256,6 +254,44 @@ See what she surfaces. Then tell her about a person you work with.
|
|
|
256
254
|
|
|
257
255
|
---
|
|
258
256
|
|
|
257
|
+
## Troubleshooting
|
|
258
|
+
|
|
259
|
+
**Memory tools not appearing?**
|
|
260
|
+
```bash
|
|
261
|
+
# Check all services
|
|
262
|
+
~/.claudia/diagnose.sh
|
|
263
|
+
|
|
264
|
+
# Common fixes:
|
|
265
|
+
# 1. Restart Claude Code in a NEW terminal (it reads .mcp.json at startup)
|
|
266
|
+
# 2. Check daemon health: curl http://localhost:3848/health
|
|
267
|
+
# 3. View logs: tail -f ~/.claudia/daemon-stderr.log
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
**Ollama not running after reboot?**
|
|
271
|
+
```bash
|
|
272
|
+
# Load the LaunchAgent
|
|
273
|
+
launchctl load ~/Library/LaunchAgents/com.ollama.serve.plist
|
|
274
|
+
|
|
275
|
+
# Or start manually
|
|
276
|
+
ollama serve
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
**Vector search not working?**
|
|
280
|
+
```bash
|
|
281
|
+
# Check if sqlite-vec is installed
|
|
282
|
+
~/.claudia/daemon/venv/bin/python -c "import sqlite_vec; print('ok')"
|
|
283
|
+
|
|
284
|
+
# If not, install it
|
|
285
|
+
~/.claudia/daemon/venv/bin/pip install sqlite-vec
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**Pull the embedding model**
|
|
289
|
+
```bash
|
|
290
|
+
ollama pull all-minilm:l6-v2
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
259
295
|
## License
|
|
260
296
|
|
|
261
297
|
Apache 2.0 — Use it, modify it, make it yours.
|
package/bin/index.js
CHANGED
|
@@ -56,37 +56,55 @@ async function main() {
|
|
|
56
56
|
const args = process.argv.slice(2);
|
|
57
57
|
const arg = args[0];
|
|
58
58
|
|
|
59
|
-
// Support "." for current directory
|
|
60
|
-
const isCurrentDir = arg === '.';
|
|
59
|
+
// Support "." or "upgrade" for current directory
|
|
60
|
+
const isCurrentDir = arg === '.' || arg === 'upgrade';
|
|
61
61
|
const targetDir = isCurrentDir ? '.' : (arg || 'claudia');
|
|
62
62
|
const targetPath = isCurrentDir ? process.cwd() : join(process.cwd(), targetDir);
|
|
63
63
|
const displayDir = isCurrentDir ? 'current directory' : targetDir;
|
|
64
64
|
|
|
65
65
|
// Check if directory already exists and has conflicting files
|
|
66
|
+
let isUpgrade = false;
|
|
67
|
+
|
|
66
68
|
if (existsSync(targetPath)) {
|
|
67
69
|
const contents = readdirSync(targetPath);
|
|
68
70
|
const hasConflict = contents.some(f => f === 'CLAUDE.md' || f === '.claude');
|
|
71
|
+
|
|
69
72
|
if (hasConflict) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
// Check if this is an upgrade (existing memories to migrate)
|
|
74
|
+
const hasExistingMemories = existsSync(join(targetPath, 'context', 'me.md')) ||
|
|
75
|
+
existsSync(join(targetPath, 'context', 'learnings.md')) ||
|
|
76
|
+
existsSync(join(targetPath, 'context', 'patterns.md')) ||
|
|
77
|
+
existsSync(join(targetPath, 'people'));
|
|
78
|
+
|
|
79
|
+
if (hasExistingMemories) {
|
|
80
|
+
console.log(`\n${colors.cyan}✓${colors.reset} Found existing Claudia instance with memories.`);
|
|
81
|
+
isUpgrade = true;
|
|
82
|
+
// Don't exit - proceed to memory installation
|
|
83
|
+
} else {
|
|
84
|
+
// Fresh install conflict - exit as before
|
|
85
|
+
console.log(`\n${colors.yellow}⚠${colors.reset} Claudia files already exist in ${displayDir}.`);
|
|
86
|
+
console.log(` Remove CLAUDE.md and .claude/ first, or choose a different location.\n`);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
73
89
|
}
|
|
74
90
|
}
|
|
75
91
|
|
|
76
|
-
// Create target directory if not current dir
|
|
77
|
-
if (!isCurrentDir) {
|
|
92
|
+
// Create target directory if not current dir (only for fresh installs)
|
|
93
|
+
if (!isCurrentDir && !isUpgrade) {
|
|
78
94
|
mkdirSync(targetPath, { recursive: true });
|
|
79
95
|
}
|
|
80
96
|
|
|
81
|
-
// Copy template files (v2 - minimal seed)
|
|
82
|
-
|
|
97
|
+
// Copy template files (v2 - minimal seed) - skip for upgrades
|
|
98
|
+
if (!isUpgrade) {
|
|
99
|
+
const templatePath = join(__dirname, '..', 'template-v2');
|
|
83
100
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
101
|
+
try {
|
|
102
|
+
cpSync(templatePath, targetPath, { recursive: true });
|
|
103
|
+
console.log(`${colors.green}✓${colors.reset} Installed in ${displayDir}`);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
console.error(`\n${colors.yellow}⚠${colors.reset} Error copying files: ${error.message}`);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
90
108
|
}
|
|
91
109
|
|
|
92
110
|
// Ask about enhanced memory system
|
|
@@ -113,10 +131,14 @@ async function main() {
|
|
|
113
131
|
|
|
114
132
|
if (existsSync(memoryDaemonPath)) {
|
|
115
133
|
try {
|
|
116
|
-
// Run the install script
|
|
134
|
+
// Run the install script, passing project path for upgrades
|
|
117
135
|
const result = spawn('bash', [memoryDaemonPath], {
|
|
118
136
|
stdio: 'inherit',
|
|
119
|
-
shell: true
|
|
137
|
+
shell: true,
|
|
138
|
+
env: {
|
|
139
|
+
...process.env,
|
|
140
|
+
CLAUDIA_PROJECT_PATH: isUpgrade ? targetPath : ''
|
|
141
|
+
}
|
|
120
142
|
});
|
|
121
143
|
|
|
122
144
|
result.on('close', (code) => {
|
|
@@ -93,16 +93,34 @@ random_message() {
|
|
|
93
93
|
echo "${MESSAGES[$RANDOM % ${#MESSAGES[@]}]}"
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
# Check Python
|
|
97
|
-
echo -e "${BOLD}Step 1/
|
|
96
|
+
# Check Python - prefer Homebrew Python on macOS (supports SQLite extensions)
|
|
97
|
+
echo -e "${BOLD}Step 1/8: Environment Check${NC}"
|
|
98
98
|
echo
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
PYTHON=""
|
|
100
|
+
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
101
|
+
# Homebrew Python supports SQLite extension loading (needed for vector search)
|
|
102
|
+
if [ -x "/opt/homebrew/bin/python3" ]; then
|
|
103
|
+
PYTHON="/opt/homebrew/bin/python3"
|
|
104
|
+
echo -e " ${GREEN}✓${NC} Using Homebrew Python (vector search supported)"
|
|
105
|
+
elif [ -x "/usr/local/bin/python3" ]; then
|
|
106
|
+
PYTHON="/usr/local/bin/python3"
|
|
107
|
+
echo -e " ${GREEN}✓${NC} Using Homebrew Python (vector search supported)"
|
|
108
|
+
fi
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
if [ -z "$PYTHON" ]; then
|
|
112
|
+
if command -v python3 &> /dev/null; then
|
|
113
|
+
PYTHON=$(command -v python3)
|
|
114
|
+
fi
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
if [ -n "$PYTHON" ]; then
|
|
101
118
|
PYTHON_VERSION=$($PYTHON --version 2>&1 | awk '{print $2}')
|
|
102
|
-
echo -e " ${GREEN}✓${NC} Python $PYTHON_VERSION"
|
|
119
|
+
echo -e " ${GREEN}✓${NC} Python $PYTHON_VERSION ($PYTHON)"
|
|
103
120
|
else
|
|
104
121
|
echo -e " ${RED}✗${NC} Python 3 not found"
|
|
105
122
|
echo -e " Please install Python 3.10 or later"
|
|
123
|
+
echo -e " ${DIM}On macOS: brew install python${NC}"
|
|
106
124
|
exit 1
|
|
107
125
|
fi
|
|
108
126
|
|
|
@@ -181,7 +199,7 @@ echo -e "${DIM}━━━━━━━━━━━━━━━━━━━━━
|
|
|
181
199
|
echo
|
|
182
200
|
|
|
183
201
|
# Pull embedding model
|
|
184
|
-
echo -e "${BOLD}Step 2/
|
|
202
|
+
echo -e "${BOLD}Step 2/8: AI Models${NC}"
|
|
185
203
|
echo
|
|
186
204
|
if [ "$OLLAMA_AVAILABLE" = true ]; then
|
|
187
205
|
# Ensure Ollama is running before pulling model
|
|
@@ -230,7 +248,7 @@ echo -e "${DIM}━━━━━━━━━━━━━━━━━━━━━
|
|
|
230
248
|
echo
|
|
231
249
|
|
|
232
250
|
# Create directories
|
|
233
|
-
echo -e "${BOLD}Step 3/
|
|
251
|
+
echo -e "${BOLD}Step 3/8: Creating Home${NC}"
|
|
234
252
|
echo
|
|
235
253
|
mkdir -p "$DAEMON_DIR"
|
|
236
254
|
mkdir -p "$MEMORY_DIR"
|
|
@@ -247,10 +265,11 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
247
265
|
SOURCE_DIR="$(dirname "$SCRIPT_DIR")"
|
|
248
266
|
|
|
249
267
|
# Copy daemon files
|
|
250
|
-
echo -e "${BOLD}Step 4/
|
|
268
|
+
echo -e "${BOLD}Step 4/8: Installing Core${NC}"
|
|
251
269
|
echo
|
|
252
270
|
echo -e " ${CYAN}◐${NC} Copying memory system files..."
|
|
253
271
|
cp -r "$SOURCE_DIR/claudia_memory" "$DAEMON_DIR/"
|
|
272
|
+
cp -r "$SOURCE_DIR/scripts" "$DAEMON_DIR/"
|
|
254
273
|
cp "$SOURCE_DIR/pyproject.toml" "$DAEMON_DIR/"
|
|
255
274
|
cp "$SOURCE_DIR/requirements.txt" "$DAEMON_DIR/"
|
|
256
275
|
echo -e " ${GREEN}✓${NC} Core files installed"
|
|
@@ -265,7 +284,7 @@ echo -e "${DIM}━━━━━━━━━━━━━━━━━━━━━
|
|
|
265
284
|
echo
|
|
266
285
|
|
|
267
286
|
# Create virtual environment
|
|
268
|
-
echo -e "${BOLD}Step 5/
|
|
287
|
+
echo -e "${BOLD}Step 5/8: Python Environment${NC}"
|
|
269
288
|
echo
|
|
270
289
|
echo -e " ${CYAN}◐${NC} Creating isolated environment..."
|
|
271
290
|
$PYTHON -m venv "$VENV_DIR"
|
|
@@ -290,7 +309,7 @@ echo -e "${DIM}━━━━━━━━━━━━━━━━━━━━━
|
|
|
290
309
|
echo
|
|
291
310
|
|
|
292
311
|
# Configure auto-start
|
|
293
|
-
echo -e "${BOLD}Step 6/
|
|
312
|
+
echo -e "${BOLD}Step 6/8: Auto-Start Setup${NC}"
|
|
294
313
|
echo
|
|
295
314
|
|
|
296
315
|
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
@@ -375,8 +394,40 @@ echo
|
|
|
375
394
|
echo -e "${DIM}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
376
395
|
echo
|
|
377
396
|
|
|
397
|
+
# Memory Migration (for upgrades)
|
|
398
|
+
echo -e "${BOLD}Step 7/8: Memory Migration${NC}"
|
|
399
|
+
echo
|
|
400
|
+
|
|
401
|
+
if [ -n "$CLAUDIA_PROJECT_PATH" ]; then
|
|
402
|
+
# Check if there are memories to migrate
|
|
403
|
+
if [ -d "$CLAUDIA_PROJECT_PATH/context" ] || [ -d "$CLAUDIA_PROJECT_PATH/people" ]; then
|
|
404
|
+
echo -e " ${CYAN}◐${NC} Found existing memories to migrate..."
|
|
405
|
+
|
|
406
|
+
# Wait a moment for daemon to start
|
|
407
|
+
sleep 2
|
|
408
|
+
|
|
409
|
+
# Run migration in quiet mode
|
|
410
|
+
"$VENV_DIR/bin/python" "$DAEMON_DIR/scripts/migrate_markdown.py" --quiet "$CLAUDIA_PROJECT_PATH"
|
|
411
|
+
|
|
412
|
+
if [ $? -eq 0 ]; then
|
|
413
|
+
echo -e " ${GREEN}✓${NC} Memories migrated to database"
|
|
414
|
+
else
|
|
415
|
+
echo -e " ${YELLOW}!${NC} Migration had issues (memories still in markdown)"
|
|
416
|
+
echo -e " ${DIM}You can retry manually: ~/.claudia/daemon/venv/bin/python -m claudia_memory.scripts.migrate_markdown $CLAUDIA_PROJECT_PATH${NC}"
|
|
417
|
+
fi
|
|
418
|
+
else
|
|
419
|
+
echo -e " ${DIM}No existing memories found to migrate${NC}"
|
|
420
|
+
fi
|
|
421
|
+
else
|
|
422
|
+
echo -e " ${DIM}Fresh install - no migration needed${NC}"
|
|
423
|
+
fi
|
|
424
|
+
|
|
425
|
+
echo
|
|
426
|
+
echo -e "${DIM}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
427
|
+
echo
|
|
428
|
+
|
|
378
429
|
# Verify all services
|
|
379
|
-
echo -e "${BOLD}Step
|
|
430
|
+
echo -e "${BOLD}Step 8/8: Verification${NC}"
|
|
380
431
|
echo
|
|
381
432
|
echo -e " ${CYAN}◐${NC} Checking all services..."
|
|
382
433
|
sleep 3
|
|
@@ -346,13 +346,22 @@ def main():
|
|
|
346
346
|
action="store_true",
|
|
347
347
|
help="Enable debug logging",
|
|
348
348
|
)
|
|
349
|
+
parser.add_argument(
|
|
350
|
+
"--quiet",
|
|
351
|
+
action="store_true",
|
|
352
|
+
help="Non-interactive mode (for automated migration)",
|
|
353
|
+
)
|
|
349
354
|
|
|
350
355
|
args = parser.parse_args()
|
|
351
356
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
357
|
+
if args.quiet:
|
|
358
|
+
# Suppress all logging in quiet mode
|
|
359
|
+
logging.basicConfig(level=logging.ERROR)
|
|
360
|
+
else:
|
|
361
|
+
logging.basicConfig(
|
|
362
|
+
level=logging.DEBUG if args.debug else logging.INFO,
|
|
363
|
+
format="%(asctime)s - %(levelname)s - %(message)s",
|
|
364
|
+
)
|
|
356
365
|
|
|
357
366
|
# Initialize database
|
|
358
367
|
db = get_db()
|
|
@@ -363,8 +372,24 @@ def main():
|
|
|
363
372
|
if not args.path.exists():
|
|
364
373
|
logger.error(f"Path not found: {args.path}")
|
|
365
374
|
sys.exit(1)
|
|
375
|
+
|
|
376
|
+
if not args.quiet:
|
|
377
|
+
print(f"Migrating: {args.path}")
|
|
378
|
+
|
|
366
379
|
stats = migrate_instance(args.path, args.dry_run)
|
|
367
|
-
|
|
380
|
+
|
|
381
|
+
if args.quiet:
|
|
382
|
+
# Quiet mode - minimal output for automated migration
|
|
383
|
+
total = sum(stats.values())
|
|
384
|
+
if total > 0:
|
|
385
|
+
print(f" - Migrated {stats['me']} items from context/me.md") if stats.get('me') else None
|
|
386
|
+
print(f" - Migrated {stats['learnings']} items from context/learnings.md") if stats.get('learnings') else None
|
|
387
|
+
print(f" - Migrated {stats['patterns']} items from context/patterns.md") if stats.get('patterns') else None
|
|
388
|
+
print(f" - Migrated {stats['commitments']} items from context/commitments.md") if stats.get('commitments') else None
|
|
389
|
+
if stats.get('people'):
|
|
390
|
+
print(f" - Migrated {stats['people']} people with {stats.get('memories', 0)} facts")
|
|
391
|
+
else:
|
|
392
|
+
print(f"\nMigrated: {stats}")
|
|
368
393
|
|
|
369
394
|
elif args.all:
|
|
370
395
|
# Migrate all instances
|
|
@@ -373,11 +398,12 @@ def main():
|
|
|
373
398
|
logger.info("No Claudia instances found")
|
|
374
399
|
sys.exit(0)
|
|
375
400
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
401
|
+
if not args.quiet:
|
|
402
|
+
print(f"Found {len(instances)} Claudia instance(s):\n")
|
|
403
|
+
for i, instance in enumerate(instances, 1):
|
|
404
|
+
print(f" {i}. {instance}")
|
|
379
405
|
|
|
380
|
-
if not args.dry_run:
|
|
406
|
+
if not args.dry_run and not args.quiet:
|
|
381
407
|
confirm = input("\nMigrate all? (y/n) ")
|
|
382
408
|
if confirm.lower() != "y":
|
|
383
409
|
sys.exit(0)
|