Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ mise use go@1.24.3 # Install/use specific version
│ ├── settings.json # Claude Code settings (hooks, plugins, permissions)
│ ├── statusline.sh # Status line display script
│ ├── CLAUDE.md # User global instructions (Workflow Orchestration)
│ ├── hooks/ # Lifecycle hooks (4): validate-shell.sh,
│ │ # session-context.sh, pre-tool-guard.sh, post-verify-rule-proposal.sh
│ ├── hooks/ # Lifecycle hooks (5): validate-shell.sh,
│ │ # session-context.sh, pre-tool-guard.sh, post-failure-proposal.sh, pre-compact-save.sh
│ ├── agents/ # Global agents (1): verify-subagent-result
│ ├── agent-catalog/ # Opt-in agents (19): available via `claude-agents` function
│ │ # dev: build-validator, code-architect, code-simplifier, verify-app, verify-shell
Expand Down Expand Up @@ -129,15 +129,21 @@ The `claude/` directory contains Claude Code settings managed by this repository
- `settings.json` - Hooks, plugins, permissions, statusLine config
- `statusline.sh` - Status line display script
- `CLAUDE.md` - User global instructions (Workflow Orchestration)
- Plan Mode Default, Subagent Strategy, Self-Improvement Loop
- Plan Mode Default, Subagent Strategy, Self-Improvement Loop (+ Memory Separation)
- Verification Before Done, Demand Elegance, Autonomous Bug Fixing
- Task Management, Core Principles

**Hooks** (4):
**Hooks** (5):
- `hooks/validate-shell.sh` - PostToolUse hook for shellcheck
- `hooks/session-context.sh` - SessionStart hook for project context injection
- `hooks/session-context.sh` - SessionStart hook for project context injection (+ PreCompact context restore)
- `hooks/pre-tool-guard.sh` - PreToolUse hook for sensitive file access blocking
- `hooks/post-verify-rule-proposal.sh` - PostToolUse hook for governance failure capture
- `hooks/post-failure-proposal.sh` - PostToolUseFailure hook for governance failure capture (Bash/Write/Edit)
- `hooks/pre-compact-save.sh` - PreCompact hook for working state preservation

**Memory Architecture**:
- Auto-Memory (`~/.claude/memory/`): tool patterns, environment info, API knowledge (auto-managed)
- `tasks/lessons.md`: user corrections, mistake patterns, project-specific rules (explicit)
- Rule: "corrected by user → lessons.md, discovered preference → auto-memory"

**Global Agents** (1, always loaded):
- `verify-subagent-result` - SubAgent verification
Expand Down
5 changes: 5 additions & 0 deletions claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
- Ruthlessly iterate on these lessons until mistake rate drops
- Review lessons at session start for relevant project

### Memory Separation
- **Auto-Memory** (`~/.claude/memory/`): tool patterns, environment info, API knowledge → let Claude Code manage automatically
- **tasks/lessons.md**: user corrections, mistake patterns, project-specific rules → record explicitly
- Rule: "corrected by user → lessons.md, discovered preference → auto-memory"


## 4. Verification Before Done
- Never mark a task complete without proving it works
Expand Down
82 changes: 82 additions & 0 deletions claude/hooks/post-failure-proposal.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/bin/bash
# PostToolUseFailure hook: Capture tool failures and propose governance rules
# Fires only on Bash/Write/Edit failures (no overhead on success).
# Records test/build/lint failures to ~/.claude/governance/proposals/ for later analysis.

# Read failure result from stdin
input=$(cat)

# Skip user interrupts (Ctrl+C)
is_interrupt=$(echo "$input" | jq -r '.is_interrupt // false' 2>/dev/null)
if [[ "$is_interrupt" == "true" ]]; then
exit 0
fi

# Extract tool name and error info
tool_name=$(echo "$input" | jq -r '.tool_name // "unknown"' 2>/dev/null)
error=$(echo "$input" | jq -r '.error // ""' 2>/dev/null)

# For Bash failures, check if the command is relevant (test/build/lint)
if [[ "$tool_name" == "Bash" ]]; then
command=$(echo "$input" | jq -r '.tool_input.command // "unknown"' 2>/dev/null)

is_relevant=false
case "$command" in
*jest*|*vitest*|*pytest*|*mocha*|*test*)
failure_type="test"
is_relevant=true
;;
*tsc*|*webpack*|*next\ build*|*vite\ build*|*build*)
failure_type="build"
is_relevant=true
;;
*eslint*|*prettier*|*rubocop*|*shellcheck*|*lint*)
failure_type="lint"
is_relevant=true
;;
*mypy*|*pyright*|*typecheck*)
failure_type="typecheck"
is_relevant=true
;;
esac

if [[ "$is_relevant" != "true" ]]; then
exit 0
fi
elif [[ "$tool_name" == "Write" ]] || [[ "$tool_name" == "Edit" ]]; then
failure_type="file_operation"
command="$tool_name"
else
exit 0
fi

# Generate proposal file
proposals_dir="$HOME/.claude/governance/proposals"
mkdir -p "$proposals_dir"

