cc-discipline 2.10.1 → 2.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +236 -153
  2. package/README.zh-CN.md +299 -207
  3. package/bin/cli.sh +96 -96
  4. package/global/CLAUDE.md +45 -45
  5. package/init.sh +594 -594
  6. package/lib/doctor.sh +145 -145
  7. package/lib/stack-remove.sh +68 -68
  8. package/lib/status.sh +100 -100
  9. package/package.json +34 -34
  10. package/templates/.claude/agents/investigator.md +44 -44
  11. package/templates/.claude/agents/reviewer.md +46 -46
  12. package/templates/.claude/hooks/action-counter.sh +58 -58
  13. package/templates/.claude/hooks/git-guard.sh +62 -62
  14. package/templates/.claude/hooks/phase-gate.sh +10 -10
  15. package/templates/.claude/hooks/post-error-remind.sh +114 -114
  16. package/templates/.claude/hooks/pre-edit-guard.sh +100 -100
  17. package/templates/.claude/hooks/session-start.sh +44 -44
  18. package/templates/.claude/hooks/streak-breaker.sh +111 -111
  19. package/templates/.claude/rules/00-core-principles.md +16 -16
  20. package/templates/.claude/rules/01-debugging.md +32 -32
  21. package/templates/.claude/rules/02-before-edit.md +22 -22
  22. package/templates/.claude/rules/03-context-mgmt.md +44 -44
  23. package/templates/.claude/rules/04-no-mole-whacking.md +26 -26
  24. package/templates/.claude/rules/05-phase-discipline.md +15 -15
  25. package/templates/.claude/rules/06-multi-task.md +12 -12
  26. package/templates/.claude/rules/07-integrity.md +92 -92
  27. package/templates/.claude/rules/stacks/embedded.md +24 -24
  28. package/templates/.claude/rules/stacks/js-ts.md +21 -21
  29. package/templates/.claude/rules/stacks/mobile.md +16 -16
  30. package/templates/.claude/rules/stacks/python.md +20 -20
  31. package/templates/.claude/rules/stacks/rtl.md +24 -24
  32. package/templates/.claude/settings.json +84 -84
  33. package/templates/.claude/skills/commit/SKILL.md +40 -40
  34. package/templates/.claude/skills/evaluate/SKILL.md +57 -57
  35. package/templates/.claude/skills/investigate/SKILL.md +192 -192
  36. package/templates/.claude/skills/retro/SKILL.md +40 -40
  37. package/templates/.claude/skills/self-check/SKILL.md +112 -87
  38. package/templates/.claude/skills/summary/SKILL.md +48 -48
  39. package/templates/.claude/skills/think/SKILL.md +108 -108
  40. package/templates/CLAUDE.md +96 -96
  41. package/templates/docs/debug-log.md +48 -48
  42. package/templates/docs/progress.md +72 -72
  43. package/templates/memory/MEMORY.md +23 -23
@@ -1,114 +1,114 @@
1
- #!/bin/bash
2
- # post-error-remind.sh — PostToolUse / PostToolUseFailure hook
3
- # Detects error patterns in Bash output and reminds Claude to follow debugging discipline
4
- #
5
- # NOTE: We use exit 2 intentionally for Post hooks.
6
- # exit 0 is completely silent — no way to inject text from Post hooks.
7
- # exit 2 + stderr is the ONLY mechanism to show reminders to Claude after tool execution.
8
- # The tool has already executed — exit 2 doesn't block execution, it injects the message.
9
- #
10
- # Design principles:
11
- # - Only match REAL error patterns, not the word "error" in any context
12
- # - Skip non-Bash tools (Edit/Write/Read have their own error handling)
13
- # - Skip truncated output (large output ≠ error)
14
- # - Use specific patterns: line-start anchors, known failure formats
15
- #
16
- # exit 0 = silent pass (normal for Post hooks)
17
- # exit 2 + stderr = inject reminder into Claude's context
18
-
19
- RAW_INPUT=$(cat)
20
-
21
- # Extract tool name and response
22
- TOOL_NAME=""
23
- OUTPUT=""
24
-
25
- if command -v jq &>/dev/null; then
26
- TOOL_NAME=$(echo "$RAW_INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
27
- # PostToolUseFailure uses .error, PostToolUse uses .tool_response
28
- OUTPUT=$(echo "$RAW_INPUT" | jq -r '.error // empty' 2>/dev/null)
29
- if [ -z "$OUTPUT" ]; then
30
- OUTPUT=$(echo "$RAW_INPUT" | jq -r '.tool_response.output // empty' 2>/dev/null)
31
- fi
32
- fi
33
-
34
- # Fallback if jq unavailable
35
- if [ -z "$OUTPUT" ]; then
36
- OUTPUT="$RAW_INPUT"
37
- fi
38
-
39
- # --- Early exits for known non-error situations ---
40
-
41
- # Only check Bash tool output
42
- if [ -n "$TOOL_NAME" ] && [ "$TOOL_NAME" != "Bash" ]; then
43
- exit 0
44
- fi
45
-
46
- # Truncated output is not an error
47
- if echo "$OUTPUT" | grep -q "Output too large"; then
48
- exit 0
49
- fi
50
-
51
- # Successful git operations
52
- if echo "$OUTPUT" | grep -qE "^\[main |^\[master |^On branch |^nothing to commit|^Already up to date"; then
53
- exit 0
54
- fi
55
-
56
- # --- Detect REAL error patterns ---
57
-
58
- HAS_ERROR=false
59
- ERROR_TYPE=""
60
-
61
- # Build/compile errors (line-start or known formats)
62
- if echo "$OUTPUT" | grep -qE "^ERROR |^\[ERROR\]|BUILD FAILURE|compilation error|cannot find symbol|package .* does not exist"; then
63
- HAS_ERROR=true
64
- ERROR_TYPE="build"
65
- fi
66
-
67
- # Test failures (Maven/Gradle/Jest specific formats)
68
- if echo "$OUTPUT" | grep -qE "Tests run:.*Failures: [1-9]|Tests:.*failed|FAILED!|BUILD FAILURE.*test"; then
69
- HAS_ERROR=true
70
- ERROR_TYPE="test"
71
- fi
72
-
73
- # Runtime crashes
74
- if echo "$OUTPUT" | grep -qiE "segmentation fault|bus error|core dumped|SIGABRT|SIGSEGV|killed.*signal"; then
75
- HAS_ERROR=true
76
- ERROR_TYPE="crash"
77
- fi
78
-
79
- # Shell errors (command failures)
80
- if echo "$OUTPUT" | grep -qE "command not found|permission denied|cannot execute|not a git repository"; then
81
- HAS_ERROR=true
82
- ERROR_TYPE="system"
83
- fi
84
-
85
- # Stack traces (Java, Python, Node)
86
- if echo "$OUTPUT" | grep -qE "^Exception in thread|^Traceback \(most recent|^Caused by:.*Exception"; then
87
- HAS_ERROR=true
88
- ERROR_TYPE="exception"
89
- fi
90
-
91
- # npm/yarn explicit failure
92
- if echo "$OUTPUT" | grep -qE "^npm ERR!|^error .*ENOENT|FATAL ERROR"; then
93
- HAS_ERROR=true
94
- ERROR_TYPE="build"
95
- fi
96
-
97
- # --- Emit reminder if error detected ---
98
-
99
- if [ "$HAS_ERROR" = true ]; then
100
- REMINDER="Error encountered — debugging checklist: 1. Resist modifying code immediately 2. Fully understand the error message 3. List >=3 possible causes — label them hypotheses, not root cause 4. Record in docs/debug-log.md 5. Eliminate >=2 hypotheses with evidence before identifying root cause 6. Only then fix. Important: after seeing one error, the first explanation is a hypothesis, not a conclusion. Say 'possible cause' until you have elimination evidence."
101
-
102
- if [ "$ERROR_TYPE" = "test" ]; then
103
- REMINDER="$REMINDER Note: Test failure — before changing the test, first determine if it's a code bug or an outdated test."
104
- fi
105
-
106
- if [ "$ERROR_TYPE" = "crash" ]; then
107
- REMINDER="$REMINDER Note: Crash/segfault — may involve memory issues."
108
- fi
109
-
110
- echo "$REMINDER" >&2
111
- exit 2
112
- fi
113
-
114
- exit 0
1
+ #!/bin/bash
2
+ # post-error-remind.sh — PostToolUse / PostToolUseFailure hook
3
+ # Detects error patterns in Bash output and reminds Claude to follow debugging discipline
4
+ #
5
+ # NOTE: We use exit 2 intentionally for Post hooks.
6
+ # exit 0 is completely silent — no way to inject text from Post hooks.
7
+ # exit 2 + stderr is the ONLY mechanism to show reminders to Claude after tool execution.
8
+ # The tool has already executed — exit 2 doesn't block execution, it injects the message.
9
+ #
10
+ # Design principles:
11
+ # - Only match REAL error patterns, not the word "error" in any context
12
+ # - Skip non-Bash tools (Edit/Write/Read have their own error handling)
13
+ # - Skip truncated output (large output ≠ error)
14
+ # - Use specific patterns: line-start anchors, known failure formats
15
+ #
16
+ # exit 0 = silent pass (normal for Post hooks)
17
+ # exit 2 + stderr = inject reminder into Claude's context
18
+
19
+ RAW_INPUT=$(cat)
20
+
21
+ # Extract tool name and response
22
+ TOOL_NAME=""
23
+ OUTPUT=""
24
+
25
+ if command -v jq &>/dev/null; then
26
+ TOOL_NAME=$(echo "$RAW_INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
27
+ # PostToolUseFailure uses .error, PostToolUse uses .tool_response
28
+ OUTPUT=$(echo "$RAW_INPUT" | jq -r '.error // empty' 2>/dev/null)
29
+ if [ -z "$OUTPUT" ]; then
30
+ OUTPUT=$(echo "$RAW_INPUT" | jq -r '.tool_response.output // empty' 2>/dev/null)
31
+ fi
32
+ fi
33
+
34
+ # Fallback if jq unavailable
35
+ if [ -z "$OUTPUT" ]; then
36
+ OUTPUT="$RAW_INPUT"
37
+ fi
38
+
39
+ # --- Early exits for known non-error situations ---
40
+
41
+ # Only check Bash tool output
42
+ if [ -n "$TOOL_NAME" ] && [ "$TOOL_NAME" != "Bash" ]; then
43
+ exit 0
44
+ fi
45
+
46
+ # Truncated output is not an error
47
+ if echo "$OUTPUT" | grep -q "Output too large"; then
48
+ exit 0
49
+ fi
50
+
51
+ # Successful git operations
52
+ if echo "$OUTPUT" | grep -qE "^\[main |^\[master |^On branch |^nothing to commit|^Already up to date"; then
53
+ exit 0
54
+ fi
55
+
56
+ # --- Detect REAL error patterns ---
57
+
58
+ HAS_ERROR=false
59
+ ERROR_TYPE=""
60
+
61
+ # Build/compile errors (line-start or known formats)
62
+ if echo "$OUTPUT" | grep -qE "^ERROR |^\[ERROR\]|BUILD FAILURE|compilation error|cannot find symbol|package .* does not exist"; then
63
+ HAS_ERROR=true
64
+ ERROR_TYPE="build"
65
+ fi
66
+
67
+ # Test failures (Maven/Gradle/Jest specific formats)
68
+ if echo "$OUTPUT" | grep -qE "Tests run:.*Failures: [1-9]|Tests:.*failed|FAILED!|BUILD FAILURE.*test"; then
69
+ HAS_ERROR=true
70
+ ERROR_TYPE="test"
71
+ fi
72
+
73
+ # Runtime crashes
74
+ if echo "$OUTPUT" | grep -qiE "segmentation fault|bus error|core dumped|SIGABRT|SIGSEGV|killed.*signal"; then
75
+ HAS_ERROR=true
76
+ ERROR_TYPE="crash"
77
+ fi
78
+
79
+ # Shell errors (command failures)
80
+ if echo "$OUTPUT" | grep -qE "command not found|permission denied|cannot execute|not a git repository"; then
81
+ HAS_ERROR=true
82
+ ERROR_TYPE="system"
83
+ fi
84
+
85
+ # Stack traces (Java, Python, Node)
86
+ if echo "$OUTPUT" | grep -qE "^Exception in thread|^Traceback \(most recent|^Caused by:.*Exception"; then
87
+ HAS_ERROR=true
88
+ ERROR_TYPE="exception"
89
+ fi
90
+
91
+ # npm/yarn explicit failure
92
+ if echo "$OUTPUT" | grep -qE "^npm ERR!|^error .*ENOENT|FATAL ERROR"; then
93
+ HAS_ERROR=true
94
+ ERROR_TYPE="build"
95
+ fi
96
+
97
+ # --- Emit reminder if error detected ---
98
+
99
+ if [ "$HAS_ERROR" = true ]; then
100
+ REMINDER="Error encountered — debugging checklist: 1. Resist modifying code immediately 2. Fully understand the error message 3. List >=3 possible causes — label them hypotheses, not root cause 4. Record in docs/debug-log.md 5. Eliminate >=2 hypotheses with evidence before identifying root cause 6. Only then fix. Important: after seeing one error, the first explanation is a hypothesis, not a conclusion. Say 'possible cause' until you have elimination evidence."
101
+
102
+ if [ "$ERROR_TYPE" = "test" ]; then
103
+ REMINDER="$REMINDER Note: Test failure — before changing the test, first determine if it's a code bug or an outdated test."
104
+ fi
105
+
106
+ if [ "$ERROR_TYPE" = "crash" ]; then
107
+ REMINDER="$REMINDER Note: Crash/segfault — may involve memory issues."
108
+ fi
109
+
110
+ echo "$REMINDER" >&2
111
+ exit 2
112
+ fi
113
+
114
+ exit 0
@@ -1,100 +1,100 @@
1
- #!/bin/bash
2
- # pre-edit-guard.sh — PreToolUse hook
3
- # Checks that Claude has finished debugging before editing source code
4
- #
5
- # Exit 0 + no output = allow edit
6
- # Exit 2 + stderr = block edit, stderr shown to Claude
7
-
8
- # Read the tool input from stdin (JSON)
9
- INPUT=$(cat)
10
-
11
- # Extract fields
12
- if command -v jq &>/dev/null; then
13
- FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
14
- CWD=$(echo "$INPUT" | jq -r '.cwd // empty' 2>/dev/null)
15
- else
16
- FILE_PATH=$(echo "$INPUT" | grep -o '"file_path":\s*"[^"]*"' | head -1 | sed 's/"file_path":\s*"//;s/"//')
17
- CWD=$(echo "$INPUT" | grep -o '"cwd":\s*"[^"]*"' | head -1 | sed 's/"cwd":\s*"//;s/"//')
18
- fi
19
-
20
- # Extract just the filename for pattern matching (avoid false matches on directory names)
21
- BASENAME=$(basename "$FILE_PATH")
22
-
23
- # Allow edits to docs/
24
- # Note: use -E (extended regex) for portability — BSD grep (macOS) doesn't support \| in basic mode
25
- if echo "$FILE_PATH" | grep -qE "^docs/|/docs/"; then
26
- exit 0
27
- fi
28
-
29
- # Allow edits to test files (match filename only, not directory path)
30
- if echo "$BASENAME" | grep -qiE "test|spec"; then
31
- exit 0
32
- fi
33
-
34
- # Allow edits to config/meta files
35
- if echo "$BASENAME" | grep -qiE "\.(md|json|yaml|yml|toml|cfg|ini)$"; then
36
- exit 0
37
- fi
38
-
39
- # Check for unresolved hypotheses in debug-log.md
40
- DEBUG_LOG=""
41
- if [ -n "$CWD" ] && [ -f "$CWD/docs/debug-log.md" ]; then
42
- DEBUG_LOG="$CWD/docs/debug-log.md"
43
- elif [ -f "docs/debug-log.md" ]; then
44
- DEBUG_LOG="docs/debug-log.md"
45
- fi
46
-
47
- if [ -n "$DEBUG_LOG" ]; then
48
- # Count only in actual table rows, strip HTML comments (both single-line and multi-line)
49
- CLEAN=$(awk '/<!--.*-->/{next} /<!--/{skip=1} /-->/{skip=0;next} !skip{print}' "$DEBUG_LOG" 2>/dev/null)
50
- PENDING=$(echo "$CLEAN" | grep -c '| pending |' 2>/dev/null) || PENDING=0
51
- CONFIRMED=$(echo "$CLEAN" | grep -c '| confirmed |' 2>/dev/null) || CONFIRMED=0
52
-
53
- if [ "$PENDING" -gt "$CONFIRMED" ] 2>/dev/null; then
54
- cat >&2 <<EOF
55
- docs/debug-log.md has $((PENDING - CONFIRMED)) unverified hypotheses.
56
- Please complete the debugging process (verify or eliminate hypotheses) before editing source code.
57
- If you have confirmed the root cause, update debug-log.md first.
58
- EOF
59
- exit 2
60
- fi
61
- fi
62
-
63
- # ─── Large diff warning ───
64
- HAS_JQ=false
65
- command -v jq &>/dev/null && HAS_JQ=true
66
-
67
- if [ "$HAS_JQ" = true ]; then
68
- NEW_STRING=$(echo "$INPUT" | jq -r '.tool_input.new_string // ""')
69
- OLD_STRING=$(echo "$INPUT" | jq -r '.tool_input.old_string // ""')
70
- NEW_LINES=$(echo "$NEW_STRING" | wc -l | tr -d ' ')
71
- OLD_LINES=$(echo "$OLD_STRING" | wc -l | tr -d ' ')
72
- DIFF_LINES=$((NEW_LINES > OLD_LINES ? NEW_LINES : OLD_LINES))
73
- if [ "$DIFF_LINES" -gt 200 ]; then
74
- echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"LARGE EDIT NOTE: This edit involves ${DIFF_LINES} lines. Consider: is this the minimal change needed? Could it be broken into smaller, more focused edits?\"}}"
75
- exit 0
76
- fi
77
- fi
78
-
79
- # ─── New tool/script detection ───
80
- # When creating a script file via Write, remind to register in CLAUDE.md
81
- TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
82
- if [ "$TOOL_NAME" = "Write" ] && echo "$BASENAME" | grep -qiE "\.(sh|py|js|ts|rb|pl)$"; then
83
- # Check if file already exists (new file = tool creation)
84
- FULL_PATH="$FILE_PATH"
85
- if [ ! -f "$FULL_PATH" ]; then
86
- cat <<JSONEOF
87
- {"hookSpecificOutput":{"hookEventName":"PreToolUse","additionalContext":"NEW SCRIPT DETECTED: You are creating $BASENAME. If this is a reusable tool/helper, register it in CLAUDE.md under 'Project Tools' now (path, purpose, usage, date) — capturing it while context is fresh saves time later."}}
88
- JSONEOF
89
- exit 0
90
- fi
91
- fi
92
-
93
- # ─── Bug-fix sanity check ───
94
- # Inject a lightweight reminder on source file edits:
95
- # "If this is a bug fix, have you eliminated alternative hypotheses?"
96
- # Uses additionalContext (non-blocking) so it doesn't slow down normal edits.
97
- cat <<JSONEOF
98
- {"hookSpecificOutput":{"hookEventName":"PreToolUse","additionalContext":"If this edit is a bug fix: have you listed >=3 possible causes and eliminated >=2 with evidence? Thorough elimination before fixing prevents wasted cycles. Use 'possible cause' until elimination evidence confirms the root cause."}}
99
- JSONEOF
100
- exit 0
1
+ #!/bin/bash
2
+ # pre-edit-guard.sh — PreToolUse hook
3
+ # Checks that Claude has finished debugging before editing source code
4
+ #
5
+ # Exit 0 + no output = allow edit
6
+ # Exit 2 + stderr = block edit, stderr shown to Claude
7
+
8
+ # Read the tool input from stdin (JSON)
9
+ INPUT=$(cat)
10
+
11
+ # Extract fields
12
+ if command -v jq &>/dev/null; then
13
+ FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
14
+ CWD=$(echo "$INPUT" | jq -r '.cwd // empty' 2>/dev/null)
15
+ else
16
+ FILE_PATH=$(echo "$INPUT" | grep -o '"file_path":\s*"[^"]*"' | head -1 | sed 's/"file_path":\s*"//;s/"//')
17
+ CWD=$(echo "$INPUT" | grep -o '"cwd":\s*"[^"]*"' | head -1 | sed 's/"cwd":\s*"//;s/"//')
18
+ fi
19
+
20
+ # Extract just the filename for pattern matching (avoid false matches on directory names)
21
+ BASENAME=$(basename "$FILE_PATH")
22
+
23
+ # Allow edits to docs/
24
+ # Note: use -E (extended regex) for portability — BSD grep (macOS) doesn't support \| in basic mode
25
+ if echo "$FILE_PATH" | grep -qE "^docs/|/docs/"; then
26
+ exit 0
27
+ fi
28
+
29
+ # Allow edits to test files (match filename only, not directory path)
30
+ if echo "$BASENAME" | grep -qiE "test|spec"; then
31
+ exit 0
32
+ fi
33
+
34
+ # Allow edits to config/meta files
35
+ if echo "$BASENAME" | grep -qiE "\.(md|json|yaml|yml|toml|cfg|ini)$"; then
36
+ exit 0
37
+ fi
38
+
39
+ # Check for unresolved hypotheses in debug-log.md
40
+ DEBUG_LOG=""
41
+ if [ -n "$CWD" ] && [ -f "$CWD/docs/debug-log.md" ]; then
42
+ DEBUG_LOG="$CWD/docs/debug-log.md"
43
+ elif [ -f "docs/debug-log.md" ]; then
44
+ DEBUG_LOG="docs/debug-log.md"
45
+ fi
46
+
47
+ if [ -n "$DEBUG_LOG" ]; then
48
+ # Count only in actual table rows, strip HTML comments (both single-line and multi-line)
49
+ CLEAN=$(awk '/<!--.*-->/{next} /<!--/{skip=1} /-->/{skip=0;next} !skip{print}' "$DEBUG_LOG" 2>/dev/null)
50
+ PENDING=$(echo "$CLEAN" | grep -c '| pending |' 2>/dev/null) || PENDING=0
51
+ CONFIRMED=$(echo "$CLEAN" | grep -c '| confirmed |' 2>/dev/null) || CONFIRMED=0
52
+
53
+ if [ "$PENDING" -gt "$CONFIRMED" ] 2>/dev/null; then
54
+ cat >&2 <<EOF
55
+ docs/debug-log.md has $((PENDING - CONFIRMED)) unverified hypotheses.
56
+ Please complete the debugging process (verify or eliminate hypotheses) before editing source code.
57
+ If you have confirmed the root cause, update debug-log.md first.
58
+ EOF
59
+ exit 2
60
+ fi
61
+ fi
62
+
63
+ # ─── Large diff warning ───
64
+ HAS_JQ=false
65
+ command -v jq &>/dev/null && HAS_JQ=true
66
+
67
+ if [ "$HAS_JQ" = true ]; then
68
+ NEW_STRING=$(echo "$INPUT" | jq -r '.tool_input.new_string // ""')
69
+ OLD_STRING=$(echo "$INPUT" | jq -r '.tool_input.old_string // ""')
70
+ NEW_LINES=$(echo "$NEW_STRING" | wc -l | tr -d ' ')
71
+ OLD_LINES=$(echo "$OLD_STRING" | wc -l | tr -d ' ')
72
+ DIFF_LINES=$((NEW_LINES > OLD_LINES ? NEW_LINES : OLD_LINES))
73
+ if [ "$DIFF_LINES" -gt 200 ]; then
74
+ echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"LARGE EDIT NOTE: This edit involves ${DIFF_LINES} lines. Consider: is this the minimal change needed? Could it be broken into smaller, more focused edits?\"}}"
75
+ exit 0
76
+ fi
77
+ fi
78
+
79
+ # ─── New tool/script detection ───
80
+ # When creating a script file via Write, remind to register in CLAUDE.md
81
+ TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
82
+ if [ "$TOOL_NAME" = "Write" ] && echo "$BASENAME" | grep -qiE "\.(sh|py|js|ts|rb|pl)$"; then
83
+ # Check if file already exists (new file = tool creation)
84
+ FULL_PATH="$FILE_PATH"
85
+ if [ ! -f "$FULL_PATH" ]; then
86
+ cat <<JSONEOF
87
+ {"hookSpecificOutput":{"hookEventName":"PreToolUse","additionalContext":"NEW SCRIPT DETECTED: You are creating $BASENAME. If this is a reusable tool/helper, register it in CLAUDE.md under 'Project Tools' now (path, purpose, usage, date) — capturing it while context is fresh saves time later."}}
88
+ JSONEOF
89
+ exit 0
90
+ fi
91
+ fi
92
+
93
+ # ─── Bug-fix sanity check ───
94
+ # Inject a lightweight reminder on source file edits:
95
+ # "If this is a bug fix, have you eliminated alternative hypotheses?"
96
+ # Uses additionalContext (non-blocking) so it doesn't slow down normal edits.
97
+ cat <<JSONEOF
98
+ {"hookSpecificOutput":{"hookEventName":"PreToolUse","additionalContext":"If this edit is a bug fix: have you listed >=3 possible causes and eliminated >=2 with evidence? Thorough elimination before fixing prevents wasted cycles. Use 'possible cause' until elimination evidence confirms the root cause."}}
99
+ JSONEOF
100
+ exit 0
@@ -1,44 +1,44 @@
1
- #!/bin/bash
2
- # cc-discipline: SessionStart hook
3
- # Injects project state + discipline reminders into Claude's context.
4
- # stdout → context (Claude can see and act on it)
5
- # Fires on: startup, resume, clear, compact
6
-
7
- # Reset action counter for this session
8
- INPUT=$(cat)
9
- SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"' 2>/dev/null)
10
- if [ -n "$SESSION_ID" ] && [ "$SESSION_ID" != "unknown" ]; then
11
- rm -f "/tmp/cc-discipline-${SESSION_ID}/action-count"
12
- fi
13
-
14
- # Read project state
15
- PROGRESS=""
16
- if [ -f "docs/progress.md" ]; then
17
- PROGRESS=$(tail -20 docs/progress.md)
18
- fi
19
-
20
- cat <<'HEADER'
21
- [cc-discipline] Session initialized.
22
- HEADER
23
-
24
- if [ -n "$PROGRESS" ]; then
25
- cat <<EOF
26
-
27
- Project state (from docs/progress.md):
28
- $PROGRESS
29
-
30
- Verify project status by reading files or asking — don't assume beyond what is stated above.
31
- EOF
32
- fi
33
-
34
- cat <<'EOF'
35
-
36
- Reminders:
37
- - /self-check available for periodic monitoring. For complex tasks: /loop 10m /self-check
38
- - Before editing: root cause identified? scope respected? change recorded?
39
- - 3 consecutive failures → pause and regroup with the user
40
- - Confirm the approach with the user before starting implementation
41
- - Verify project state (phase, status, dependencies) by reading files or asking
42
- EOF
43
-
44
- exit 0
1
+ #!/bin/bash
2
+ # cc-discipline: SessionStart hook
3
+ # Injects project state + discipline reminders into Claude's context.
4
+ # stdout → context (Claude can see and act on it)
5
+ # Fires on: startup, resume, clear, compact
6
+
7
+ # Reset action counter for this session
8
+ INPUT=$(cat)
9
+ SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"' 2>/dev/null)
10
+ if [ -n "$SESSION_ID" ] && [ "$SESSION_ID" != "unknown" ]; then
11
+ rm -f "/tmp/cc-discipline-${SESSION_ID}/action-count"
12
+ fi
13
+
14
+ # Read project state
15
+ PROGRESS=""
16
+ if [ -f "docs/progress.md" ]; then
17
+ PROGRESS=$(tail -20 docs/progress.md)
18
+ fi
19
+
20
+ cat <<'HEADER'
21
+ [cc-discipline] Session initialized.
22
+ HEADER
23
+
24
+ if [ -n "$PROGRESS" ]; then
25
+ cat <<EOF
26
+
27
+ Project state (from docs/progress.md):
28
+ $PROGRESS
29
+
30
+ Verify project status by reading files or asking — don't assume beyond what is stated above.
31
+ EOF
32
+ fi
33
+
34
+ cat <<'EOF'
35
+
36
+ Reminders:
37
+ - /self-check available for periodic monitoring. For complex tasks: /loop 10m /self-check
38
+ - Before editing: root cause identified? scope respected? change recorded?
39
+ - 3 consecutive failures → pause and regroup with the user
40
+ - Confirm the approach with the user before starting implementation
41
+ - Verify project state (phase, status, dependencies) by reading files or asking
42
+ EOF
43
+
44
+ exit 0