Skip to content
This repository was archived by the owner on Jan 2, 2026. It is now read-only.

Commit 6d528e9

Browse files
committed
feat(hooks): add SessionStart hook for context injection
- Inject memory system status at session start - Remind about capture markers: [remember], [capture], @memory - Show namespace breakdown and memory count
1 parent 6a0954f commit 6d528e9

1 file changed

Lines changed: 131 additions & 0 deletions

File tree

hooks/sessionstart.py

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
#!/usr/bin/env python3
2+
"""Hook: Inject memory capture context at session start.
3+
4+
This hook runs at the start of each Claude Code session and injects
5+
context that reminds the user and assistant about memory capture markers.
6+
7+
The hook:
8+
1. Provides memory system status (index health, memory count)
9+
2. Reminds about capture markers: [remember], [capture], @memory
10+
3. Lists available namespaces and their purposes
11+
4. Suggests relevant memories if spec context is available
12+
"""
13+
14+
from __future__ import annotations
15+
16+
import json
17+
import os
18+
import sys
19+
from pathlib import Path
20+
21+
22+
def get_memory_status() -> dict:
23+
"""Get current memory system status.
24+
25+
Returns:
26+
Dict with status information.
27+
"""
28+
try:
29+
from git_notes_memory.config import get_index_path
30+
from git_notes_memory.index import IndexService
31+
32+
index_path = get_index_path()
33+
if not index_path.exists():
34+
return {
35+
"initialized": False,
36+
"total_memories": 0,
37+
"message": "Memory index not initialized. Run `/memory:sync` to initialize.",
38+
}
39+
40+
index = IndexService(index_path)
41+
index.initialize()
42+
stats = index.get_stats()
43+
index.close()
44+
45+
return {
46+
"initialized": True,
47+
"total_memories": stats.total_memories,
48+
"by_namespace": dict(stats.by_namespace) if stats.by_namespace else {},
49+
}
50+
51+
except ImportError:
52+
return {
53+
"initialized": False,
54+
"total_memories": 0,
55+
"error": "git-notes-memory library not installed",
56+
}
57+
except Exception as e:
58+
return {
59+
"initialized": False,
60+
"total_memories": 0,
61+
"error": str(e),
62+
}
63+
64+
65+
def build_context_message(status: dict) -> str:
66+
"""Build the context injection message.
67+
68+
Args:
69+
status: Memory system status dict.
70+
71+
Returns:
72+
Formatted context message for Claude.
73+
"""
74+
lines = []
75+
76+
# Memory system status
77+
if status.get("initialized"):
78+
total = status.get("total_memories", 0)
79+
lines.append(f"Memory system active: {total} memories indexed.")
80+
if status.get("by_namespace"):
81+
ns_summary = ", ".join(
82+
f"{ns}: {count}" for ns, count in list(status["by_namespace"].items())[:5]
83+
)
84+
lines.append(f"Namespaces: {ns_summary}")
85+
else:
86+
lines.append("Memory system: not initialized.")
87+
if status.get("error"):
88+
lines.append(f"Note: {status['error']}")
89+
90+
lines.append("")
91+
lines.append("MEMORY CAPTURE MARKERS:")
92+
lines.append(
93+
"When you discover important information worth preserving, prefix your response with:"
94+
)
95+
lines.append("- [remember] <content> - Captures as a 'learnings' memory")
96+
lines.append("- [capture] <content> - Captures as a 'learnings' memory")
97+
lines.append("- @memory <content> - Same as [capture]")
98+
lines.append("")
99+
lines.append(
100+
"Examples of what to capture: decisions, learnings, blockers, "
101+
"patterns, progress, and key insights."
102+
)
103+
104+
return "\n".join(lines)
105+
106+
107+
def main() -> None:
108+
"""Main hook entry point."""
109+
# Read hook input from stdin
110+
try:
111+
input_data = json.load(sys.stdin)
112+
except (json.JSONDecodeError, ValueError):
113+
input_data = {}
114+
115+
# Get memory system status
116+
status = get_memory_status()
117+
118+
# Build context message
119+
context_message = build_context_message(status)
120+
121+
# Output the context injection
122+
output = {
123+
"continue": True,
124+
"additionalContext": context_message,
125+
}
126+
127+
print(json.dumps(output))
128+
129+
130+
if __name__ == "__main__":
131+
main()

0 commit comments

Comments
 (0)