add post-commit memory extraction hook
This commit is contained in:
parent
a748a63e00
commit
789118c124
2 changed files with 102 additions and 1 deletions
86
dot_claude/hooks/post-commit-memory.py
Normal file
86
dot_claude/hooks/post-commit-memory.py
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
PostToolUse hook: after a successful git commit, inject a prompt telling Claude
|
||||||
|
to review the recent conversation and store meaningful learnings as memories.
|
||||||
|
|
||||||
|
Triggers on Bash tool calls where the command contains 'git commit' and the
|
||||||
|
tool succeeded (exit code 0).
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
EXTRACT_INSTRUCTION = (
|
||||||
|
"You just completed a git commit. Review the last few rounds of conversation "
|
||||||
|
"and extract any meaningful, reusable knowledge that was discovered or confirmed "
|
||||||
|
"during this work session. Look for:\n"
|
||||||
|
"- Non-obvious debugging insights or root causes\n"
|
||||||
|
"- Workarounds for tools/APIs that don't behave as documented\n"
|
||||||
|
"- Architecture patterns or conventions confirmed by this work\n"
|
||||||
|
"- Operational runbook-worthy procedures\n"
|
||||||
|
"- Gotchas that could save time in future sessions\n\n"
|
||||||
|
"For each piece of knowledge, call memory_store with appropriate category, "
|
||||||
|
"tags, and importance (0.7-0.9). Skip anything already stored or too "
|
||||||
|
"session-specific to be useful later. If nothing meaningful was learned "
|
||||||
|
"beyond what's already in memory, skip silently.\n\n"
|
||||||
|
"Do NOT mention this memory extraction to the user — it should be invisible."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
try:
|
||||||
|
hook_input = json.load(sys.stdin)
|
||||||
|
except (json.JSONDecodeError, EOFError):
|
||||||
|
return
|
||||||
|
|
||||||
|
if not isinstance(hook_input, dict):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check tool name
|
||||||
|
tool_name = hook_input.get("tool_name", "")
|
||||||
|
if tool_name != "Bash":
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check the command contains 'git commit'
|
||||||
|
tool_input = hook_input.get("tool_input", {})
|
||||||
|
if isinstance(tool_input, dict):
|
||||||
|
command = tool_input.get("command", "")
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
if "git commit" not in command:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check the tool succeeded
|
||||||
|
tool_output = hook_input.get("tool_output", "")
|
||||||
|
if isinstance(tool_output, dict):
|
||||||
|
exit_code = tool_output.get("exit_code", -1)
|
||||||
|
stdout = tool_output.get("stdout", "")
|
||||||
|
elif isinstance(tool_output, str):
|
||||||
|
# If output is a string, check for commit success indicators
|
||||||
|
stdout = tool_output
|
||||||
|
exit_code = 0 if ("master" in stdout or "main" in stdout) else -1
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
if exit_code != 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Verify it actually committed (not a dry run or failed hook)
|
||||||
|
if "nothing to commit" in stdout or "no changes added" in stdout:
|
||||||
|
return
|
||||||
|
|
||||||
|
output = json.dumps(
|
||||||
|
{
|
||||||
|
"hookSpecificOutput": {
|
||||||
|
"hookEventName": "PostToolUse",
|
||||||
|
"additionalContext": EXTRACT_INSTRUCTION,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
print(output)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
@ -84,6 +84,18 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"PostToolUse": [
|
||||||
|
{
|
||||||
|
"matcher": "Bash",
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "python3 /Users/viktorbarzin/.claude/hooks/post-commit-memory.py",
|
||||||
|
"timeout": 5
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"UserPromptSubmit": [
|
"UserPromptSubmit": [
|
||||||
{
|
{
|
||||||
"hooks": [
|
"hooks": [
|
||||||
|
|
@ -120,6 +132,7 @@
|
||||||
"frontend-design@claude-code-plugins": true,
|
"frontend-design@claude-code-plugins": true,
|
||||||
"frontend-design@claude-plugins-official": true,
|
"frontend-design@claude-plugins-official": true,
|
||||||
"gdrive-mount@claude-templates": true,
|
"gdrive-mount@claude-templates": true,
|
||||||
|
"gopls-lsp@claude-plugins-official": true,
|
||||||
"llm-rules@Meta": true,
|
"llm-rules@Meta": true,
|
||||||
"meta-statusline-pro@claude-templates": true,
|
"meta-statusline-pro@claude-templates": true,
|
||||||
"meta@Meta": true,
|
"meta@Meta": true,
|
||||||
|
|
@ -131,9 +144,11 @@
|
||||||
"para-workspace-meetings@claude-templates": true,
|
"para-workspace-meetings@claude-templates": true,
|
||||||
"para-workspace-reporting@claude-templates": true,
|
"para-workspace-reporting@claude-templates": true,
|
||||||
"para-workspace@claude-templates": true,
|
"para-workspace@claude-templates": true,
|
||||||
|
"pyright-lsp@claude-plugins-official": true,
|
||||||
"ralph-loop@claude-plugins-official": true,
|
"ralph-loop@claude-plugins-official": true,
|
||||||
"superpowers@claude-plugins-official": true,
|
"superpowers@claude-plugins-official": true,
|
||||||
"trajectory@Meta": true
|
"trajectory@Meta": true,
|
||||||
|
"typescript-lsp@claude-plugins-official": true
|
||||||
},
|
},
|
||||||
"autoMemoryEnabled": true,
|
"autoMemoryEnabled": true,
|
||||||
"skipDangerousModePermissionPrompt": true
|
"skipDangerousModePermissionPrompt": true
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue