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

Commit 7ada7ca

Browse files
zircoteclaude
andcommitted
fix(hooks): use explicit venv python path for hook execution
- hooks.json: Use ${CLAUDE_PLUGIN_ROOT}/.venv/bin/python3 instead of relying on shebang, ensures correct interpreter with dependencies - sessionstart.py: Delegate to session_start_handler module instead of inline implementation - Add marketplace.json for plugin discovery 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent e6b08e3 commit 7ada7ca

3 files changed

Lines changed: 58 additions & 133 deletions

File tree

hooks/hooks.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
"hooks": [
77
{
88
"type": "command",
9-
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/sessionstart.py",
10-
"timeout": 10
9+
"command": "${CLAUDE_PLUGIN_ROOT}/.venv/bin/python3 ${CLAUDE_PLUGIN_ROOT}/hooks/sessionstart.py",
10+
"timeout": 30
1111
}
1212
]
1313
}
@@ -17,7 +17,7 @@
1717
"hooks": [
1818
{
1919
"type": "command",
20-
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/userpromptsubmit.py",
20+
"command": "${CLAUDE_PLUGIN_ROOT}/.venv/bin/python3 ${CLAUDE_PLUGIN_ROOT}/hooks/userpromptsubmit.py",
2121
"timeout": 10
2222
}
2323
]
@@ -29,7 +29,7 @@
2929
"hooks": [
3030
{
3131
"type": "command",
32-
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/posttooluse.py",
32+
"command": "${CLAUDE_PLUGIN_ROOT}/.venv/bin/python3 ${CLAUDE_PLUGIN_ROOT}/hooks/posttooluse.py",
3333
"timeout": 5
3434
}
3535
]
@@ -41,7 +41,7 @@
4141
"hooks": [
4242
{
4343
"type": "command",
44-
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/precompact.py",
44+
"command": "${CLAUDE_PLUGIN_ROOT}/.venv/bin/python3 ${CLAUDE_PLUGIN_ROOT}/hooks/precompact.py",
4545
"timeout": 15
4646
}
4747
]
@@ -52,7 +52,7 @@
5252
"hooks": [
5353
{
5454
"type": "command",
55-
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/stop.py",
55+
"command": "${CLAUDE_PLUGIN_ROOT}/.venv/bin/python3 ${CLAUDE_PLUGIN_ROOT}/hooks/stop.py",
5656
"timeout": 30
5757
}
5858
]

hooks/sessionstart.py

Lines changed: 27 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
#!/usr/bin/env python3
2-
"""Hook: Inject memory capture context at session start.
2+
"""Hook: Inject memory context at session start.
33
44
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
5+
context that includes:
6+
1. Memory system status (index health, memory count)
7+
2. Relevant memories for the current project/spec
8+
3. Response guidance for memory capture markers
9+
4. Available namespaces and their purposes
10+
11+
Environment Variables:
12+
HOOK_ENABLED: Master switch for hooks (default: true)
13+
HOOK_SESSION_START_ENABLED: Enable this hook (default: true)
14+
HOOK_DEBUG: Enable debug logging (default: false)
15+
16+
Exit codes:
17+
0 - Success (non-blocking)
1218
"""
1319

1420
from __future__ import annotations
@@ -24,130 +30,24 @@
2430
sys.path.insert(0, str(_src_path))
2531

2632

27-
def get_memory_status() -> dict:
28-
"""Get current memory system status.
33+
def main() -> None:
34+
"""Main hook entry point.
2935
30-
Returns:
31-
Dict with status information.
36+
Delegates to the session_start_handler module for actual processing.
37+
Falls back gracefully if the library is not installed.
3238
"""
3339
try:
34-
from git_notes_memory.config import get_index_path
35-
from git_notes_memory.index import IndexService
36-
37-
index_path = get_index_path()
38-
if not index_path.exists():
39-
return {
40-
"initialized": False,
41-
"total_memories": 0,
42-
"message": "Memory index not initialized. Run `/memory:sync` to initialize.",
43-
}
44-
45-
index = IndexService(index_path)
46-
index.initialize()
47-
stats = index.get_stats()
48-
index.close()
49-
50-
return {
51-
"initialized": True,
52-
"total_memories": stats.total_memories,
53-
"by_namespace": dict(stats.by_namespace) if stats.by_namespace else {},
54-
}
40+
from git_notes_memory.hooks.session_start_handler import main as handler_main
5541

