cc-discipline 2.10.3 → 2.12.0
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.
- package/bin/cli.js +147 -147
- package/init.sh +9 -28
- package/lib/doctor.sh +6 -6
- package/lib/status.sh +5 -8
- package/package.json +1 -1
- package/templates/.claude/hooks/action-counter.sh +37 -13
- package/templates/.claude/hooks/git-guard.sh +33 -4
- package/templates/.claude/hooks/post-error-remind.sh +22 -8
- package/templates/.claude/hooks/pre-edit-guard.sh +45 -27
- package/templates/.claude/hooks/session-start.sh +14 -8
- package/templates/.claude/hooks/streak-breaker.sh +14 -7
- package/templates/.claude/rules/00-core-principles.md +1 -1
- package/templates/.claude/rules/02-before-edit.md +0 -11
- package/templates/.claude/rules/03-context-mgmt.md +6 -7
- package/templates/.claude/rules/07-integrity.md +0 -13
- package/templates/.claude/skills/finish/SKILL.md +44 -0
- package/templates/.claude/skills/retro/SKILL.md +16 -7
- package/templates/.claude/skills/self-check/SKILL.md +3 -2
- package/templates/.claude/skills/think/SKILL.md +10 -1
- package/templates/docs/progress.md +22 -0
package/bin/cli.js
CHANGED
|
@@ -1,147 +1,147 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// cc-discipline CLI entry point (cross-platform)
|
|
3
|
-
// Detects platform and spawns bash with correct paths
|
|
4
|
-
|
|
5
|
-
const { execSync, spawnSync } = require('child_process');
|
|
6
|
-
const path = require('path');
|
|
7
|
-
const fs = require('fs');
|
|
8
|
-
|
|
9
|
-
const PKG_DIR = path.resolve(__dirname, '..');
|
|
10
|
-
const args = process.argv.slice(2);
|
|
11
|
-
|
|
12
|
-
// Find bash executable
|
|
13
|
-
function findBash() {
|
|
14
|
-
// Unix: bash is always available
|
|
15
|
-
if (process.platform !== 'win32') return 'bash';
|
|
16
|
-
|
|
17
|
-
// Windows: try common Git Bash locations
|
|
18
|
-
const candidates = [
|
|
19
|
-
'C:\\Program Files\\Git\\bin\\bash.exe',
|
|
20
|
-
'C:\\Program Files (x86)\\Git\\bin\\bash.exe',
|
|
21
|
-
process.env.PROGRAMFILES + '\\Git\\bin\\bash.exe',
|
|
22
|
-
];
|
|
23
|
-
|
|
24
|
-
for (const candidate of candidates) {
|
|
25
|
-
if (fs.existsSync(candidate)) return candidate;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Try PATH
|
|
29
|
-
try {
|
|
30
|
-
execSync('bash --version', { stdio: 'ignore' });
|
|
31
|
-
return 'bash';
|
|
32
|
-
} catch (e) {
|
|
33
|
-
console.error('Error: bash not found. Please install Git for Windows (https://git-scm.com/download/win)');
|
|
34
|
-
console.error('Git Bash is required to run cc-discipline on Windows.');
|
|
35
|
-
process.exit(1);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const bash = findBash();
|
|
40
|
-
|
|
41
|
-
// Convert Windows path to Unix-style for bash
|
|
42
|
-
function toUnixPath(p) {
|
|
43
|
-
if (process.platform !== 'win32') return p;
|
|
44
|
-
// C:\Users\foo → /c/Users/foo
|
|
45
|
-
return p.replace(/\\/g, '/').replace(/^([A-Za-z]):/, (_, drive) => '/' + drive.toLowerCase());
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Route subcommands
|
|
49
|
-
const command = args[0] || 'init';
|
|
50
|
-
const restArgs = args.slice(1);
|
|
51
|
-
|
|
52
|
-
let script;
|
|
53
|
-
let scriptArgs;
|
|
54
|
-
|
|
55
|
-
switch (command) {
|
|
56
|
-
case 'init':
|
|
57
|
-
script = path.join(PKG_DIR, 'init.sh');
|
|
58
|
-
scriptArgs = restArgs;
|
|
59
|
-
break;
|
|
60
|
-
case 'upgrade':
|
|
61
|
-
script = path.join(PKG_DIR, 'init.sh');
|
|
62
|
-
scriptArgs = ['--auto', ...restArgs];
|
|
63
|
-
break;
|
|
64
|
-
case 'status':
|
|
65
|
-
script = path.join(PKG_DIR, 'lib', 'status.sh');
|
|
66
|
-
scriptArgs = [];
|
|
67
|
-
break;
|
|
68
|
-
case 'doctor':
|
|
69
|
-
script = path.join(PKG_DIR, 'lib', 'doctor.sh');
|
|
70
|
-
scriptArgs = [];
|
|
71
|
-
break;
|
|
72
|
-
case 'add-stack':
|
|
73
|
-
if (restArgs.length === 0) {
|
|
74
|
-
console.log('Usage: cc-discipline add-stack <numbers>');
|
|
75
|
-
console.log(' e.g.: cc-discipline add-stack 3 4');
|
|
76
|
-
process.exit(1);
|
|
77
|
-
}
|
|
78
|
-
script = path.join(PKG_DIR, 'init.sh');
|
|
79
|
-
scriptArgs = ['--stack', restArgs.join(' '), '--no-global'];
|
|
80
|
-
break;
|
|
81
|
-
case 'remove-stack':
|
|
82
|
-
script = path.join(PKG_DIR, 'lib', 'stack-remove.sh');
|
|
83
|
-
scriptArgs = restArgs;
|
|
84
|
-
break;
|
|
85
|
-
case '-v':
|
|
86
|
-
case '--version':
|
|
87
|
-
case 'version':
|
|
88
|
-
const pkg = require(path.join(PKG_DIR, 'package.json'));
|
|
89
|
-
console.log(`cc-discipline v${pkg.version}`);
|
|
90
|
-
process.exit(0);
|
|
91
|
-
case '-h':
|
|
92
|
-
case '--help':
|
|
93
|
-
case 'help':
|
|
94
|
-
const ver = require(path.join(PKG_DIR, 'package.json')).version;
|
|
95
|
-
console.log(`cc-discipline v${ver} — Discipline framework for Claude Code
|
|
96
|
-
|
|
97
|
-
Usage: cc-discipline <command> [options]
|
|
98
|
-
|
|
99
|
-
Commands:
|
|
100
|
-
init [options] Install discipline into current project (default)
|
|
101
|
-
upgrade Upgrade rules/hooks (shortcut for init --auto)
|
|
102
|
-
add-stack <numbers> Add stack rules (e.g., add-stack 3 4)
|
|
103
|
-
remove-stack <numbers> Remove stack rules
|
|
104
|
-
status Show installed version, stacks, and hooks
|
|
105
|
-
doctor Check installation integrity
|
|
106
|
-
version Show version
|
|
107
|
-
|
|
108
|
-
Init options:
|
|
109
|
-
--auto Non-interactive with defaults
|
|
110
|
-
--stack <choices> Stack selection: 1-7, space-separated
|
|
111
|
-
--name <name> Project name (default: directory name)
|
|
112
|
-
--global Install global rules to ~/.claude/CLAUDE.md
|
|
113
|
-
--no-global Skip global rules install
|
|
114
|
-
|
|
115
|
-
Stacks:
|
|
116
|
-
1=RTL 2=Embedded 3=Python 4=JS/TS 5=Mobile 6=Fullstack 7=General
|
|
117
|
-
|
|
118
|
-
Examples:
|
|
119
|
-
npx cc-discipline # Interactive setup
|
|
120
|
-
npx cc-discipline init --auto # Non-interactive defaults
|
|
121
|
-
npx cc-discipline init --auto --stack "3 4" # Python + JS/TS
|
|
122
|
-
npx cc-discipline upgrade # Upgrade to latest
|
|
123
|
-
npx cc-discipline status # Check what's installed
|
|
124
|
-
npx cc-discipline doctor # Diagnose issues`);
|
|
125
|
-
process.exit(0);
|
|
126
|
-
default:
|
|
127
|
-
console.error(`Unknown command: ${command}`);
|
|
128
|
-
console.error("Run 'cc-discipline --help' for usage");
|
|
129
|
-
process.exit(1);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Run the bash script
|
|
133
|
-
const unixScript = toUnixPath(script);
|
|
134
|
-
const pkgVersion = require(path.join(PKG_DIR, 'package.json')).version;
|
|
135
|
-
const env = {
|
|
136
|
-
...process.env,
|
|
137
|
-
CC_DISCIPLINE_PKG_DIR: process.platform === 'win32' ? toUnixPath(PKG_DIR) : PKG_DIR,
|
|
138
|
-
CC_DISCIPLINE_VERSION: pkgVersion,
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
const result = spawnSync(bash, [unixScript, ...scriptArgs], {
|
|
142
|
-
stdio: 'inherit',
|
|
143
|
-
env,
|
|
144
|
-
cwd: process.cwd(),
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
process.exit(result.status || 0);
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// cc-discipline CLI entry point (cross-platform)
|
|
3
|
+
// Detects platform and spawns bash with correct paths
|
|
4
|
+
|
|
5
|
+
const { execSync, spawnSync } = require('child_process');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
|
|
9
|
+
const PKG_DIR = path.resolve(__dirname, '..');
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
|
|
12
|
+
// Find bash executable
|
|
13
|
+
function findBash() {
|
|
14
|
+
// Unix: bash is always available
|
|
15
|
+
if (process.platform !== 'win32') return 'bash';
|
|
16
|
+
|
|
17
|
+
// Windows: try common Git Bash locations
|
|
18
|
+
const candidates = [
|
|
19
|
+
'C:\\Program Files\\Git\\bin\\bash.exe',
|
|
20
|
+
'C:\\Program Files (x86)\\Git\\bin\\bash.exe',
|
|
21
|
+
process.env.PROGRAMFILES + '\\Git\\bin\\bash.exe',
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
for (const candidate of candidates) {
|
|
25
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Try PATH
|
|
29
|
+
try {
|
|
30
|
+
execSync('bash --version', { stdio: 'ignore' });
|
|
31
|
+
return 'bash';
|
|
32
|
+
} catch (e) {
|
|
33
|
+
console.error('Error: bash not found. Please install Git for Windows (https://git-scm.com/download/win)');
|
|
34
|
+
console.error('Git Bash is required to run cc-discipline on Windows.');
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const bash = findBash();
|
|
40
|
+
|
|
41
|
+
// Convert Windows path to Unix-style for bash
|
|
42
|
+
function toUnixPath(p) {
|
|
43
|
+
if (process.platform !== 'win32') return p;
|
|
44
|
+
// C:\Users\foo → /c/Users/foo
|
|
45
|
+
return p.replace(/\\/g, '/').replace(/^([A-Za-z]):/, (_, drive) => '/' + drive.toLowerCase());
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Route subcommands
|
|
49
|
+
const command = args[0] || 'init';
|
|
50
|
+
const restArgs = args.slice(1);
|
|
51
|
+
|
|
52
|
+
let script;
|
|
53
|
+
let scriptArgs;
|
|
54
|
+
|
|
55
|
+
switch (command) {
|
|
56
|
+
case 'init':
|
|
57
|
+
script = path.join(PKG_DIR, 'init.sh');
|
|
58
|
+
scriptArgs = restArgs;
|
|
59
|
+
break;
|
|
60
|
+
case 'upgrade':
|
|
61
|
+
script = path.join(PKG_DIR, 'init.sh');
|
|
62
|
+
scriptArgs = ['--auto', ...restArgs];
|
|
63
|
+
break;
|
|
64
|
+
case 'status':
|
|
65
|
+
script = path.join(PKG_DIR, 'lib', 'status.sh');
|
|
66
|
+
scriptArgs = [];
|
|
67
|
+
break;
|
|
68
|
+
case 'doctor':
|
|
69
|
+
script = path.join(PKG_DIR, 'lib', 'doctor.sh');
|
|
70
|
+
scriptArgs = [];
|
|
71
|
+
break;
|
|
72
|
+
case 'add-stack':
|
|
73
|
+
if (restArgs.length === 0) {
|
|
74
|
+
console.log('Usage: cc-discipline add-stack <numbers>');
|
|
75
|
+
console.log(' e.g.: cc-discipline add-stack 3 4');
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
script = path.join(PKG_DIR, 'init.sh');
|
|
79
|
+
scriptArgs = ['--stack', restArgs.join(' '), '--no-global'];
|
|
80
|
+
break;
|
|
81
|
+
case 'remove-stack':
|
|
82
|
+
script = path.join(PKG_DIR, 'lib', 'stack-remove.sh');
|
|
83
|
+
scriptArgs = restArgs;
|
|
84
|
+
break;
|
|
85
|
+
case '-v':
|
|
86
|
+
case '--version':
|
|
87
|
+
case 'version':
|
|
88
|
+
const pkg = require(path.join(PKG_DIR, 'package.json'));
|
|
89
|
+
console.log(`cc-discipline v${pkg.version}`);
|
|
90
|
+
process.exit(0);
|
|
91
|
+
case '-h':
|
|
92
|
+
case '--help':
|
|
93
|
+
case 'help':
|
|
94
|
+
const ver = require(path.join(PKG_DIR, 'package.json')).version;
|
|
95
|
+
console.log(`cc-discipline v${ver} — Discipline framework for Claude Code
|
|
96
|
+
|
|
97
|
+
Usage: cc-discipline <command> [options]
|
|
98
|
+
|
|
99
|
+
Commands:
|
|
100
|
+
init [options] Install discipline into current project (default)
|
|
101
|
+
upgrade Upgrade rules/hooks (shortcut for init --auto)
|
|
102
|
+
add-stack <numbers> Add stack rules (e.g., add-stack 3 4)
|
|
103
|
+
remove-stack <numbers> Remove stack rules
|
|
104
|
+
status Show installed version, stacks, and hooks
|
|
105
|
+
doctor Check installation integrity
|
|
106
|
+
version Show version
|
|
107
|
+
|
|
108
|
+
Init options:
|
|
109
|
+
--auto Non-interactive with defaults
|
|
110
|
+
--stack <choices> Stack selection: 1-7, space-separated
|
|
111
|
+
--name <name> Project name (default: directory name)
|
|
112
|
+
--global Install global rules to ~/.claude/CLAUDE.md
|
|
113
|
+
--no-global Skip global rules install
|
|
114
|
+
|
|
115
|
+
Stacks:
|
|
116
|
+
1=RTL 2=Embedded 3=Python 4=JS/TS 5=Mobile 6=Fullstack 7=General
|
|
117
|
+
|
|
118
|
+
Examples:
|
|
119
|
+
npx cc-discipline # Interactive setup
|
|
120
|
+
npx cc-discipline init --auto # Non-interactive defaults
|
|
121
|
+
npx cc-discipline init --auto --stack "3 4" # Python + JS/TS
|
|
122
|
+
npx cc-discipline upgrade # Upgrade to latest
|
|
123
|
+
npx cc-discipline status # Check what's installed
|
|
124
|
+
npx cc-discipline doctor # Diagnose issues`);
|
|
125
|
+
process.exit(0);
|
|
126
|
+
default:
|
|
127
|
+
console.error(`Unknown command: ${command}`);
|
|
128
|
+
console.error("Run 'cc-discipline --help' for usage");
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Run the bash script
|
|
133
|
+
const unixScript = toUnixPath(script);
|
|
134
|
+
const pkgVersion = require(path.join(PKG_DIR, 'package.json')).version;
|
|
135
|
+
const env = {
|
|
136
|
+
...process.env,
|
|
137
|
+
CC_DISCIPLINE_PKG_DIR: process.platform === 'win32' ? toUnixPath(PKG_DIR) : PKG_DIR,
|
|
138
|
+
CC_DISCIPLINE_VERSION: pkgVersion,
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const result = spawnSync(bash, [unixScript, ...scriptArgs], {
|
|
142
|
+
stdio: 'inherit',
|
|
143
|
+
env,
|
|
144
|
+
cwd: process.cwd(),
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
process.exit(result.status || 0);
|
package/init.sh
CHANGED
|
@@ -365,20 +365,13 @@ cp "$SCRIPT_DIR/templates/.claude/agents/investigator.md" .claude/agents/
|
|
|
365
365
|
|
|
366
366
|
# ─── Install skills ───
|
|
367
367
|
echo -e "${GREEN}Installing skills...${NC}"
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
cp -r "$
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
echo " ✓ /commit — smart commit (test → update memory → commit)"
|
|
376
|
-
echo " ✓ /self-check — periodic discipline check (use with /loop 10m /self-check)"
|
|
377
|
-
echo " ✓ /evaluate — evaluate external review/advice against codebase context"
|
|
378
|
-
echo " ✓ /think — stop and think before coding (ask → propose → wait)"
|
|
379
|
-
echo " ✓ /retro — post-task retrospective (project + framework feedback)"
|
|
380
|
-
echo " ✓ /summary — write high-quality compact option before /compact"
|
|
381
|
-
echo " ✓ /investigate — multi-agent cross-investigation and proposal review"
|
|
368
|
+
# Install every skill directory under templates/ — no per-skill enumeration,
|
|
369
|
+
# so adding a new skill needs zero changes here.
|
|
370
|
+
for skill_dir in "$SCRIPT_DIR"/templates/.claude/skills/*/; do
|
|
371
|
+
[ -d "$skill_dir" ] || continue
|
|
372
|
+
cp -r "$skill_dir" .claude/skills/
|
|
373
|
+
echo " ✓ /$(basename "$skill_dir")"
|
|
374
|
+
done
|
|
382
375
|
|
|
383
376
|
# ─── Handle CLAUDE.md ───
|
|
384
377
|
if [ ! -f "CLAUDE.md" ]; then
|
|
@@ -534,13 +527,7 @@ if [ "$INSTALL_MODE" = "fresh" ]; then
|
|
|
534
527
|
echo -e " ${GREEN}.claude/rules/${NC} ← Auto-injected rules"
|
|
535
528
|
echo -e " ${GREEN}.claude/hooks/${NC} ← 7 discipline hooks (edit guard, streak breaker, git guard, phase gate, action counter, error remind, session start)"
|
|
536
529
|
echo -e " ${GREEN}.claude/agents/${NC} ← Reviewer & investigator subagents"
|
|
537
|
-
echo -e " ${GREEN}.claude/skills
|
|
538
|
-
echo -e " ${GREEN}.claude/skills/self-check/${NC} ← /self-check periodic discipline check"
|
|
539
|
-
echo -e " ${GREEN}.claude/skills/evaluate/${NC} ← /evaluate assess external review advice"
|
|
540
|
-
echo -e " ${GREEN}.claude/skills/think/${NC} ← /think stop and think before coding"
|
|
541
|
-
echo -e " ${GREEN}.claude/skills/retro/${NC} ← /retro post-task retrospective"
|
|
542
|
-
echo -e " ${GREEN}.claude/skills/summary/${NC} ← /summary before compacting"
|
|
543
|
-
echo -e " ${GREEN}.claude/skills/investigate/${NC} ← /investigate multi-agent cross-investigation"
|
|
530
|
+
echo -e " ${GREEN}.claude/skills/${NC} ← Skills (run 'npx cc-discipline status' to list)"
|
|
544
531
|
echo -e " ${GREEN}.claude/settings.json${NC} ← Hooks configuration"
|
|
545
532
|
echo -e " ${GREEN}docs/progress.md${NC} ← Progress log (maintained by Claude)"
|
|
546
533
|
echo -e " ${GREEN}docs/debug-log.md${NC} ← Debug log (maintained by Claude)"
|
|
@@ -556,13 +543,7 @@ else
|
|
|
556
543
|
echo -e " ${GREEN}.claude/rules/${NC} ← Discipline rules installed/updated"
|
|
557
544
|
echo -e " ${GREEN}.claude/hooks/${NC} ← Hook scripts installed/updated"
|
|
558
545
|
echo -e " ${GREEN}.claude/agents/${NC} ← Subagents installed/updated"
|
|
559
|
-
echo -e " ${GREEN}.claude/skills
|
|
560
|
-
echo -e " ${GREEN}.claude/skills/self-check/${NC} ← /self-check discipline check installed"
|
|
561
|
-
echo -e " ${GREEN}.claude/skills/evaluate/${NC} ← /evaluate external review assessment"
|
|
562
|
-
echo -e " ${GREEN}.claude/skills/think/${NC} ← /think stop and think before coding"
|
|
563
|
-
echo -e " ${GREEN}.claude/skills/retro/${NC} ← /retro post-task retrospective"
|
|
564
|
-
echo -e " ${GREEN}.claude/skills/summary/${NC} ← /summary before compacting"
|
|
565
|
-
echo -e " ${GREEN}.claude/skills/investigate/${NC} ← /investigate multi-agent cross-investigation"
|
|
546
|
+
echo -e " ${GREEN}.claude/skills/${NC} ← Skills installed/updated (run 'npx cc-discipline status' to list)"
|
|
566
547
|
if [ ! -f "$BACKUP_DIR/settings.json" ] || [ -f ".claude/.cc-discipline-settings-template.json" ]; then
|
|
567
548
|
echo -e " ${YELLOW}.claude/settings.json${NC} ← See notes above"
|
|
568
549
|
else
|
package/lib/doctor.sh
CHANGED
|
@@ -95,13 +95,13 @@ done
|
|
|
95
95
|
# 6. Skills
|
|
96
96
|
echo ""
|
|
97
97
|
echo "Skills:"
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
fi
|
|
98
|
+
SKILL_FOUND=0
|
|
99
|
+
for skill_dir in .claude/skills/*/; do
|
|
100
|
+
[ -d "$skill_dir" ] || continue
|
|
101
|
+
ok "/$(basename "$skill_dir")"
|
|
102
|
+
SKILL_FOUND=$((SKILL_FOUND + 1))
|
|
104
103
|
done
|
|
104
|
+
[ "$SKILL_FOUND" -eq 0 ] && warn "No skills installed (optional)"
|
|
105
105
|
|
|
106
106
|
# 7. jq
|
|
107
107
|
echo ""
|
package/lib/status.sh
CHANGED
|
@@ -66,15 +66,12 @@ echo -e "${GREEN}${AGENT_COUNT}/2${NC} (${AGENTS% })"
|
|
|
66
66
|
# Skills
|
|
67
67
|
echo -n "Skills: "
|
|
68
68
|
SKILLS=""
|
|
69
|
-
|
|
70
|
-
[ -d "
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
[ -d ".claude/skills/retro" ] && SKILLS="${SKILLS}/retro "
|
|
74
|
-
[ -d ".claude/skills/summary" ] && SKILLS="${SKILLS}/summary "
|
|
75
|
-
[ -d ".claude/skills/investigate" ] && SKILLS="${SKILLS}/investigate "
|
|
69
|
+
for skill_dir in .claude/skills/*/; do
|
|
70
|
+
[ -d "$skill_dir" ] || continue
|
|
71
|
+
SKILLS="${SKILLS}/$(basename "$skill_dir") "
|
|
72
|
+
done
|
|
76
73
|
SKILL_COUNT=$(echo "$SKILLS" | wc -w | tr -d ' ')
|
|
77
|
-
echo -e "${GREEN}${SKILL_COUNT}
|
|
74
|
+
echo -e "${GREEN}${SKILL_COUNT}${NC} (${SKILLS% })"
|
|
78
75
|
|
|
79
76
|
# Settings
|
|
80
77
|
echo -n "Settings: "
|
package/package.json
CHANGED
|
@@ -3,13 +3,18 @@
|
|
|
3
3
|
# Counts action-type tool calls per session, injects self-check every N actions.
|
|
4
4
|
# PreToolUse on Edit|Write|MultiEdit|Bash|Agent — additionalContext injection.
|
|
5
5
|
|
|
6
|
-
THRESHOLD=25
|
|
7
|
-
|
|
8
6
|
INPUT=$(cat)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
# Extract session_id with a grep fallback for when jq is unavailable (e.g.
|
|
8
|
+
# Windows Git Bash). Without this fallback, every session collapsed to the
|
|
9
|
+
# literal "unknown" and shared ONE never-resetting global counter — which
|
|
10
|
+
# permanently disabled the early-action phase check (count never restarted
|
|
11
|
+
# at 1) and made the periodic reflection fire off a global tally. (fixed 2026-06-05)
|
|
12
|
+
if command -v jq &>/dev/null; then
|
|
13
|
+
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // empty' 2>/dev/null)
|
|
14
|
+
else
|
|
15
|
+
SESSION_ID=$(echo "$INPUT" | grep -o '"session_id":\s*"[^"]*"' | head -1 | sed 's/"session_id":\s*"//;s/"//')
|
|
12
16
|
fi
|
|
17
|
+
SESSION_ID="${SESSION_ID:-unknown}"
|
|
13
18
|
|
|
14
19
|
COUNT_DIR="/tmp/cc-discipline-${SESSION_ID}"
|
|
15
20
|
COUNT_FILE="${COUNT_DIR}/action-count"
|
|
@@ -29,14 +34,29 @@ fi
|
|
|
29
34
|
|
|
30
35
|
# Progress.md staleness check: every 50 actions, check if progress.md was updated recently
|
|
31
36
|
if [ $((COUNT % 50)) -eq 0 ]; then
|
|
32
|
-
|
|
37
|
+
if command -v jq &>/dev/null; then
|
|
38
|
+
CWD=$(echo "$INPUT" | jq -r '.cwd // ""' 2>/dev/null)
|
|
39
|
+
else
|
|
40
|
+
CWD=$(echo "$INPUT" | sed -n -E 's/.*"cwd"[[:space:]]*:[[:space:]]*"([^"]*)".*/\1/p' | head -1 | sed 's/[\][\]/\//g')
|
|
41
|
+
fi
|
|
33
42
|
PROGRESS_FILE=""
|
|
34
43
|
[ -f "$CWD/docs/progress.md" ] && PROGRESS_FILE="$CWD/docs/progress.md"
|
|
35
44
|
[ -z "$PROGRESS_FILE" ] && [ -f "docs/progress.md" ] && PROGRESS_FILE="docs/progress.md"
|
|
36
45
|
if [ -n "$PROGRESS_FILE" ]; then
|
|
37
|
-
# Check if file was modified in the last 30 minutes
|
|
46
|
+
# Check if file was modified in the last 30 minutes.
|
|
47
|
+
# GNU stat (Linux, Windows Git Bash) FIRST, BSD stat (macOS) second —
|
|
48
|
+
# this order matters and the reverse is broken: in GNU stat, `-f` is not
|
|
49
|
+
# BSD's "format" flag, it means "show filesystem status". It therefore
|
|
50
|
+
# SUCCEEDS on Git Bash and prints a multi-line filesystem dump, so the
|
|
51
|
+
# `||` fallback never ran and $((NOW - FILE_MOD)) died with "syntax error
|
|
52
|
+
# in expression". `stat -c` is simply an invalid option on macOS, so it
|
|
53
|
+
# fails cleanly and falls through. The numeric guard below makes the
|
|
54
|
+
# failure mode silent either way. (fixed 2026-07-30)
|
|
38
55
|
if command -v stat &>/dev/null; then
|
|
39
|
-
FILE_MOD=$(stat -
|
|
56
|
+
FILE_MOD=$(stat -c %Y "$PROGRESS_FILE" 2>/dev/null || stat -f %m "$PROGRESS_FILE" 2>/dev/null)
|
|
57
|
+
case "$FILE_MOD" in
|
|
58
|
+
''|*[!0-9]*) FILE_MOD="" ;;
|
|
59
|
+
esac
|
|
40
60
|
NOW=$(date +%s)
|
|
41
61
|
if [ -n "$FILE_MOD" ] && [ $((NOW - FILE_MOD)) -gt 1800 ]; then
|
|
42
62
|
STALE_MIN=$(( (NOW - FILE_MOD) / 60 ))
|
|
@@ -49,10 +69,14 @@ JSONEOF
|
|
|
49
69
|
fi
|
|
50
70
|
fi
|
|
51
71
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
72
|
+
# The 25-action, 10-question "Periodic reflection" block was removed 2026-07-30.
|
|
73
|
+
# Anthropic's Opus 5 guidance: the model verifies its own work without being told
|
|
74
|
+
# to, and "legacy harness scaffolding that adds separate verification steps"
|
|
75
|
+
# causes over-verification — it compounds with the model's own behavior and adds
|
|
76
|
+
# cost with no quality gain. The block also duplicated rules already injected
|
|
77
|
+
# every session (00-core, 03, 06, 07), at ~299 tokens per firing. The remaining
|
|
78
|
+
# checks above (early-action phase check, progress.md staleness) are kept: both
|
|
79
|
+
# came out of the 112-session insights analysis in v2.4.0 and target failure
|
|
80
|
+
# modes we actually measured, not generic self-review.
|
|
57
81
|
|
|
58
82
|
exit 0
|
|
@@ -3,17 +3,46 @@
|
|
|
3
3
|
# PreToolUse on Bash — blocks git checkout/restore/reset --hard/clean -f without confirmation.
|
|
4
4
|
|
|
5
5
|
INPUT=$(cat)
|
|
6
|
-
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // ""' 2>/dev/null)
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
# Extract tool_name and command. MUST have a jq-or-grep fallback: jq is absent
|
|
8
|
+
# on Windows Git Bash, and the previous jq-only version left TOOL_NAME empty
|
|
9
|
+
# there, so the `!= "Bash"` check below exited 0 immediately and EVERY guard in
|
|
10
|
+
# this file was dead code. Destructive-git protection never ran on Windows.
|
|
11
|
+
# (fixed 2026-07-30 — verified with jq absent, see docs/progress.md)
|
|
12
|
+
if command -v jq &>/dev/null; then
|
|
13
|
+
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // ""' 2>/dev/null)
|
|
14
|
+
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // ""' 2>/dev/null)
|
|
15
|
+
else
|
|
16
|
+
TOOL_NAME=$(echo "$INPUT" | sed -n -E 's/.*"tool_name"[[:space:]]*:[[:space:]]*"([^"]*)".*/\1/p' | head -1)
|
|
17
|
+
# The [{,] anchor makes this pick the real "command" field rather than an
|
|
18
|
+
# escaped \"command\" nested inside it (happens when piping JSON to a hook).
|
|
19
|
+
# Unescape \n and \" so line-spanning commands still match the patterns below.
|
|
20
|
+
CMD=$(echo "$INPUT" | sed -n -E 's/.*[{,][[:space:]]*"command"[[:space:]]*:[[:space:]]*"(.*)".*/\1/p' \
|
|
21
|
+
| sed 's/[\]n/ /g; s/[\]"/"/g')
|
|
22
|
+
# If the command could not be isolated, scan the whole payload instead of
|
|
23
|
+
# giving up. For a destructive-git guard the failure directions are not
|
|
24
|
+
# symmetric: a spurious confirmation prompt costs one turn, a miss costs the
|
|
25
|
+
# user's uncommitted work. Fail loud.
|
|
26
|
+
[ -z "$CMD" ] && CMD="$INPUT"
|
|
10
27
|
fi
|
|
11
28
|
|
|
12
|
-
|
|
29
|
+
# Only gate on tool_name when it actually resolved — an unresolvable tool_name
|
|
30
|
+
# must not silently disable the guard (that was the original bug).
|
|
31
|
+
if [ -n "$TOOL_NAME" ] && [ "$TOOL_NAME" != "Bash" ]; then
|
|
32
|
+
exit 0
|
|
33
|
+
fi
|
|
13
34
|
|
|
14
35
|
# Normalize: collapse whitespace, trim
|
|
15
36
|
CMD_NORM=$(echo "$CMD" | tr '\n' ' ' | sed 's/ */ /g')
|
|
16
37
|
|
|
38
|
+
# This guard matches command TEXT, so a command that merely quotes a destructive
|
|
39
|
+
# command trips it. The one recurring legitimate case is feeding JSON into one of
|
|
40
|
+
# these hooks to test them (the workflow documented in CLAUDE.md). Exempt it —
|
|
41
|
+
# piping a payload to a hook script never touches the working tree.
|
|
42
|
+
if echo "$CMD_NORM" | grep -qE 'hooks[/\\][a-z-]+\.sh'; then
|
|
43
|
+
exit 0
|
|
44
|
+
fi
|
|
45
|
+
|
|
17
46
|
BLOCKED=""
|
|
18
47
|
SUGGESTION=""
|
|
19
48
|
|
|
@@ -29,11 +29,25 @@ if command -v jq &>/dev/null; then
|
|
|
29
29
|
if [ -z "$OUTPUT" ]; then
|
|
30
30
|
OUTPUT=$(echo "$RAW_INPUT" | jq -r '.tool_response.output // empty' 2>/dev/null)
|
|
31
31
|
fi
|
|
32
|
+
else
|
|
33
|
+
# jq is absent on Windows Git Bash. Extract the same two fields with sed.
|
|
34
|
+
# Unescape \n so the line-anchored patterns below (^ERROR, ^Traceback, ...)
|
|
35
|
+
# still work.
|
|
36
|
+
TOOL_NAME=$(echo "$RAW_INPUT" | sed -n -E 's/.*"tool_name"[[:space:]]*:[[:space:]]*"([^"]*)".*/\1/p' | head -1)
|
|
37
|
+
OUTPUT=$(echo "$RAW_INPUT" | sed -n -E 's/.*[{,][[:space:]]*"(error|output)"[[:space:]]*:[[:space:]]*"(.*)".*/\2/p' | head -1 \
|
|
38
|
+
| sed 's/[\]n/\
|
|
39
|
+
/g; s/[\]"/"/g')
|
|
32
40
|
fi
|
|
33
41
|
|
|
34
|
-
#
|
|
42
|
+
# NEVER match against the raw JSON envelope. The command text lives in there
|
|
43
|
+
# too, so `grep -rn "permission denied" logs/` used to flag itself — and with
|
|
44
|
+
# tool_name unresolved the non-Bash early-exit below never fired either, so this
|
|
45
|
+
# hook lectured on clean Read calls. Both were the old `OUTPUT="$RAW_INPUT"`
|
|
46
|
+
# fallback. If the tool's own output can't be isolated, stay silent: a false
|
|
47
|
+
# positive here costs a turn and misleads, so silence is the safe direction.
|
|
48
|
+
# (fixed 2026-07-30 — verified with jq absent, see docs/progress.md)
|
|
35
49
|
if [ -z "$OUTPUT" ]; then
|
|
36
|
-
|
|
50
|
+
exit 0
|
|
37
51
|
fi
|
|
38
52
|
|
|
39
53
|
# --- Early exits for known non-error situations ---
|
|
@@ -97,14 +111,14 @@ fi
|
|
|
97
111
|
# --- Emit reminder if error detected ---
|
|
98
112
|
|
|
99
113
|
if [ "$HAS_ERROR" = true ]; then
|
|
100
|
-
|
|
114
|
+
# Keep this to ONE line. The hypothesis discipline itself lives in the
|
|
115
|
+
# always-injected rules (00-core §6, 01-debugging) — re-injecting the full
|
|
116
|
+
# ">=3 causes / record in debug-log / eliminate >=2" ritual on every error
|
|
117
|
+
# duplicated them and pushed toward over-verification. Trimmed 2026-07-30.
|
|
118
|
+
REMINDER="Error detected: the first explanation that comes to mind is a hypothesis, not the root cause. Read the actual error before changing code."
|
|
101
119
|
|
|
102
120
|
if [ "$ERROR_TYPE" = "test" ]; then
|
|
103
|
-
REMINDER="$REMINDER
|
|
104
|
-
fi
|
|
105
|
-
|
|
106
|
-
if [ "$ERROR_TYPE" = "crash" ]; then
|
|
107
|
-
REMINDER="$REMINDER Note: Crash/segfault — may involve memory issues."
|
|
121
|
+
REMINDER="$REMINDER Test failure — decide whether the code is wrong or the test is outdated before touching either."
|
|
108
122
|
fi
|
|
109
123
|
|
|
110
124
|
echo "$REMINDER" >&2
|
|
@@ -51,34 +51,54 @@ if [ -n "$DEBUG_LOG" ]; then
|
|
|
51
51
|
CONFIRMED=$(echo "$CLEAN" | grep -c '| confirmed |' 2>/dev/null) || CONFIRMED=0
|
|
52
52
|
|
|
53
53
|
if [ "$PENDING" -gt "$CONFIRMED" ] 2>/dev/null; then
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
# Downgraded from a hard block (exit 2) to a note, 2026-07-30.
|
|
55
|
+
# As a hard block this combined with 01-debugging Phase 2 to form a trap:
|
|
56
|
+
# follow the rule, write 3 hypotheses into debug-log.md, and you were then
|
|
57
|
+
# forbidden from editing source until 3 were marked confirmed — including
|
|
58
|
+
# for unrelated planned work. It is the "legacy harness scaffolding that
|
|
59
|
+
# adds separate verification steps" Anthropic's Opus 5 guidance calls out.
|
|
60
|
+
# The hypothesis discipline itself stays in rules 00-core §6 / 01-debugging
|
|
61
|
+
# (56 measured wrong-approach incidents); only the enforcement is relaxed.
|
|
62
|
+
cat <<JSONEOF
|
|
63
|
+
{"hookSpecificOutput":{"hookEventName":"PreToolUse","additionalContext":"DEBUG-LOG NOTE: docs/debug-log.md has $((PENDING - CONFIRMED)) hypotheses still marked pending. If this edit is the fix for one of them, update its status first so the log stays truthful. If this edit is unrelated work, carry on."}}
|
|
64
|
+
JSONEOF
|
|
65
|
+
exit 0
|
|
60
66
|
fi
|
|
61
67
|
fi
|
|
62
68
|
|
|
63
69
|
# ─── Large diff warning ───
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
70
|
+
# Counts `content` too, not just new_string/old_string: Write sends `content`, so
|
|
71
|
+
# the previous version silently never fired on a large Write. Has a no-jq path so
|
|
72
|
+
# the "every jq read has an else" invariant holds repo-wide (see CLAUDE.md).
|
|
73
|
+
if command -v jq &>/dev/null; then
|
|
74
|
+
NEW_LINES=$(echo "$INPUT" | jq -r '.tool_input.new_string // .tool_input.content // ""' | wc -l | tr -d ' ')
|
|
75
|
+
OLD_LINES=$(echo "$INPUT" | jq -r '.tool_input.old_string // ""' | wc -l | tr -d ' ')
|
|
76
|
+
else
|
|
77
|
+
# Newlines arrive as the two-character sequence \n inside the JSON string.
|
|
78
|
+
count_lines() {
|
|
79
|
+
c=$(echo "$INPUT" | sed -n -E "s/.*[{,][[:space:]]*\"$1\"[[:space:]]*:[[:space:]]*\"(.*)\".*/\1/p" \
|
|
80
|
+
| grep -o '[\]n' | wc -l | tr -d ' ')
|
|
81
|
+
echo $((c + 1))
|
|
82
|
+
}
|
|
83
|
+
NEW_LINES=$(count_lines new_string)
|
|
84
|
+
[ "$NEW_LINES" -le 1 ] && NEW_LINES=$(count_lines content)
|
|
85
|
+
OLD_LINES=$(count_lines old_string)
|
|
86
|
+
fi
|
|
87
|
+
DIFF_LINES=$((NEW_LINES > OLD_LINES ? NEW_LINES : OLD_LINES))
|
|
88
|
+
if [ "$DIFF_LINES" -gt 200 ]; then
|
|
89
|
+
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?\"}}"
|
|
90
|
+
exit 0
|
|
77
91
|
fi
|
|
78
92
|
|
|
79
93
|
# ─── New tool/script detection ───
|
|
80
94
|
# When creating a script file via Write, remind to register in CLAUDE.md
|
|
81
|
-
|
|
95
|
+
# jq-or-sed: the previous jq-only line left TOOL_NAME empty on Windows Git Bash,
|
|
96
|
+
# so this detection never fired there. (fixed 2026-07-30)
|
|
97
|
+
if command -v jq &>/dev/null; then
|
|
98
|
+
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
|
|
99
|
+
else
|
|
100
|
+
TOOL_NAME=$(echo "$INPUT" | sed -n -E 's/.*"tool_name"[[:space:]]*:[[:space:]]*"([^"]*)".*/\1/p' | head -1)
|
|
101
|
+
fi
|
|
82
102
|
if [ "$TOOL_NAME" = "Write" ] && echo "$BASENAME" | grep -qiE "\.(sh|py|js|ts|rb|pl)$"; then
|
|
83
103
|
# Check if file already exists (new file = tool creation)
|
|
84
104
|
FULL_PATH="$FILE_PATH"
|
|
@@ -90,11 +110,9 @@ JSONEOF
|
|
|
90
110
|
fi
|
|
91
111
|
fi
|
|
92
112
|
|
|
93
|
-
#
|
|
94
|
-
#
|
|
95
|
-
#
|
|
96
|
-
#
|
|
97
|
-
|
|
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
|
|
113
|
+
# Normal source edit: stay silent (exit 0, no output).
|
|
114
|
+
# The "list >=3 causes before a bug fix" guidance already lives in the
|
|
115
|
+
# always-injected rules (00-core §6, 01-debugging), the hard debug-log block
|
|
116
|
+
# above, and post-error-remind. Re-injecting it on EVERY edit fired even on
|
|
117
|
+
# planned feature/registration work — redundant noise, removed 2026-06-05.
|
|
100
118
|
exit 0
|
|
@@ -4,9 +4,15 @@
|
|
|
4
4
|
# stdout → context (Claude can see and act on it)
|
|
5
5
|
# Fires on: startup, resume, clear, compact
|
|
6
6
|
|
|
7
|
-
# Reset action counter for this session
|
|
7
|
+
# Reset action counter for this session.
|
|
8
|
+
# jq-or-sed: jq is absent on Windows Git Bash, and the previous jq-only version
|
|
9
|
+
# left SESSION_ID empty there, so the reset below never ran. (fixed 2026-07-30)
|
|
8
10
|
INPUT=$(cat)
|
|
9
|
-
|
|
11
|
+
if command -v jq &>/dev/null; then
|
|
12
|
+
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"' 2>/dev/null)
|
|
13
|
+
else
|
|
14
|
+
SESSION_ID=$(echo "$INPUT" | sed -n -E 's/.*"session_id"[[:space:]]*:[[:space:]]*"([^"]*)".*/\1/p' | head -1)
|
|
15
|
+
fi
|
|
10
16
|
if [ -n "$SESSION_ID" ] && [ "$SESSION_ID" != "unknown" ]; then
|
|
11
17
|
rm -f "/tmp/cc-discipline-${SESSION_ID}/action-count"
|
|
12
18
|
fi
|
|
@@ -31,14 +37,14 @@ Verify project status by reading files or asking — don't assume beyond what is
|
|
|
31
37
|
EOF
|
|
32
38
|
fi
|
|
33
39
|
|
|
40
|
+
# Only the skill pointer is injected here. The four rule restatements that used
|
|
41
|
+
# to follow it (pre-edit checks, 3-failure rule, confirm-before-implementing,
|
|
42
|
+
# verify project state) were removed 2026-07-30: all four are already in the
|
|
43
|
+
# rules injected every session (02, 00-core §4, 05, 07 §4a), so repeating them
|
|
44
|
+
# here bought nothing. Skills are the one thing rules don't announce.
|
|
34
45
|
cat <<'EOF'
|
|
35
46
|
|
|
36
|
-
|
|
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
|
|
47
|
+
/self-check is available for periodic monitoring — for long tasks: /loop 10m /self-check
|
|
42
48
|
EOF
|
|
43
49
|
|
|
44
50
|
exit 0
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
# Pauses for reflection when the pattern suggests circling
|
|
5
5
|
#
|
|
6
6
|
# Design:
|
|
7
|
-
# - Source code files (.java/.ts/.py/.go etc): warn at
|
|
8
|
-
# - Config/doc files (.md/.json/.yaml/.xml etc): warn at
|
|
7
|
+
# - Source code files (.java/.ts/.py/.go etc): warn at 6, stop at 10
|
|
8
|
+
# - Config/doc files (.md/.json/.yaml/.xml etc): warn at 10, stop at 16
|
|
9
9
|
# - docs/ directory: exempt (always allow)
|
|
10
10
|
#
|
|
11
11
|
# Exit 0 + no output = silent allow
|
|
@@ -41,13 +41,20 @@ fi
|
|
|
41
41
|
BASENAME=$(basename "$FILE_PATH")
|
|
42
42
|
|
|
43
43
|
if echo "$BASENAME" | grep -qiE "\.(md|json|yaml|yml|toml|xml|cfg|ini|properties|gitignore)$"; then
|
|
44
|
-
# Config/doc files: higher thresholds (many independent sections to fill)
|
|
44
|
+
# Config/doc files: higher thresholds (many independent sections to fill).
|
|
45
|
+
# Raised 6/10 -> 10/16 on 2026-07-30 to keep this tier above the source tier
|
|
46
|
+
# after source was raised to 6/10.
|
|
47
|
+
WARN_THRESHOLD=10
|
|
48
|
+
STOP_THRESHOLD=16
|
|
49
|
+
else
|
|
50
|
+
# Source code files: repeated edits may indicate circling.
|
|
51
|
+
# Raised from 3/5 to 6/10 on 2026-07-30. Opus 5 completes multi-file features
|
|
52
|
+
# and larger refactors end-to-end rather than in one pass per file, so 5 edits
|
|
53
|
+
# to one source file is now common in legitimate feature work — the old
|
|
54
|
+
# thresholds fired on progress, not on circling. Circling that is actually
|
|
55
|
+
# worth interrupting still shows up well before 10.
|
|
45
56
|
WARN_THRESHOLD=6
|
|
46
57
|
STOP_THRESHOLD=10
|
|
47
|
-
else
|
|
48
|
-
# Source code files: strict thresholds (repeated edits may indicate circling)
|
|
49
|
-
WARN_THRESHOLD=3
|
|
50
|
-
STOP_THRESHOLD=5
|
|
51
58
|
fi
|
|
52
59
|
|
|
53
60
|
# Counter logic
|
|
@@ -5,7 +5,7 @@ description: "Core working principles — auto-injected before all operations"
|
|
|
5
5
|
|
|
6
6
|
## Core Principles
|
|
7
7
|
|
|
8
|
-
1. **Understand before acting** —
|
|
8
|
+
1. **Understand before acting** — Know what you're changing, why, and what it affects before you edit. State the reasoning when it isn't evident from the change itself; don't narrate routine edits
|
|
9
9
|
2. **Don't lock onto the first explanation** — After finding a suspected cause, list >=2 alternative hypotheses before acting
|
|
10
10
|
3. **Minimal change, minimal complexity** — No large-scale refactors unless explicitly requested. When proposing solutions, prefer the simplest approach that meets requirements. If a lightweight solution exists, choose it over a heavyweight one unless the user asks for more.
|
|
11
11
|
4. **3 consecutive failures → pause and regroup** — Report current state, attempted solutions, and points of confusion. Fresh perspective from the user often unblocks what repetition cannot.
|
|
@@ -9,14 +9,3 @@ Before modifying this file, confirm each of the following:
|
|
|
9
9
|
- [ ] **I know how to verify after the change** — Per 07-integrity: run it, paste output, or mark unverified
|
|
10
10
|
|
|
11
11
|
If any item is uncertain, resolving it first will make the edit smoother and avoid rework.
|
|
12
|
-
|
|
13
|
-
## Post-Edit Checklist
|
|
14
|
-
|
|
15
|
-
After writing or modifying code, before running it:
|
|
16
|
-
|
|
17
|
-
- [ ] **Syntax check** — Does the code compile/parse without errors? (e.g., `python -m py_compile`, `tsc --noEmit`, `go vet`)
|
|
18
|
-
- [ ] **Obvious errors** — No undefined variables, no wrong function signatures, no missing imports?
|
|
19
|
-
- [ ] **API correctness** — Are function/method calls using the right arguments, types, and return values? If unsure, read the API docs or source first.
|
|
20
|
-
- [ ] **Edge cases in your changes** — Did you handle empty inputs, None/null, off-by-one, etc.?
|
|
21
|
-
|
|
22
|
-
A 10-second syntax check catches errors that would otherwise cost 10-minute debug cycles. Always worth it.
|
|
@@ -5,13 +5,12 @@
|
|
|
5
5
|
- During debugging → update `docs/debug-log.md` (hypotheses, evidence, elimination results)
|
|
6
6
|
- When making architectural decisions → record the decision and reasoning in progress.md
|
|
7
7
|
|
|
8
|
-
###
|
|
9
|
-
- **
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
- **Keep the main conversation for decisions
|
|
14
|
-
- **When to parallelize:** if two subtasks don't depend on each other's output, they should run concurrently, not sequentially.
|
|
8
|
+
### Delegation
|
|
9
|
+
- **Delegate for isolation and genuine parallelism — not by default.** A subagent earns its cost when the work is sizeable, genuinely independent, and would otherwise flood the main conversation: a wide multi-file investigation, one agent per area of a broad survey.
|
|
10
|
+
- **Work directly** on single-file edits, short sequences of tool calls, and anything where you need to carry context across steps. If you can finish it in a handful of tool calls, don't delegate it.
|
|
11
|
+
- **Never delegate verification.** Don't spawn agents to double-check or re-verify your own work.
|
|
12
|
+
- **Keep spawn counts low.** If one subagent can do the job, use one rather than several.
|
|
13
|
+
- **Keep the main conversation for decisions.** When you do delegate research, the subagent reads and reports; the main conversation synthesizes and decides.
|
|
15
14
|
|
|
16
15
|
### Compact Strategy
|
|
17
16
|
- Avoid proactively suggesting compacting or warning about "context running low." The system auto-compacts when context hits 0% — there is no advance warning, and you cannot see the percentage. With 200K-1M context, most sessions never hit the limit. The urge to say "this session is getting long" is understandable in a long session, but it's not based on information you have access to — the system will handle it. Focus on the work.
|
|
@@ -77,16 +77,3 @@ When you discover wrong information in memory, docs, or prior output:
|
|
|
77
77
|
1. Correct it now, not "next time"
|
|
78
78
|
2. Note the correction and why, to prevent recurrence
|
|
79
79
|
3. If wrong information was already sent externally, alert the user
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
## Pre-action Checklist
|
|
84
|
-
|
|
85
|
-
Before any significant action, verify:
|
|
86
|
-
|
|
87
|
-
- [ ] Are my assumptions verified, or inferred from names/context?
|
|
88
|
-
- [ ] Are my "verified" claims actually backed by execution output?
|
|
89
|
-
- [ ] Am I quoting tool output verbatim, or have I altered it?
|
|
90
|
-
- [ ] Is the external information I'm referencing current?
|
|
91
|
-
- [ ] Does this content go external? Has the user reviewed it?
|
|
92
|
-
- [ ] Is there anything I wrote confidently but am actually unsure about?
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: finish
|
|
3
|
+
description: Drive a task to completion with the quality bar — solid, comprehensive, fully tested; "not run" never counts as done. Use when you're ready to execute to the end (standalone, or as the handoff after /think approval).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You are in **finish mode**: the task is understood and approved — now drive it to completion without stopping early. This is the opposite stance from /think (which aligns and waits). Here you execute, persist, and hold a high quality bar.
|
|
7
|
+
|
|
8
|
+
## Step 1: Lock the completion conditions
|
|
9
|
+
|
|
10
|
+
State explicitly — in one short block — what "done" means for this task:
|
|
11
|
+
- The concrete deliverables (what must exist / work when finished)
|
|
12
|
+
- The quality bar below, applied to each
|
|
13
|
+
- Anything you'll treat as "blocked, must report" rather than silently skip
|
|
14
|
+
|
|
15
|
+
If invoked standalone (no prior /think) and the scope is genuinely unclear, ask ONE tight round of questions, then commit. Don't turn finish mode into a planning session — the point is to execute.
|
|
16
|
+
|
|
17
|
+
## Step 2: The quality bar (definition of done)
|
|
18
|
+
|
|
19
|
+
Hold all of these. They are the standard, not aspirations:
|
|
20
|
+
|
|
21
|
+
- **扎实 (solid)** — Fix the root cause, not symptoms. Handle edge cases (empty / null / error paths). No TODO, stub, or workaround left standing in as "the solution."
|
|
22
|
+
- **全面 (comprehensive)** — Cover the full scope, not just the happy path. Update related call sites, docs, and `docs/progress.md`. Don't leave half the task for "later."
|
|
23
|
+
- **完备测试 (fully tested)** — Write tests AND run them. Per 07-integrity §2, "verified" requires actual execution output — paste the command and result. Untested code is not done.
|
|
24
|
+
- **诚实 (honest)** — If something is blocked by an external resource, mark it "⚠️ code ready, verification pending: [reason]" — never ✅ it. Distinguish done from blocked.
|
|
25
|
+
|
|
26
|
+
## Step 3: Drive
|
|
27
|
+
|
|
28
|
+
Keep going until the completion conditions are met. While driving:
|
|
29
|
+
- Make reasonable decisions and keep moving — note them, don't stop to ask about trivia.
|
|
30
|
+
- The discipline rules still apply: 3 consecutive failures → pause and regroup; scope changes → re-align; anything irreversible or outward-facing → confirm first.
|
|
31
|
+
- Don't declare partial success to exit early. If you feel the urge to stop before the bar is met, that urge is the signal to push through or report the specific blocker — not to lower the bar.
|
|
32
|
+
|
|
33
|
+
## Step 4: Report on completion
|
|
34
|
+
|
|
35
|
+
When the completion conditions are met, give a short close-out:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
FINISH — [task]
|
|
39
|
+
Done: [each deliverable + how it was verified — paste key command output]
|
|
40
|
+
Quality bar: 扎实 [✓/note] · 全面 [✓/note] · 完备测试 [✓/note]
|
|
41
|
+
Blocked (if any): [item — why, what's needed]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
If any part is blocked rather than done, say so plainly. A truthful "90% done, X blocked on Y" beats a false ✅.
|
|
@@ -3,11 +3,11 @@ name: retro
|
|
|
3
3
|
description: Find friction, remove friction. Quick post-task review that makes this project's workflow smoother and feeds improvements back to cc-discipline.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Find friction. Remove friction.
|
|
6
|
+
Find friction. Remove friction. Record what the rules actually caught.
|
|
7
7
|
|
|
8
8
|
## What to do
|
|
9
9
|
|
|
10
|
-
Quickly scan what just happened — `git log --oneline -10` and any hook triggers you remember. Then output
|
|
10
|
+
Quickly scan what just happened — `git log --oneline -10` and any hook triggers you remember. Then output in this format:
|
|
11
11
|
|
|
12
12
|
```
|
|
13
13
|
RETRO — [date]
|
|
@@ -15,6 +15,9 @@ RETRO — [date]
|
|
|
15
15
|
Friction:
|
|
16
16
|
- [what got in the way] → fix: [specific actionable change]
|
|
17
17
|
|
|
18
|
+
Saves:
|
|
19
|
+
- [rule/hook] caught [the specific real problem] — without it: [what would have shipped]
|
|
20
|
+
|
|
18
21
|
Insights:
|
|
19
22
|
- [something learned that should survive this session]
|
|
20
23
|
|
|
@@ -23,18 +26,24 @@ Framework:
|
|
|
23
26
|
```
|
|
24
27
|
|
|
25
28
|
Rules:
|
|
26
|
-
- **Only friction** —
|
|
27
|
-
- **Only actionable** — Every friction item must have a "→ fix:" with a concrete change (adjust a threshold, add to CLAUDE.md, update memory, exempt a path).
|
|
29
|
+
- **Only actionable friction** — Every friction item must have a "→ fix:" with a concrete change (adjust a threshold, add to CLAUDE.md, update memory, exempt a path).
|
|
28
30
|
- **Only new** — Don't repeat friction that's already been addressed or recorded in memory.
|
|
29
31
|
- **Be specific** — "streak-breaker was annoying" is not useful. "streak-breaker triggered 3x on config.yaml during template fill → fix: add config.yaml to docs/ exempt path, or raise config threshold to 10" is useful.
|
|
30
32
|
- **Framework items are rare** — Most friction is project-specific. Only flag framework issues if the same problem would hit other projects too.
|
|
31
|
-
- **Keep it short** — 3-5 items max. If you can't find friction, say "no friction found" and move on. An empty
|
|
33
|
+
- **Keep it short** — 3-5 items per section max. If you can't find friction, say "no friction found" and move on. An empty friction list is a good sign.
|
|
34
|
+
|
|
35
|
+
Saves — read this before filling that section in:
|
|
36
|
+
- **A save is not "what went well."** Log a save only when a rule or hook *changed the outcome*: it caught a real mistake, blocked a real loss, or stopped a wrong turn that was already in motion. "The rules kept me disciplined" is not a save. "git-guard blocked `git reset --hard` while 40 min of uncommitted work was in the tree" is.
|
|
37
|
+
- **"no saves" is a real answer, and it is data.** Write it plainly rather than manufacturing one.
|
|
38
|
+
- **Why this section exists:** friction is visible and saves are invisible — a rule that works silently suppresses the very failure it was written for, so the only naturally measurable signal is its cost. With cost-only data every rule eventually looks like pure overhead and gets cut, including the ones that are still load-bearing. The save log is what makes it possible to judge, later and with evidence, whether a given rule still earns its place.
|
|
32
39
|
|
|
33
40
|
## After output
|
|
34
41
|
|
|
35
|
-
|
|
42
|
+
Append both Friction and Saves to a `## Rule Ledger` section in `docs/progress.md` (create the section at the end of the file if it isn't there yet), one dated line each. This accumulates the record across sessions — a single retro proves nothing, twenty of them decide which rules stay.
|
|
43
|
+
|
|
44
|
+
Then present the items. User decides:
|
|
36
45
|
- "fix it" → apply the changes
|
|
37
46
|
- "remember it" → write to memory via /commit
|
|
38
47
|
- "skip" → move on
|
|
39
48
|
|
|
40
|
-
Do not auto-apply. Do not pad. Do not turn this into a report.
|
|
49
|
+
Do not auto-apply fixes. Do not pad. Do not turn this into a report. (Appending to the ledger is not a fix — do that without asking.)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
name: self-check
|
|
3
3
|
description: Periodic self-check — reflect on alignment, progress, and quality. Use with /loop for continuous monitoring.
|
|
4
4
|
disable-model-invocation: true
|
|
5
|
+
disallowed-tools: AskUserQuestion
|
|
5
6
|
---
|
|
6
7
|
|
|
7
8
|
Pause and honestly answer every question below.
|
|
@@ -59,7 +60,7 @@ Pause and honestly answer every question below.
|
|
|
59
60
|
- **Gotchas** — what went wrong or was surprising
|
|
60
61
|
- **Verification** — how it was confirmed working (test output, manual check)
|
|
61
62
|
|
|
62
|
-
If any of the above are stale or incomplete: **update docs/progress.md now
|
|
63
|
+
If any of the above are stale or incomplete: **update docs/progress.md now, automatically — don't ask for permission.** Keeping progress.md current is always-correct maintenance, not a decision that needs sign-off. Just do it, then note "updated now" in the status line. This takes 2 minutes and saves hours of re-discovery after compact.
|
|
63
64
|
|
|
64
65
|
## 6. Am I using the project's scaffolding?
|
|
65
66
|
|
|
@@ -105,7 +106,7 @@ Going well: [one thing]
|
|
|
105
106
|
Issues found: [list, or "none"]
|
|
106
107
|
```
|
|
107
108
|
|
|
108
|
-
If any issues were found, pause and report to the user before continuing.
|
|
109
|
+
If any issues were found, pause and report to the user before continuing. (Routine progress.md updates from §5 don't count as "issues" — you already made them silently; just report "updated now". Reserve the pause for alignment, rigor, or scope problems that genuinely need the user.)
|
|
109
110
|
|
|
110
111
|
## Reminder
|
|
111
112
|
|
|
@@ -73,7 +73,7 @@ Rules:
|
|
|
73
73
|
- Flag risks or unknowns you've spotted
|
|
74
74
|
- **Every step must have acceptance criteria** — "done when" must be observable and verifiable, not vague. Bad: "done when refactored". Good: "done when 3 methods extracted, each ≤20 lines, all tests pass"
|
|
75
75
|
- **Simplicity bias** — If a simple approach meets all requirements, list it first and recommend it. Do NOT lead with complex/elegant solutions unless the user signals they want that. "Simple but sufficient" beats "powerful but overkill".
|
|
76
|
-
- **
|
|
76
|
+
- **Note real dependencies** — Mark which steps depend on which. Don't annotate steps for parallel delegation by default; see 03-context-mgmt "Delegation" for when a subagent is actually warranted.
|
|
77
77
|
|
|
78
78
|
## Step 4: Self-review
|
|
79
79
|
|
|
@@ -106,3 +106,12 @@ When the user confirms an approach, transition to implementation. You now have:
|
|
|
106
106
|
- Known risks flagged upfront
|
|
107
107
|
|
|
108
108
|
Carry these forward. If scope changes during implementation, pause and re-align rather than silently expanding.
|
|
109
|
+
|
|
110
|
+
## Downstream: what the user appended
|
|
111
|
+
|
|
112
|
+
The user may steer what happens after alignment by appending a directive to the invocation:
|
|
113
|
+
|
|
114
|
+
- **`/think and plan`** — after alignment, produce the plan (in plan mode, present it for approval via ExitPlanMode).
|
|
115
|
+
- **`/think and finish`** (or `and goal`) — after the user approves the approach, transition into **/finish**: drive to completion with its quality bar (solid, comprehensive, fully tested). Do NOT start before approval — 05-phase-discipline still applies; "and finish" declares the post-approval execution stance, it does not bypass the gate.
|
|
116
|
+
|
|
117
|
+
If no directive was appended, stop and wait as usual (Step 5).
|
|
@@ -70,3 +70,25 @@
|
|
|
70
70
|
| # | Decision | Reason | Impact Scope | Date |
|
|
71
71
|
|---|----------|--------|-------------|------|
|
|
72
72
|
| | | | | |
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Rule Ledger
|
|
77
|
+
|
|
78
|
+
<!--
|
|
79
|
+
Appended by /retro. Two columns of evidence about the discipline rules themselves:
|
|
80
|
+
|
|
81
|
+
- SAVE — a rule or hook changed the outcome: caught a real mistake, blocked a
|
|
82
|
+
real loss, stopped a wrong turn already in motion.
|
|
83
|
+
- FRICTION — a rule or hook got in the way and cost time for no benefit.
|
|
84
|
+
|
|
85
|
+
Why keep this: friction is visible, saves are invisible. A rule that works
|
|
86
|
+
silently suppresses the very failure it was written for, so cost is the only
|
|
87
|
+
signal that shows up on its own. Judging rules on cost alone eventually cuts the
|
|
88
|
+
load-bearing ones. This ledger is the counterweight — with enough dated entries,
|
|
89
|
+
"should this rule stay?" becomes a lookup instead of a guess.
|
|
90
|
+
-->
|
|
91
|
+
|
|
92
|
+
| Date | Kind | Rule / Hook | What happened |
|
|
93
|
+
|------|------|-------------|---------------|
|
|
94
|
+
| | | | |
|