Commit 3791202f7b9a
Changed files (8)
dots
.claude
plugins
session-manager
commands
tools
claude-hooks
dots/.claude/plugins/session-manager/commands/save-session.md
@@ -0,0 +1,186 @@
+---
+description: Save a summary of the current Claude Code session to history
+---
+
+# Save Session
+
+Create a comprehensive session summary following the history-system format and save it to `~/.claude/history/sessions/`.
+
+## Important Guidelines
+
+- **DO NOT use echo or command-line tools to communicate** - output all text directly in your response
+- **Create a properly formatted session entry** following the history-system skill template
+- **Save to the correct location** with proper timestamp and filename format
+- **Be concise but comprehensive** - capture what matters
+
+---
+
+## Workflow
+
+### Step 1: Analyze the Session
+
+Review the conversation and identify:
+1. **Main accomplishments** - What was actually done?
+2. **Key decisions** - What choices were made and why?
+3. **Next steps** - What follow-up work is needed?
+4. **Related topics** - What areas of the codebase or system were touched?
+
+### Step 2: Generate Session Entry
+
+Create a session entry file with:
+
+**Filename format**: `YYYY-MM-DD-HHMMSS_SESSION_description.md`
+
+**Location**: `~/.claude/history/sessions/YYYY-MM/`
+
+**Template**:
+```markdown
+# Session: <Brief Description>
+
+**Date**: YYYY-MM-DD HH:MM
+**Duration**: <estimated duration if known>
+**Context**: <What prompted this work session>
+
+## What Was Accomplished
+- <Specific task 1>
+- <Specific task 2>
+- <Specific task 3>
+
+## Decisions Made
+- **<Decision>**: <Rationale>
+- **<Decision>**: <Rationale>
+
+## Technical Details
+<Any important technical information worth preserving>
+
+## Next Steps
+- [ ] <Follow-up task 1>
+- [ ] <Follow-up task 2>
+
+## Related Notes
+<If applicable, link to related denote notes>
+
+## Tags
+#session #<relevant-topic-tags>
+```
+
+### Step 3: Save the File
+
+Use the Write tool to save the session entry to:
+```
+~/.claude/history/sessions/YYYY-MM/YYYY-MM-DD-HHMMSS_SESSION_description.md
+```
+
+Replace:
+- `YYYY-MM` with current year-month
+- `YYYY-MM-DD-HHMMSS` with current timestamp
+- `description` with a short hyphenated description (e.g., `nixos-syncthing-config`)
+
+### Step 4: Confirm to User
+
+After saving, inform the user:
+```
+✅ Session saved to: ~/.claude/history/sessions/YYYY-MM/YYYY-MM-DD-HHMMSS_SESSION_description.md
+
+Summary:
+- X tasks completed
+- Y decisions documented
+- Z next steps identified
+```
+
+---
+
+## Examples
+
+### Example 1: Configuration Change Session
+```markdown
+# Session: Configure Syncthing for Claude History
+
+**Date**: 2025-12-04 07:30
+**Duration**: 30 minutes
+**Context**: Need to sync Claude Code history across machines for backup
+
+## What Was Accomplished
+- Added claude-history folder to globals.nix syncthingFolders
+- Generated syncthing folder ID (j5zdn-6kq4t)
+- Configured claude-history sync for kyushu and aomi
+- Path: /home/vincent/.claude/history
+
+## Decisions Made
+- **Syncthing ID format**: Used random 5-char strings (xxxxx-xxxxx) following existing pattern
+- **Machines**: Started with kyushu and aomi only, can add more later
+
+## Technical Details
+- Syncthing folder ID: j5zdn-6kq4t
+- Path: /home/vincent/.claude/history
+- Synced machines: kyushu (SBLRZF4-...), aomi (CN5P3MV-...)
+
+## Next Steps
+- [ ] Rebuild NixOS on kyushu to activate sync
+- [ ] Rebuild NixOS on aomi to activate sync
+- [ ] Verify syncthing picks up the new folder
+- [ ] Consider adding more machines later
+
+## Tags
+#session #nixos #syncthing #claude-code #homelab
+```
+
+### Example 2: Development Session
+```markdown
+# Session: Implement Session Saving Hooks
+
+**Date**: 2025-12-04 08:00
+**Duration**: 45 minutes
+**Context**: Automate session saving in Claude Code
+
+## What Was Accomplished
+- Created claude-hooks-save-session Go command
+- Created /save-session slash command plugin
+- Updated plugin structure in dots/.claude/plugins/session-manager
+- Documented workflow in command file
+
+## Decisions Made
+- **SessionEnd hook approach**: Prompt user instead of auto-save (user agency)
+- **Plugin structure**: Created dedicated session-manager plugin
+- **Format**: Follow existing history-system markdown template
+
+## Technical Details
+- Hook location: tools/claude-hooks/cmd/save-session/
+- Plugin location: dots/.claude/plugins/session-manager/
+- Follows existing claude-hooks Go patterns
+
+## Next Steps
+- [ ] Update default.nix to build save-session command
+- [ ] Add SessionEnd hook to settings.json
+- [ ] Test hook and slash command
+- [ ] Update setup-hooks.sh
+
+## Tags
+#session #development #claude-code #golang #hooks
+```
+
+---
+
+## Best Practices
+
+1. **Be specific** - Don't just say "worked on code", say what exactly was modified
+2. **Capture decisions** - Document WHY choices were made, not just what was done
+3. **Include context** - Future you needs to know what prompted this work
+4. **Link related work** - Reference denote notes, commits, or other sessions
+5. **Add tags** - Make sessions searchable by topic
+6. **Keep it real** - If nothing significant happened, it's okay to skip saving
+
+## When to Use
+
+- After completing significant work
+- When making important architectural decisions
+- When learning something worth preserving
+- At the end of productive sessions
+- When asked by SessionEnd hook
+
+## When to Skip
+
+- Very short sessions (<5 minutes)
+- Purely exploratory work with no findings
+- When no meaningful progress was made
+- When the work will be documented elsewhere
dots/.claude/plugins/session-manager/plugin.json
@@ -0,0 +1,12 @@
+{
+ "name": "session-manager",
+ "version": "1.0.0",
+ "description": "Save and manage Claude Code session summaries",
+ "author": "Vincent Demeester",
+ "commands": [
+ {
+ "name": "save-session",
+ "file": "commands/save-session.md"
+ }
+ ]
+}
dots/Makefile
@@ -31,6 +31,9 @@ claude-hooks : ~/.claude/hooks
all += claude-settings
claude-settings : ~/.claude/settings.json
+all += claude-plugins
+claude-plugins : ~/.claude/plugins/session-manager
+
# Example: Override default rule to generate content instead of copying
# Uncomment and customize this pattern for files that should be generated:
#
tools/claude-hooks/cmd/save-session/main.go
@@ -0,0 +1,42 @@
+package main
+
+import (
+ "fmt"
+ "os"
+)
+
+// isSubagentSession checks if this is a subagent session
+func isSubagentSession() bool {
+ claudeProjectDir := os.Getenv("CLAUDE_PROJECT_DIR")
+ if len(claudeProjectDir) > 0 && (len(claudeProjectDir) < 2 || claudeProjectDir[len(claudeProjectDir)-2:] != "/.") {
+ return true
+ }
+ if os.Getenv("CLAUDE_AGENT_TYPE") != "" {
+ return true
+ }
+ return false
+}
+
+func main() {
+ // Check if this is a subagent session
+ if isSubagentSession() {
+ // Silent exit for subagent sessions
+ os.Exit(0)
+ }
+
+ // Output prompt for Claude to save the session
+ // This will be shown in the conversation
+ fmt.Println("")
+ fmt.Println("---")
+ fmt.Println("")
+ fmt.Println("**Session ending**. Would you like me to save a summary of this session to your history?")
+ fmt.Println("")
+ fmt.Println("I can create a session entry in `~/.claude/history/sessions/` documenting:")
+ fmt.Println("- What was accomplished")
+ fmt.Println("- Decisions made")
+ fmt.Println("- Next steps")
+ fmt.Println("- Related notes")
+ fmt.Println("")
+
+ os.Exit(0)
+}
tools/claude-hooks/default.nix
@@ -7,11 +7,12 @@ buildGoModule rec {
vendorHash = "sha256-bdpAteulG3045jPdEpjcT4yGlnxLKDMlK7lk9WVRTKc=";
- # Build all three binaries
+ # Build all binaries
subPackages = [
"cmd/capture-tool-output"
"cmd/initialize-session"
"cmd/validate-docs"
+ "cmd/save-session"
];
# Rename binaries to have consistent prefix
@@ -19,10 +20,11 @@ buildGoModule rec {
mv $out/bin/capture-tool-output $out/bin/claude-hooks-capture-tool-output
mv $out/bin/initialize-session $out/bin/claude-hooks-initialize-session
mv $out/bin/validate-docs $out/bin/claude-hooks-validate-docs
+ mv $out/bin/save-session $out/bin/claude-hooks-save-session
'';
meta = {
- description = "Claude Code hooks for session initialization, tool output capture, and documentation validation";
+ description = "Claude Code hooks for session management, tool output capture, and documentation validation";
mainProgram = "claude-hooks-capture-tool-output";
};
}
tools/claude-hooks/README.md
@@ -34,6 +34,16 @@ Migrated from TypeScript/Bun implementation in `dots/.claude/hooks/`.
- Exit code 0 if valid, 1 if broken links found
- Skips external URLs, anchors, and mailto links
+### 4. `claude-hooks-save-session`
+**Event**: SessionEnd
+
+**What it does**:
+- Prompts user to save session summary when ending a Claude Code session
+- Skips subagent sessions (silent)
+- Displays a message asking if session should be saved
+- Works with `/save-session` slash command for creating session entries
+- Saves to `~/.claude/history/sessions/YYYY-MM/YYYY-MM-DD-HHMMSS_SESSION_description.md`
+
## Architecture
```
@@ -41,6 +51,7 @@ tools/claude-hooks/
├── cmd/
│ ├── capture-tool-output/main.go # PostToolUse hook
│ ├── initialize-session/main.go # SessionStart hook
+│ ├── save-session/main.go # SessionEnd hook
│ └── validate-docs/main.go # Documentation validator
├── internal/
│ └── paths/paths.go # Shared path utilities
@@ -100,11 +111,27 @@ tools/claude-hooks/
}
]
}
+ ],
+ "SessionEnd": [
+ {
+ "hooks": [
+ {
+ "type": "command",
+ "command": "claude-hooks-save-session"
+ }
+ ]
+ }
]
}
}
```
+5. **Enable the session-manager plugin** (for `/save-session` command):
+ ```bash
+ # Symlink the plugin if not already linked
+ ln -s ~/src/home/dots/.claude/plugins/session-manager ~/.claude/plugins/session-manager
+ ```
+
### Manual Build (without Nix)
```bash
@@ -113,6 +140,7 @@ cd tools/claude-hooks
# Build all hooks
go build -o bin/claude-hooks-capture-tool-output ./cmd/capture-tool-output
go build -o bin/claude-hooks-initialize-session ./cmd/initialize-session
+go build -o bin/claude-hooks-save-session ./cmd/save-session
go build -o bin/claude-hooks-validate-docs ./cmd/validate-docs
# Copy to PATH
tools/claude-hooks/setup-hooks.sh
@@ -62,10 +62,23 @@ POST_TOOL_HOOKS=$(cat <<'EOF'
EOF
)
+SESSION_END_HOOKS=$(cat <<'EOF'
+{
+ "hooks": [
+ {
+ "type": "command",
+ "command": "claude-hooks-save-session"
+ }
+ ]
+}
+EOF
+)
+
# Use jq to update the settings.json with proper JSON merging
UPDATED_SETTINGS=$(echo "$CURRENT_SETTINGS" | jq --argjson sessionStart "$NEW_HOOKS" \
--argjson postTool "$POST_TOOL_HOOKS" \
- '.hooks.SessionStart = [$sessionStart] | .hooks.PostToolUse = [$postTool]')
+ --argjson sessionEnd "$SESSION_END_HOOKS" \
+ '.hooks.SessionStart = [$sessionStart] | .hooks.PostToolUse = [$postTool] | .hooks.SessionEnd = [$sessionEnd]')
if [[ "$DRY_RUN" == true ]]; then
echo "=== DRY RUN - No changes made ==="
@@ -81,6 +94,7 @@ else
echo "Hook binaries configured:"
echo " - SessionStart: claude-hooks-initialize-session"
echo " - PostToolUse: claude-hooks-capture-tool-output"
+ echo " - SessionEnd: claude-hooks-save-session"
echo ""
echo "Make sure claude-hooks is installed:"
echo " nix profile install .#claude-hooks"
globals.nix
@@ -35,6 +35,10 @@ _: {
id = "kcyrf-mugzt";
path = "/home/vincent/desktop/music";
};
+ claude-history = {
+ id = "j5zdn-6kq4t";
+ path = "/home/vincent/.claude/history";
+ };
};
net = {
dns = {
@@ -215,6 +219,7 @@ _: {
sync = { };
screenshots = { };
wallpapers = { };
+ claude-history = { };
# TODO: implement paused or filter theses
# photos = {
# type = "receiveonly";
@@ -251,6 +256,7 @@ _: {
sync = { };
screenshots = { };
wallpapers = { };
+ claude-history = { };
# photos = {
# type = "receiveonly";
# paused = true; # TODO: implement this, start as paused