get-claudia 1.28.0 → 1.28.2
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/memory-daemon/claudia_memory/mcp/server.py +13 -0
- package/memory-daemon/claudia_memory/services/remember.py +7 -0
- package/memory-daemon/tests/test_turn_buffering.py +37 -0
- package/package.json +1 -1
- package/template-v2/.claude/hooks/session-health-check.sh +32 -2
- package/template-v2/.claude/skills/memory-manager.md +26 -7
- package/template-v2/CLAUDE.md +6 -2
|
@@ -1427,6 +1427,19 @@ async def call_tool(name: str, arguments: Dict[str, Any]) -> CallToolResult:
|
|
|
1427
1427
|
|
|
1428
1428
|
elif name == "memory.end_session":
|
|
1429
1429
|
episode_id = arguments["episode_id"]
|
|
1430
|
+
|
|
1431
|
+
# Auto-create episode if it doesn't exist (handles skipped buffer_turn)
|
|
1432
|
+
svc = get_remember_service()
|
|
1433
|
+
episode = svc.db.get_one("episodes", where="id = ?", where_params=(episode_id,))
|
|
1434
|
+
if not episode:
|
|
1435
|
+
from datetime import datetime
|
|
1436
|
+
new_id = svc.db.insert("episodes", {
|
|
1437
|
+
"started_at": datetime.utcnow().isoformat(),
|
|
1438
|
+
"source": arguments.get("source", "claude_code"),
|
|
1439
|
+
})
|
|
1440
|
+
logger.info(f"Auto-created episode {new_id} (requested {episode_id} did not exist)")
|
|
1441
|
+
episode_id = new_id
|
|
1442
|
+
|
|
1430
1443
|
result = end_session(
|
|
1431
1444
|
episode_id=episode_id,
|
|
1432
1445
|
narrative=arguments["narrative"],
|
|
@@ -993,6 +993,13 @@ class RememberService:
|
|
|
993
993
|
"relationships_stored": 0,
|
|
994
994
|
}
|
|
995
995
|
|
|
996
|
+
# Validate episode exists before any DB operations
|
|
997
|
+
episode = self.db.get_one("episodes", where="id = ?", where_params=(episode_id,))
|
|
998
|
+
if not episode:
|
|
999
|
+
result["error"] = f"Episode {episode_id} not found. Call memory.buffer_turn first to create an episode."
|
|
1000
|
+
logger.warning(f"end_session called with non-existent episode_id={episode_id}")
|
|
1001
|
+
return result
|
|
1002
|
+
|
|
996
1003
|
# 1. Store narrative in episode
|
|
997
1004
|
update_data = {
|
|
998
1005
|
"narrative": narrative,
|
|
@@ -160,6 +160,43 @@ class TestEndSession:
|
|
|
160
160
|
db.close()
|
|
161
161
|
|
|
162
162
|
|
|
163
|
+
def test_end_session_nonexistent_episode(self):
|
|
164
|
+
"""end_session with a non-existent episode_id should return error, not raise."""
|
|
165
|
+
db, tmpdir = _make_db()
|
|
166
|
+
try:
|
|
167
|
+
svc = _make_service(db)
|
|
168
|
+
|
|
169
|
+
# Call end_session with an episode_id that was never created
|
|
170
|
+
result = svc.end_session(
|
|
171
|
+
episode_id=9999,
|
|
172
|
+
narrative="This episode does not exist."
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
assert result["episode_id"] == 9999
|
|
176
|
+
assert result["narrative_stored"] is False
|
|
177
|
+
assert "error" in result
|
|
178
|
+
assert "not found" in result["error"].lower()
|
|
179
|
+
finally:
|
|
180
|
+
db.close()
|
|
181
|
+
|
|
182
|
+
def test_end_session_episode_zero(self):
|
|
183
|
+
"""end_session with episode_id=0 should return error (AUTOINCREMENT starts at 1)."""
|
|
184
|
+
db, tmpdir = _make_db()
|
|
185
|
+
try:
|
|
186
|
+
svc = _make_service(db)
|
|
187
|
+
|
|
188
|
+
result = svc.end_session(
|
|
189
|
+
episode_id=0,
|
|
190
|
+
narrative="Default zero episode."
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
assert result["episode_id"] == 0
|
|
194
|
+
assert result["narrative_stored"] is False
|
|
195
|
+
assert "error" in result
|
|
196
|
+
finally:
|
|
197
|
+
db.close()
|
|
198
|
+
|
|
199
|
+
|
|
163
200
|
class TestUnsummarized:
|
|
164
201
|
"""Tests for get_unsummarized_turns functionality."""
|
|
165
202
|
|
package/package.json
CHANGED
|
@@ -1,10 +1,40 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# Quick health check at session start
|
|
3
3
|
# Returns JSON with additionalContext to inform Claudia of memory system status
|
|
4
|
+
# Provides actionable guidance when daemon is down
|
|
4
5
|
|
|
5
6
|
if curl -s "http://localhost:3848/health" 2>/dev/null | grep -q "healthy"; then
|
|
6
7
|
echo '{"additionalContext": "Memory system healthy."}'
|
|
7
|
-
|
|
8
|
-
echo '{"additionalContext": "Warning: Memory daemon not responding. Run /diagnose for details. Operating in fallback mode."}'
|
|
8
|
+
exit 0
|
|
9
9
|
fi
|
|
10
|
+
|
|
11
|
+
# Daemon is NOT healthy. Figure out why and provide actionable guidance.
|
|
12
|
+
CONTEXT="IMPORTANT: Memory daemon is NOT running. Without it, you lose semantic search, pattern detection, cross-session learning, and proactive predictions. You MUST surface this to the user and offer to help fix it."
|
|
13
|
+
|
|
14
|
+
# Check if daemon is installed
|
|
15
|
+
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
16
|
+
PLIST="$HOME/Library/LaunchAgents/com.claudia.memory.plist"
|
|
17
|
+
if [ -f "$PLIST" ]; then
|
|
18
|
+
CONTEXT="$CONTEXT Daemon is installed (LaunchAgent exists) but not running. Suggest: 'Your memory daemon is installed but stopped. Want me to try starting it? I can run: launchctl load ~/Library/LaunchAgents/com.claudia.memory.plist'"
|
|
19
|
+
else
|
|
20
|
+
CONTEXT="$CONTEXT Daemon is NOT installed. Suggest: 'The memory daemon hasn\u0027t been set up yet. Want me to install it? I can run the installer for you.'"
|
|
21
|
+
fi
|
|
22
|
+
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
|
23
|
+
SERVICE="$HOME/.config/systemd/user/claudia-memory.service"
|
|
24
|
+
if [ -f "$SERVICE" ]; then
|
|
25
|
+
CONTEXT="$CONTEXT Daemon is installed (systemd service exists) but not running. Suggest: 'Your memory daemon is installed but stopped. Want me to try starting it? I can run: systemctl --user start claudia-memory'"
|
|
26
|
+
else
|
|
27
|
+
CONTEXT="$CONTEXT Daemon is NOT installed. Suggest: 'The memory daemon hasn\u0027t been set up yet. Want me to install it? I can run the installer for you.'"
|
|
28
|
+
fi
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
# Check for recent crash logs
|
|
32
|
+
if [ -f "$HOME/.claudia/daemon-stderr.log" ]; then
|
|
33
|
+
LAST_ERROR=$(tail -5 "$HOME/.claudia/daemon-stderr.log" 2>/dev/null | head -3)
|
|
34
|
+
if [ -n "$LAST_ERROR" ]; then
|
|
35
|
+
CONTEXT="$CONTEXT Recent daemon log: $LAST_ERROR"
|
|
36
|
+
fi
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
echo "{\"additionalContext\": \"$CONTEXT\"}"
|
|
10
40
|
exit 0
|
|
@@ -81,9 +81,17 @@ User shares transcript/email/document
|
|
|
81
81
|
|
|
82
82
|
Before greeting the user:
|
|
83
83
|
1. Check that `memory.*` tools are in your available tools
|
|
84
|
-
2. If missing:
|
|
84
|
+
2. If missing: **Do not silently fall back.** Proactively tell the user and offer to fix it:
|
|
85
|
+
- If the session-health-check hook reported the daemon is installed but stopped, offer to start it:
|
|
86
|
+
- macOS: `launchctl load ~/Library/LaunchAgents/com.claudia.memory.plist`
|
|
87
|
+
- Linux: `systemctl --user start claudia-memory`
|
|
88
|
+
- If the daemon was never installed, offer to run the installer:
|
|
89
|
+
- `~/.claudia/daemon/scripts/install.sh` (if daemon dir exists)
|
|
90
|
+
- Or `cd [claudia-dir] && ./memory-daemon/scripts/install.sh`
|
|
91
|
+
- Briefly explain what's lost without it: "Without the daemon, I can't search memories semantically, detect patterns, track relationships across sessions, or give you proactive predictions."
|
|
92
|
+
- After starting, the user needs to restart Claude Code for MCP tools to appear
|
|
85
93
|
3. Call `memory.session_context` to load context
|
|
86
|
-
4. If this fails: Warn user about degraded mode
|
|
94
|
+
4. If this fails: Warn user about degraded mode and suggest checking `~/.claudia/daemon-stderr.log`
|
|
87
95
|
|
|
88
96
|
### 3. Buffer Turns During Sessions
|
|
89
97
|
|
|
@@ -157,21 +165,32 @@ Do NOT:
|
|
|
157
165
|
|
|
158
166
|
## Memory System Detection
|
|
159
167
|
|
|
160
|
-
At session start, check which memory system is available
|
|
168
|
+
At session start, check which memory system is available. **This is not optional.** The daemon is Claudia's brain. Without it she's operating at a fraction of her capability.
|
|
161
169
|
|
|
162
170
|
1. **Enhanced Memory (Preferred):** Check if `memory.recall` MCP tool is available
|
|
163
|
-
2. **
|
|
171
|
+
2. **If missing, diagnose and offer to fix** (don't silently degrade)
|
|
172
|
+
3. **Fallback:** Use markdown files in `context/` directory only as last resort
|
|
164
173
|
|
|
165
174
|
```
|
|
166
175
|
Session Start:
|
|
167
176
|
├── Check if memory.recall tool exists
|
|
168
177
|
│ ├── YES → Use enhanced memory system
|
|
169
|
-
│ └── NO → Check
|
|
170
|
-
│ ├──
|
|
178
|
+
│ └── NO → Check session-health-check hook output for diagnosis
|
|
179
|
+
│ ├── Hook says "installed but stopped"
|
|
180
|
+
│ │ → Offer to start: "Your memory daemon is installed but stopped.
|
|
181
|
+
│ │ Want me to start it?" Then run the platform-specific command.
|
|
182
|
+
│ │ After starting, user must restart Claude Code for MCP tools.
|
|
183
|
+
│ ├── Hook says "not installed"
|
|
184
|
+
│ │ → Offer to install: "The memory system hasn't been set up yet.
|
|
185
|
+
│ │ Want me to run the installer?"
|
|
186
|
+
│ ├── No hook output → Check daemon health: curl -s localhost:3848/health
|
|
171
187
|
│ │ ├── Healthy but no MCP tools → User needs to restart Claude Code
|
|
172
|
-
│ │ └── Not healthy →
|
|
188
|
+
│ │ └── Not healthy → Offer to start/install (as above)
|
|
189
|
+
│ └── After offering, if user declines → Fall back to markdown files
|
|
173
190
|
```
|
|
174
191
|
|
|
192
|
+
**The key behavior change:** Never silently fall back to markdown. Always tell the user and offer to fix it. The daemon makes Claudia dramatically more capable and users should know when they're missing out.
|
|
193
|
+
|
|
175
194
|
---
|
|
176
195
|
|
|
177
196
|
## Troubleshooting MCP Connection
|
package/template-v2/CLAUDE.md
CHANGED
|
@@ -81,14 +81,18 @@ Check for `context/me.md` at the start of any session. If it doesn't exist, this
|
|
|
81
81
|
At the start of every session (after confirming `context/me.md` exists):
|
|
82
82
|
|
|
83
83
|
1. **Verify memory tools** - Check that `memory.*` MCP tools are available in your tool list
|
|
84
|
-
- If NO memory tools:
|
|
84
|
+
- If NO memory tools: **Don't just warn. Offer to fix it.** Check the session-health-check hook output:
|
|
85
|
+
- Daemon installed but stopped → Offer to start it (platform-specific command)
|
|
86
|
+
- Daemon not installed → Offer to run the installer
|
|
87
|
+
- Briefly explain what's lost: semantic search, pattern detection, cross-session learning, proactive predictions
|
|
88
|
+
- If user agrees to start it, they'll need to restart Claude Code afterward for MCP tools to register
|
|
85
89
|
- If memory tools present: Continue to step 2
|
|
86
90
|
2. **Load context** - Call `memory.session_context` to get recent memories, predictions, commitments, and unsummarized session alerts
|
|
87
91
|
- If this call fails: The daemon may have crashed. Suggest checking `~/.claudia/daemon-stderr.log`
|
|
88
92
|
3. **Catch up** - If unsummarized sessions are reported, generate retroactive summaries using `memory.end_session`
|
|
89
93
|
4. **Greet naturally** - Use the loaded context to inform your greeting and surface urgent items
|
|
90
94
|
|
|
91
|
-
**Fallback mode:** If memory tools aren't available, read markdown context files directly (`context/*.md`). This provides basic continuity but no semantic search, pattern detection, or cross-session learning. Always inform the user they're in degraded mode.
|
|
95
|
+
**Fallback mode:** If memory tools aren't available and the user declines to start the daemon, read markdown context files directly (`context/*.md`). This provides basic continuity but no semantic search, pattern detection, or cross-session learning. Always inform the user they're in degraded mode.
|
|
92
96
|
|
|
93
97
|
### Returning User Greetings
|
|
94
98
|
|