42+
handler_main()
5643
except ImportError:
57-
return {
58-
"initialized": False,
59-
"total_memories": 0,
60-
"error": "git-notes-memory library not installed",
61-
}
62-
except Exception as e:
63-
return {
64-
"initialized": False,
65-
"total_memories": 0,
66-
"error": str(e),
67-
}
68-
69-
70-
def build_context_message(status: dict) -> str:
71-
"""Build the context injection message.
72-
73-
Args:
74-
status: Memory system status dict.
75-
76-
Returns:
77-
Formatted context message for Claude.
78-
"""
79-
lines = []
80-
81-
# Memory system status
82-
if status.get("initialized"):
83-
total = status.get("total_memories", 0)
84-
lines.append(f"Memory system active: {total} memories indexed.")
85-
if status.get("by_namespace"):
86-
ns_summary = ", ".join(
87-
f"{ns}: {count}" for ns, count in list(status["by_namespace"].items())[:5]
88-
)
89-
lines.append(f"Namespaces: {ns_summary}")
90-
else:
91-
lines.append("Memory system: not initialized.")
92-
if status.get("error"):
93-
lines.append(f"Note: {status['error']}")
94-
95-
lines.append("")
96-
lines.append("MEMORY CAPTURE MARKERS:")
97-
lines.append(
98-
"When you discover important information worth preserving, prefix your response with:"
99-
)
100-
lines.append("- [remember] <content> - Captures as a 'learnings' memory")
101-
lines.append("- [capture] <content> - Captures as a 'learnings' memory")
102-
lines.append("- @memory <content> - Same as [capture]")
103-
lines.append("")
104-
lines.append(
105-
"Examples of what to capture: decisions, learnings, blockers, "
106-
"patterns, progress, and key insights."
107-
)
108-
109-
return "\n".join(lines)
110-
111-
112-
def build_user_message(status: dict) -> str:
113-
"""Build a concise user-visible status message.
114-
115-
Args:
116-
status: Memory system status dict.
117-
118-
Returns:
119-
Short status message with emoji indicator.
120-
"""
121-
if status.get("initialized"):
122-
total = status.get("total_memories", 0)
123-
return f"📚 Memory system: {total} memories indexed"
124-
else:
125-
return "📚 Memory system: not initialized"
126-
127-
128-
def main() -> None:
129-
"""Main hook entry point."""
130-
# Read hook input from stdin (not used but must be consumed)
131-
try:
132-
_input_data = json.load(sys.stdin)
133-
except (json.JSONDecodeError, ValueError):
134-
_input_data = {} # noqa: F841
135-
136-
# Get memory system status
137-
status = get_memory_status()
138-
139-
# Build context message (for Claude) and user message (visible)
140-
context_message = build_context_message(status)
141-
user_message = build_user_message(status)
142-
143-
# Output the context injection with user-visible message
144-
output = {
145-
"continue": True,
146-
"additionalContext": context_message,
147-
"message": user_message,
148-
}
149-
150-
print(json.dumps(output))
44+
# Library not installed, exit silently (non-blocking)
45+
print(json.dumps({"continue": True}))
46+
sys.exit(0)
47+
except Exception:
48+
# Any unexpected error, exit silently (non-blocking)
49+
print(json.dumps({"continue": True}))
50+
sys.exit(0)
15151

15252

15353
if __name__ == "__main__":

marketplace.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "git-notes-memory",
3+
"description": "Plugin marketplace for git-notes-memory - Git-native, semantically-searchable memory storage for Claude Code",
4+
"version": "1.0.0",
5+
"owner": {
6+
"name": "zircote",
7+
"email": "zircote@gmail.com"
8+
},
9+
"plugins": [
10+
{
11+
"name": "memory-capture",
12+
"description": "Git-backed memory system for Claude Code. Captures decisions, learnings, and context as git notes with semantic search and automatic recall.",
13+
"version": "0.1.0",
14+
"author": {
15+
"name": "Robert Allen",
16+
"email": "zircote@gmail.com"
17+
},
18+
"repository": "https://github.com/zircote/git-notes-memory-manager",
19+
"license": "MIT",
20+
"keywords": ["memory", "git-notes", "semantic-search", "context", "recall"],
21+
"source": "./",
22+
"homepage": "https://github.com/zircote/git-notes-memory-manager#readme"
23+
}
24+
]
25+
}

0 commit comments

Comments
 (0)