timestamp=$(date +%Y-%m-%d-%H%M%S)
proposal_file="$proposals_dir/${timestamp}.json"

# Truncate error to avoid massive files
truncated_error=$(echo "$error" | head -50)

# Get working directory context
cwd=$(echo "$input" | jq -r '.cwd // "unknown"' 2>/dev/null)

# Write proposal
cat > "$proposal_file" << PROPOSAL_EOF
{
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"tool_name": "$tool_name",
"failure_type": "$failure_type",
"command": $(echo "$command" | jq -Rs .),
"cwd": $(echo "$cwd" | jq -Rs .),
"error": $(echo "$truncated_error" | jq -Rs .),
"status": "pending",
"proposed_rule": null,
"reviewed_at": null
}
PROPOSAL_EOF

# Don't block Claude's workflow
exit 0
78 changes: 0 additions & 78 deletions claude/hooks/post-verify-rule-proposal.sh

This file was deleted.

47 changes: 47 additions & 0 deletions claude/hooks/pre-compact-save.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/bin/bash
# PreCompact hook: Save working state before context compaction
# Writes to ~/.claude/pre-compact-context.md (overwritten each time)
# Always exits 0 to never block compaction.

input=$(cat)

context_file="$HOME/.claude/pre-compact-context.md"

# Extract available fields from PreCompact input
cwd=$(echo "$input" | jq -r '.cwd // "unknown"' 2>/dev/null)
summary=$(echo "$input" | jq -r '.summary // ""' 2>/dev/null)

# Build context snapshot
{
echo "# Pre-Compact Context (auto-saved)"
echo ""
echo "**Saved at**: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
echo "**Working directory**: $cwd"
echo ""

# Include compaction summary if available
if [[ -n "$summary" ]] && [[ "$summary" != "null" ]]; then
echo "## Compaction Summary"
echo "$summary"
echo ""
fi

# Include tasks/todo.md if it exists in the working directory
todo_file="$cwd/tasks/todo.md"
if [[ -f "$todo_file" ]]; then
echo "## Active Tasks (tasks/todo.md)"
head -50 "$todo_file"
echo ""
fi

# Include custom instructions hint
claude_md="$cwd/CLAUDE.md"
if [[ -f "$claude_md" ]]; then
echo "## Project Instructions"
echo "CLAUDE.md exists at: $claude_md"
echo ""
fi
} > "$context_file"

# Never block compaction
exit 0
9 changes: 9 additions & 0 deletions claude/hooks/session-context.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,12 @@ last_commit=$(git -C "$current_dir" log -1 --oneline 2>/dev/null || echo "no com
worktree_count=$(git -C "$current_dir" worktree list 2>/dev/null | wc -l | tr -d ' ')

echo "Project context: branch=${branch}, last_commit=\"${last_commit}\", active_worktrees=${worktree_count}"

# Restore pre-compact context if available (one-shot restore)
context_file="$HOME/.claude/pre-compact-context.md"
if [[ -f "$context_file" ]]; then
echo ""
echo "--- Restored from pre-compact snapshot ---"
cat "$context_file"
rm -f "$context_file"
fi
19 changes: 16 additions & 3 deletions claude/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,26 @@
"command": "~/.claude/hooks/validate-shell.sh"
}
]
},
}
],
"PostToolUseFailure": [
{
"matcher": "Bash",
"matcher": "Bash|Write|Edit",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/post-failure-proposal.sh"
}
]
}
],
"PreCompact": [
{
"matcher": ".*",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/post-verify-rule-proposal.sh"
"command": "~/.claude/hooks/pre-compact-save.sh"
}
]
}
Expand Down
4 changes: 3 additions & 1 deletion install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,12 @@ create_symlinks() {

# claude hooks
mkdir -p "$HOME/.claude/hooks"
rm -f "$HOME/.claude/hooks/post-verify-rule-proposal.sh" # cleanup stale hook (replaced by post-failure-proposal.sh)
safe_ln "$DOTFILES_DIR/claude/hooks/validate-shell.sh" "$HOME/.claude/hooks/validate-shell.sh"
safe_ln "$DOTFILES_DIR/claude/hooks/session-context.sh" "$HOME/.claude/hooks/session-context.sh"
safe_ln "$DOTFILES_DIR/claude/hooks/pre-tool-guard.sh" "$HOME/.claude/hooks/pre-tool-guard.sh"
safe_ln "$DOTFILES_DIR/claude/hooks/post-verify-rule-proposal.sh" "$HOME/.claude/hooks/post-verify-rule-proposal.sh"
safe_ln "$DOTFILES_DIR/claude/hooks/post-failure-proposal.sh" "$HOME/.claude/hooks/post-failure-proposal.sh"
safe_ln "$DOTFILES_DIR/claude/hooks/pre-compact-save.sh" "$HOME/.claude/hooks/pre-compact-save.sh"

# claude CLAUDE.md (user global)
safe_ln "$DOTFILES_DIR/claude/CLAUDE.md" "$HOME/.claude/CLAUDE.md"
Expand Down