@hivehub/rulebook 5.2.1 → 5.3.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/.claude/commands/analysis.md +35 -0
- package/.claude/commands/rulebook-task-apply.md +7 -25
- package/.claude/commands/rulebook-task-archive.md +10 -19
- package/.claude/commands/rulebook-task-create.md +1 -1
- package/README.md +354 -965
- package/dist/cli/commands/analysis.d.ts +8 -0
- package/dist/cli/commands/analysis.d.ts.map +1 -0
- package/dist/cli/commands/analysis.js +78 -0
- package/dist/cli/commands/analysis.js.map +1 -0
- package/dist/cli/commands/context-intelligence.d.ts +33 -0
- package/dist/cli/commands/context-intelligence.d.ts.map +1 -0
- package/dist/cli/commands/context-intelligence.js +181 -0
- package/dist/cli/commands/context-intelligence.js.map +1 -0
- package/dist/cli/commands/index.d.ts +19 -0
- package/dist/cli/commands/index.d.ts.map +1 -0
- package/dist/cli/commands/index.js +19 -0
- package/dist/cli/commands/index.js.map +1 -0
- package/dist/cli/commands/init.d.ts +15 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +608 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/mcp.d.ts +10 -0
- package/dist/cli/commands/mcp.d.ts.map +1 -0
- package/dist/cli/commands/mcp.js +128 -0
- package/dist/cli/commands/mcp.js.map +1 -0
- package/dist/cli/commands/memory.d.ts +24 -0
- package/dist/cli/commands/memory.d.ts.map +1 -0
- package/dist/cli/commands/memory.js +265 -0
- package/dist/cli/commands/memory.js.map +1 -0
- package/dist/cli/commands/misc.d.ts +33 -0
- package/dist/cli/commands/misc.d.ts.map +1 -0
- package/dist/cli/commands/misc.js +576 -0
- package/dist/cli/commands/misc.js.map +1 -0
- package/dist/cli/commands/plans.d.ts +15 -0
- package/dist/cli/commands/plans.d.ts.map +1 -0
- package/dist/cli/commands/plans.js +266 -0
- package/dist/cli/commands/plans.js.map +1 -0
- package/dist/cli/commands/ralph.d.ts +45 -0
- package/dist/cli/commands/ralph.d.ts.map +1 -0
- package/dist/cli/commands/ralph.js +694 -0
- package/dist/cli/commands/ralph.js.map +1 -0
- package/dist/cli/commands/skills.d.ts +9 -0
- package/dist/cli/commands/skills.d.ts.map +1 -0
- package/dist/cli/commands/skills.js +249 -0
- package/dist/cli/commands/skills.js.map +1 -0
- package/dist/cli/commands/task.d.ts +16 -0
- package/dist/cli/commands/task.d.ts.map +1 -0
- package/dist/cli/commands/task.js +256 -0
- package/dist/cli/commands/task.js.map +1 -0
- package/dist/cli/commands/update.d.ts +14 -0
- package/dist/cli/commands/update.d.ts.map +1 -0
- package/dist/cli/commands/update.js +636 -0
- package/dist/cli/commands/update.js.map +1 -0
- package/dist/cli/commands/workspace.d.ts +6 -0
- package/dist/cli/commands/workspace.d.ts.map +1 -0
- package/dist/cli/commands/workspace.js +141 -0
- package/dist/cli/commands/workspace.js.map +1 -0
- package/dist/core/agent-template-engine.js +28 -28
- package/dist/core/analysis-manager.d.ts +56 -0
- package/dist/core/analysis-manager.d.ts.map +1 -0
- package/dist/core/analysis-manager.js +218 -0
- package/dist/core/analysis-manager.js.map +1 -0
- package/dist/core/claude-md-generator.d.ts +52 -0
- package/dist/core/claude-md-generator.d.ts.map +1 -0
- package/dist/core/claude-md-generator.js +104 -0
- package/dist/core/claude-md-generator.js.map +1 -0
- package/dist/core/claude-settings-manager.d.ts +37 -0
- package/dist/core/claude-settings-manager.d.ts.map +1 -0
- package/dist/core/claude-settings-manager.js +168 -0
- package/dist/core/claude-settings-manager.js.map +1 -0
- package/dist/core/compact-context-manager.d.ts +34 -0
- package/dist/core/compact-context-manager.d.ts.map +1 -0
- package/dist/core/compact-context-manager.js +60 -0
- package/dist/core/compact-context-manager.js.map +1 -0
- package/dist/core/doctor.d.ts +19 -0
- package/dist/core/doctor.d.ts.map +1 -0
- package/dist/core/doctor.js +163 -0
- package/dist/core/doctor.js.map +1 -0
- package/dist/core/generator.js +28 -28
- package/dist/core/mcp-reference-generator.d.ts +13 -0
- package/dist/core/mcp-reference-generator.d.ts.map +1 -0
- package/dist/core/mcp-reference-generator.js +66 -0
- package/dist/core/mcp-reference-generator.js.map +1 -0
- package/dist/core/merger.d.ts +35 -0
- package/dist/core/merger.d.ts.map +1 -1
- package/dist/core/merger.js +120 -0
- package/dist/core/merger.js.map +1 -1
- package/dist/core/prd-generator.d.ts.map +1 -1
- package/dist/core/prd-generator.js +7 -1
- package/dist/core/prd-generator.js.map +1 -1
- package/dist/core/ralph-manager.d.ts.map +1 -1
- package/dist/core/ralph-manager.js +17 -0
- package/dist/core/ralph-manager.js.map +1 -1
- package/dist/core/rules-generator.d.ts +73 -0
- package/dist/core/rules-generator.d.ts.map +1 -0
- package/dist/core/rules-generator.js +201 -0
- package/dist/core/rules-generator.js.map +1 -0
- package/dist/core/state-writer.d.ts +35 -0
- package/dist/core/state-writer.d.ts.map +1 -0
- package/dist/core/state-writer.js +81 -0
- package/dist/core/state-writer.js.map +1 -0
- package/dist/core/task-manager.d.ts +35 -0
- package/dist/core/task-manager.d.ts.map +1 -1
- package/dist/core/task-manager.js +135 -38
- package/dist/core/task-manager.js.map +1 -1
- package/dist/core/telemetry.d.ts +29 -0
- package/dist/core/telemetry.d.ts.map +1 -0
- package/dist/core/telemetry.js +57 -0
- package/dist/core/telemetry.js.map +1 -0
- package/dist/core/workflow-generator.d.ts.map +1 -1
- package/dist/core/workflow-generator.js +2 -177
- package/dist/core/workflow-generator.js.map +1 -1
- package/dist/index.js +28 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/rulebook-server.d.ts.map +1 -1
- package/dist/mcp/rulebook-server.js +190 -7
- package/dist/mcp/rulebook-server.js.map +1 -1
- package/dist/memory/memory-store.js +91 -91
- package/dist/types.d.ts +11 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/gitignore.d.ts +10 -0
- package/dist/utils/gitignore.d.ts.map +1 -0
- package/dist/utils/gitignore.js +38 -0
- package/dist/utils/gitignore.js.map +1 -0
- package/package.json +1 -1
- package/templates/compact-context/_default.md +23 -0
- package/templates/compact-context/cpp.md +26 -0
- package/templates/compact-context/go.md +26 -0
- package/templates/compact-context/python.md +26 -0
- package/templates/compact-context/rust.md +28 -0
- package/templates/compact-context/typescript.md +29 -0
- package/templates/core/CLAUDE_MD_v2.md +71 -0
- package/templates/hooks/check-context-and-handoff.ps1 +50 -0
- package/templates/hooks/check-context-and-handoff.sh +69 -0
- package/templates/hooks/enforce-mcp-for-tasks.sh +31 -0
- package/templates/hooks/enforce-no-deferred.sh +21 -0
- package/templates/hooks/enforce-no-shortcuts.sh +31 -0
- package/templates/hooks/enforce-team-for-background-agents.ps1 +63 -0
- package/templates/hooks/enforce-team-for-background-agents.sh +55 -0
- package/templates/hooks/on-compact-reinject.sh +34 -0
- package/templates/hooks/resume-from-handoff.ps1 +33 -0
- package/templates/hooks/resume-from-handoff.sh +55 -0
- package/templates/rules/consult-analysis-before-implementing.md +23 -0
- package/templates/rules/cpp.md +46 -0
- package/templates/rules/csharp.md +44 -0
- package/templates/rules/diagnostic-first.md +39 -0
- package/templates/rules/fail-twice-escalate.md +46 -0
- package/templates/rules/go.md +40 -0
- package/templates/rules/java.md +43 -0
- package/templates/rules/javascript.md +39 -0
- package/templates/rules/multi-agent-teams.md +75 -0
- package/templates/rules/python.md +43 -0
- package/templates/rules/respect-handoff-trigger.md +41 -0
- package/templates/rules/rust.md +40 -0
- package/templates/rules/typescript.md +40 -0
- package/templates/skills/dev/analysis/SKILL.md +19 -0
- package/templates/skills/dev/handoff/SKILL.md +27 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Claude Code Stop hook — context freshness monitor (PowerShell).
|
|
2
|
+
# See check-context-and-handoff.sh for the full design rationale.
|
|
3
|
+
|
|
4
|
+
$ErrorActionPreference = 'Stop'
|
|
5
|
+
|
|
6
|
+
$ProjectRoot = Get-Location
|
|
7
|
+
$ConfigFile = Join-Path $ProjectRoot '.rulebook/rulebook.json'
|
|
8
|
+
$HandoffDir = Join-Path $ProjectRoot '.rulebook/handoff'
|
|
9
|
+
|
|
10
|
+
$WarnPct = 75
|
|
11
|
+
$ForcePct = 90
|
|
12
|
+
$MaxContextChars = 800000
|
|
13
|
+
|
|
14
|
+
if (Test-Path $ConfigFile) {
|
|
15
|
+
try {
|
|
16
|
+
$cfg = Get-Content $ConfigFile -Raw | ConvertFrom-Json
|
|
17
|
+
if ($cfg.handoff.warnThresholdPct) { $WarnPct = $cfg.handoff.warnThresholdPct }
|
|
18
|
+
if ($cfg.handoff.forceThresholdPct) { $ForcePct = $cfg.handoff.forceThresholdPct }
|
|
19
|
+
} catch {}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
$TranscriptSize = 0
|
|
23
|
+
$ClaudeDir = Join-Path $env:USERPROFILE '.claude/projects'
|
|
24
|
+
if (Test-Path $ClaudeDir) {
|
|
25
|
+
$latest = Get-ChildItem $ClaudeDir -Recurse -Filter '*.jsonl' -File |
|
|
26
|
+
Sort-Object LastWriteTime -Descending | Select-Object -First 1
|
|
27
|
+
if ($latest) { $TranscriptSize = $latest.Length }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if ($TranscriptSize -eq 0) {
|
|
31
|
+
Write-Output '{}'
|
|
32
|
+
exit 0
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
$Pct = [math]::Floor($TranscriptSize * 100 / $MaxContextChars)
|
|
36
|
+
|
|
37
|
+
if ($Pct -ge $ForcePct) {
|
|
38
|
+
if (-not (Test-Path $HandoffDir)) { New-Item -ItemType Directory -Path $HandoffDir -Force | Out-Null }
|
|
39
|
+
New-Item -ItemType File -Path (Join-Path $HandoffDir '.urgent') -Force | Out-Null
|
|
40
|
+
$msg = "CONTEXT AT ${Pct}% (FORCE THRESHOLD). You MUST invoke /handoff NOW."
|
|
41
|
+
$out = @{ hookSpecificOutput = @{ hookEventName = 'Stop'; additionalContext = $msg } } | ConvertTo-Json -Compress -Depth 4
|
|
42
|
+
Write-Output $out
|
|
43
|
+
} elseif ($Pct -ge $WarnPct) {
|
|
44
|
+
$msg = "Context at ${Pct}%. Recommended: invoke /handoff to save session state."
|
|
45
|
+
$out = @{ hookSpecificOutput = @{ hookEventName = 'Stop'; additionalContext = $msg } } | ConvertTo-Json -Compress -Depth 4
|
|
46
|
+
Write-Output $out
|
|
47
|
+
} else {
|
|
48
|
+
Write-Output '{}'
|
|
49
|
+
}
|
|
50
|
+
exit 0
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Claude Code Stop hook — context freshness monitor.
|
|
3
|
+
#
|
|
4
|
+
# Runs after every model turn. Estimates the current context usage
|
|
5
|
+
# from the JSONL transcript and, when it exceeds the configured
|
|
6
|
+
# threshold, emits additionalContext instructing the model to invoke
|
|
7
|
+
# the /handoff skill and tell the user to type /clear.
|
|
8
|
+
#
|
|
9
|
+
# Thresholds are read from .rulebook/rulebook.json `handoff` section.
|
|
10
|
+
# Defaults: warn=75, force=90 (percentage of estimated max context).
|
|
11
|
+
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
PROJECT_ROOT="$(pwd)"
|
|
15
|
+
CONFIG_FILE="${PROJECT_ROOT}/.rulebook/rulebook.json"
|
|
16
|
+
HANDOFF_DIR="${PROJECT_ROOT}/.rulebook/handoff"
|
|
17
|
+
|
|
18
|
+
# Defaults
|
|
19
|
+
WARN_PCT=75
|
|
20
|
+
FORCE_PCT=90
|
|
21
|
+
MAX_CONTEXT_CHARS=800000 # ~200k tokens ≈ 800k chars (rough 1:4 ratio)
|
|
22
|
+
|
|
23
|
+
# Override from config if available
|
|
24
|
+
if [[ -f "$CONFIG_FILE" ]] && command -v jq &>/dev/null; then
|
|
25
|
+
WARN_PCT=$(jq -r '.handoff.warnThresholdPct // 75' "$CONFIG_FILE" 2>/dev/null || echo 75)
|
|
26
|
+
FORCE_PCT=$(jq -r '.handoff.forceThresholdPct // 90' "$CONFIG_FILE" 2>/dev/null || echo 90)
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
# Read the hook input from stdin (Claude Code passes it as JSON)
|
|
30
|
+
input="$(cat)"
|
|
31
|
+
|
|
32
|
+
# Try to find the transcript path from the session
|
|
33
|
+
# Claude Code stores transcripts as JSONL in ~/.claude/projects/<hash>/
|
|
34
|
+
# The hook input may or may not contain session info; we fall back to
|
|
35
|
+
# estimating from the input itself.
|
|
36
|
+
transcript_size=0
|
|
37
|
+
|
|
38
|
+
# Strategy 1: check the most recent JSONL in the project-specific Claude dir
|
|
39
|
+
CLAUDE_PROJECTS_DIR="${HOME}/.claude/projects"
|
|
40
|
+
if [[ -d "$CLAUDE_PROJECTS_DIR" ]]; then
|
|
41
|
+
latest_jsonl=$(find "$CLAUDE_PROJECTS_DIR" -name "*.jsonl" -type f -printf '%T@ %p\n' 2>/dev/null | sort -rn | head -1 | awk '{print $2}' || true)
|
|
42
|
+
if [[ -n "$latest_jsonl" && -f "$latest_jsonl" ]]; then
|
|
43
|
+
transcript_size=$(stat -c%s "$latest_jsonl" 2>/dev/null || stat -f%z "$latest_jsonl" 2>/dev/null || echo 0)
|
|
44
|
+
fi
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# If we couldn't get transcript size, emit nothing (no-op)
|
|
48
|
+
if [[ "$transcript_size" -eq 0 ]]; then
|
|
49
|
+
printf '%s' '{}'
|
|
50
|
+
exit 0
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# Estimate context percentage
|
|
54
|
+
pct=$(( transcript_size * 100 / MAX_CONTEXT_CHARS ))
|
|
55
|
+
|
|
56
|
+
if [[ "$pct" -ge "$FORCE_PCT" ]]; then
|
|
57
|
+
# Force mode: write urgent sentinel + emit strong instruction
|
|
58
|
+
mkdir -p "$HANDOFF_DIR"
|
|
59
|
+
touch "${HANDOFF_DIR}/.urgent"
|
|
60
|
+
msg="⚠️ CONTEXT AT ${pct}% (FORCE THRESHOLD). You MUST invoke /handoff NOW to save session state to .rulebook/handoff/_pending.md. After it succeeds, tell the user: '>>> TYPE /clear NOW — your context will be auto-restored in the next session <<<'. Do NOT continue working until the user has typed /clear."
|
|
61
|
+
jq -nc --arg msg "$msg" '{ hookSpecificOutput: { hookEventName: "Stop", additionalContext: $msg } }'
|
|
62
|
+
elif [[ "$pct" -ge "$WARN_PCT" ]]; then
|
|
63
|
+
msg="⚠️ Context at ${pct}%. Recommended: invoke /handoff to save session state. After it succeeds, tell the user to type /clear for a fresh session."
|
|
64
|
+
jq -nc --arg msg "$msg" '{ hookSpecificOutput: { hookEventName: "Stop", additionalContext: $msg } }'
|
|
65
|
+
else
|
|
66
|
+
# Below threshold — no-op
|
|
67
|
+
printf '%s' '{}'
|
|
68
|
+
fi
|
|
69
|
+
exit 0
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# PreToolUse hook: deny manual task file creation — must use MCP tools
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
input="$(cat)"
|
|
5
|
+
|
|
6
|
+
result="$(node -e "
|
|
7
|
+
const input = JSON.parse(process.argv[1]);
|
|
8
|
+
const tool = input.tool_name || '';
|
|
9
|
+
if (tool === 'Write' || tool === 'Edit') {
|
|
10
|
+
const file = input.tool_input?.file_path || input.tool_input?.filePath || '';
|
|
11
|
+
// Block creating new proposal.md or .metadata.json in tasks/
|
|
12
|
+
if (/\.rulebook\/tasks\/[^/]+\/(proposal\.md|\.metadata\.json)$/.test(file.replace(/\\\\/g,'/'))) {
|
|
13
|
+
// Allow if editing existing file
|
|
14
|
+
try { require('fs').accessSync(file); console.log('ALLOW'); } catch { console.log('DENY'); }
|
|
15
|
+
process.exit(0);
|
|
16
|
+
}
|
|
17
|
+
} else if (tool === 'Bash') {
|
|
18
|
+
const cmd = input.tool_input?.command || '';
|
|
19
|
+
if (/mkdir.*\.rulebook\/tasks\//.test(cmd) || /mkdir.*\.rulebook\\\\tasks\\\\/.test(cmd)) {
|
|
20
|
+
console.log('DENY');
|
|
21
|
+
process.exit(0);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
console.log('ALLOW');
|
|
25
|
+
" "$input" 2>/dev/null || echo "ALLOW")"
|
|
26
|
+
|
|
27
|
+
if [[ "$result" == "DENY" ]]; then
|
|
28
|
+
echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"DENIED: task files must be created via rulebook_task_create MCP tool, not manually. Use: rulebook_task_create({ taskId: phase1_your-task-name })"}}'
|
|
29
|
+
else
|
|
30
|
+
echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}'
|
|
31
|
+
fi
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# PreToolUse hook: deny deferred/TODO/skip items in tasks.md
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
input="$(cat)"
|
|
5
|
+
|
|
6
|
+
# Parse JSON with node (jq may not be available on Windows)
|
|
7
|
+
result="$(node -e "
|
|
8
|
+
const input = JSON.parse(process.argv[1]);
|
|
9
|
+
const tool = input.tool_name || '';
|
|
10
|
+
if (tool !== 'Edit' && tool !== 'Write') { console.log('ALLOW'); process.exit(0); }
|
|
11
|
+
const file = input.tool_input?.file_path || input.tool_input?.filePath || '';
|
|
12
|
+
if (!file.endsWith('tasks.md')) { console.log('ALLOW'); process.exit(0); }
|
|
13
|
+
const content = input.tool_input?.new_string || input.tool_input?.content || '';
|
|
14
|
+
if (/\b(deferred|skip(ped)?|later|todo)\b/i.test(content)) { console.log('DENY'); } else { console.log('ALLOW'); }
|
|
15
|
+
" "$input" 2>/dev/null || echo "ALLOW")"
|
|
16
|
+
|
|
17
|
+
if [[ "$result" == "DENY" ]]; then
|
|
18
|
+
echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"DENIED: tasks.md cannot contain deferred, skip, later, or TODO. Implement the item now or explain why impossible. See .claude/rules/no-deferred.md"}}'
|
|
19
|
+
else
|
|
20
|
+
echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}'
|
|
21
|
+
fi
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# PreToolUse hook: deny stubs, TODOs, placeholders in source code
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
input="$(cat)"
|
|
5
|
+
|
|
6
|
+
result="$(node -e "
|
|
7
|
+
const input = JSON.parse(process.argv[1]);
|
|
8
|
+
const tool = input.tool_name || '';
|
|
9
|
+
if (tool !== 'Edit' && tool !== 'Write') { console.log('ALLOW'); process.exit(0); }
|
|
10
|
+
const file = input.tool_input?.file_path || input.tool_input?.filePath || '';
|
|
11
|
+
// Only check source files
|
|
12
|
+
if (!/\.(ts|tsx|js|jsx|py|rs|go|java|cs|cpp|c|hpp|h)$/.test(file)) { console.log('ALLOW'); process.exit(0); }
|
|
13
|
+
// Skip test files
|
|
14
|
+
if (/\.test\.|\.spec\.|__tests__|\/tests\//.test(file)) { console.log('ALLOW'); process.exit(0); }
|
|
15
|
+
const content = input.tool_input?.new_string || input.tool_input?.content || '';
|
|
16
|
+
if (/\/\/\s*(TODO|FIXME|HACK)\b|\/\*\s*(TODO|FIXME|HACK)\b|#\s*(TODO|FIXME|HACK)\b/.test(content)) { console.log('DENY_TODO'); process.exit(0); }
|
|
17
|
+
if (/\bplaceholder\b|\bstub\b/i.test(content)) { console.log('DENY_STUB'); process.exit(0); }
|
|
18
|
+
console.log('ALLOW');
|
|
19
|
+
" "$input" 2>/dev/null || echo "ALLOW")"
|
|
20
|
+
|
|
21
|
+
case "$result" in
|
|
22
|
+
DENY_TODO)
|
|
23
|
+
echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"DENIED: source code cannot contain // TODO, // FIXME, or // HACK. Implement the logic now. See .claude/rules/no-shortcuts.md"}}'
|
|
24
|
+
;;
|
|
25
|
+
DENY_STUB)
|
|
26
|
+
echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"DENIED: source code cannot contain placeholders or stubs. Implement real logic. See .claude/rules/no-shortcuts.md"}}'
|
|
27
|
+
;;
|
|
28
|
+
*)
|
|
29
|
+
echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}'
|
|
30
|
+
;;
|
|
31
|
+
esac
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Claude Code PreToolUse hook for the Agent tool (PowerShell variant).
|
|
2
|
+
#
|
|
3
|
+
# Policy enforced by @hivehub/rulebook v5.3.0:
|
|
4
|
+
# - A single Agent call is fine (foreground or background).
|
|
5
|
+
# - Spawning multiple standalone background Agents is FORBIDDEN.
|
|
6
|
+
# Parallel multi-agent work MUST go through a Team so agents can
|
|
7
|
+
# communicate via SendMessage.
|
|
8
|
+
#
|
|
9
|
+
# Block any Agent invocation with run_in_background=true UNLESS it
|
|
10
|
+
# targets subagent_type=team-lead or provides a team_name. This forces
|
|
11
|
+
# background parallel work through a Team.
|
|
12
|
+
|
|
13
|
+
$ErrorActionPreference = 'Stop'
|
|
14
|
+
|
|
15
|
+
$input = [Console]::In.ReadToEnd()
|
|
16
|
+
$data = $null
|
|
17
|
+
try { $data = $input | ConvertFrom-Json } catch {}
|
|
18
|
+
|
|
19
|
+
$toolName = $null
|
|
20
|
+
if ($data -and $data.PSObject.Properties.Name -contains 'tool_name') { $toolName = $data.tool_name }
|
|
21
|
+
|
|
22
|
+
if ($toolName -ne 'Agent') {
|
|
23
|
+
Write-Output '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}'
|
|
24
|
+
exit 0
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
$runInBackground = $false
|
|
28
|
+
$subagentType = ''
|
|
29
|
+
$teamName = ''
|
|
30
|
+
if ($data.tool_input) {
|
|
31
|
+
if ($data.tool_input.PSObject.Properties.Name -contains 'run_in_background') {
|
|
32
|
+
$runInBackground = [bool]$data.tool_input.run_in_background
|
|
33
|
+
}
|
|
34
|
+
if ($data.tool_input.PSObject.Properties.Name -contains 'subagent_type') {
|
|
35
|
+
$subagentType = [string]$data.tool_input.subagent_type
|
|
36
|
+
}
|
|
37
|
+
if ($data.tool_input.PSObject.Properties.Name -contains 'team_name') {
|
|
38
|
+
$teamName = [string]$data.tool_input.team_name
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (-not $runInBackground) {
|
|
43
|
+
Write-Output '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}'
|
|
44
|
+
exit 0
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if ($subagentType -eq 'team-lead' -or $teamName) {
|
|
48
|
+
Write-Output '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}'
|
|
49
|
+
exit 0
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
$reason = 'POLICY VIOLATION: Spawning standalone background Agents is forbidden. Multi-agent parallel work MUST use a Team so agents can communicate via SendMessage. Either (a) use TeamCreate to create a team, (b) spawn a team-lead that creates the team, or (c) set team_name on the Agent call. See .claude/rules/multi-agent-teams.md for the policy.'
|
|
53
|
+
|
|
54
|
+
$out = @{
|
|
55
|
+
hookSpecificOutput = @{
|
|
56
|
+
hookEventName = 'PreToolUse'
|
|
57
|
+
permissionDecision = 'deny'
|
|
58
|
+
permissionDecisionReason = $reason
|
|
59
|
+
}
|
|
60
|
+
} | ConvertTo-Json -Compress -Depth 4
|
|
61
|
+
|
|
62
|
+
Write-Output $out
|
|
63
|
+
exit 0
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Claude Code PreToolUse hook for the Agent tool.
|
|
3
|
+
#
|
|
4
|
+
# Policy enforced by @hivehub/rulebook v5.3.0:
|
|
5
|
+
# - A single Agent call is fine (foreground or background).
|
|
6
|
+
# - Spawning multiple standalone Agents for parallel work is FORBIDDEN.
|
|
7
|
+
# Parallel multi-agent work MUST go through a Team so agents can
|
|
8
|
+
# communicate via SendMessage.
|
|
9
|
+
#
|
|
10
|
+
# Enforcement strategy:
|
|
11
|
+
# Block any Agent invocation with `run_in_background: true` UNLESS it
|
|
12
|
+
# targets `subagent_type: team-lead` or provides a `team_name`. This
|
|
13
|
+
# forces background parallel work to be coordinated through a Team.
|
|
14
|
+
#
|
|
15
|
+
# The hook reads the tool input JSON from stdin and emits a permission
|
|
16
|
+
# decision JSON on stdout, per Claude Code's PreToolUse hook contract.
|
|
17
|
+
|
|
18
|
+
set -euo pipefail
|
|
19
|
+
|
|
20
|
+
input="$(cat)"
|
|
21
|
+
|
|
22
|
+
tool_name="$(printf '%s' "$input" | jq -r '.tool_name // empty' 2>/dev/null || true)"
|
|
23
|
+
if [[ "$tool_name" != "Agent" ]]; then
|
|
24
|
+
# Not our concern — allow.
|
|
25
|
+
printf '%s' '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}'
|
|
26
|
+
exit 0
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
run_in_background="$(printf '%s' "$input" | jq -r '.tool_input.run_in_background // false' 2>/dev/null || echo false)"
|
|
30
|
+
subagent_type="$(printf '%s' "$input" | jq -r '.tool_input.subagent_type // empty' 2>/dev/null || true)"
|
|
31
|
+
team_name="$(printf '%s' "$input" | jq -r '.tool_input.team_name // empty' 2>/dev/null || true)"
|
|
32
|
+
|
|
33
|
+
# Foreground single agent → always allowed.
|
|
34
|
+
if [[ "$run_in_background" != "true" ]]; then
|
|
35
|
+
printf '%s' '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}'
|
|
36
|
+
exit 0
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
# Background agents must be part of a team OR be the team-lead coordinator.
|
|
40
|
+
if [[ "$subagent_type" == "team-lead" ]] || [[ -n "$team_name" ]]; then
|
|
41
|
+
printf '%s' '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}'
|
|
42
|
+
exit 0
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# Block standalone background agent.
|
|
46
|
+
reason="POLICY VIOLATION: Spawning standalone background Agents is forbidden. Multi-agent parallel work MUST use a Team so agents can communicate via SendMessage. Either (a) use TeamCreate to create a team, (b) spawn a team-lead that creates the team, or (c) set team_name on the Agent call. See .claude/rules/multi-agent-teams.md for the policy."
|
|
47
|
+
|
|
48
|
+
jq -nc --arg reason "$reason" '{
|
|
49
|
+
hookSpecificOutput: {
|
|
50
|
+
hookEventName: "PreToolUse",
|
|
51
|
+
permissionDecision: "deny",
|
|
52
|
+
permissionDecisionReason: $reason
|
|
53
|
+
}
|
|
54
|
+
}'
|
|
55
|
+
exit 0
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Claude Code SessionStart hook (matcher: "compact").
|
|
3
|
+
#
|
|
4
|
+
# Re-injects critical architectural context after a conversation
|
|
5
|
+
# compaction. Claude Code already re-loads CLAUDE.md on compact, so
|
|
6
|
+
# this hook is defense-in-depth: it outputs a short, always-fresh
|
|
7
|
+
# cheat sheet from `.rulebook/COMPACT_CONTEXT.md` so the model has
|
|
8
|
+
# the load-bearing reminders immediately available without waiting
|
|
9
|
+
# for the CLAUDE.md re-read.
|
|
10
|
+
#
|
|
11
|
+
# The file is user-editable. Rulebook seeds it during `init` from a
|
|
12
|
+
# stack-specific template and never overwrites it afterward.
|
|
13
|
+
|
|
14
|
+
set -euo pipefail
|
|
15
|
+
|
|
16
|
+
PROJECT_ROOT="$(pwd)"
|
|
17
|
+
CONTEXT_FILE="${PROJECT_ROOT}/.rulebook/COMPACT_CONTEXT.md"
|
|
18
|
+
|
|
19
|
+
if [[ ! -f "$CONTEXT_FILE" ]]; then
|
|
20
|
+
# Nothing to inject — emit a benign empty additionalContext.
|
|
21
|
+
printf '%s' '{"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":""}}'
|
|
22
|
+
exit 0
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
content="$(cat "$CONTEXT_FILE")"
|
|
26
|
+
|
|
27
|
+
# Emit as additionalContext via jq so we correctly escape newlines/quotes.
|
|
28
|
+
jq -nc --arg ctx "$content" '{
|
|
29
|
+
hookSpecificOutput: {
|
|
30
|
+
hookEventName: "SessionStart",
|
|
31
|
+
additionalContext: $ctx
|
|
32
|
+
}
|
|
33
|
+
}'
|
|
34
|
+
exit 0
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Claude Code SessionStart hook — auto-restore from handoff (PowerShell).
|
|
2
|
+
# See resume-from-handoff.sh for the full design rationale.
|
|
3
|
+
|
|
4
|
+
$ErrorActionPreference = 'Stop'
|
|
5
|
+
|
|
6
|
+
$ProjectRoot = Get-Location
|
|
7
|
+
$HandoffDir = Join-Path $ProjectRoot '.rulebook/handoff'
|
|
8
|
+
$Pending = Join-Path $HandoffDir '_pending.md'
|
|
9
|
+
$Urgent = Join-Path $HandoffDir '.urgent'
|
|
10
|
+
|
|
11
|
+
if (-not (Test-Path $Pending)) {
|
|
12
|
+
Write-Output '{}'
|
|
13
|
+
exit 0
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
$content = Get-Content $Pending -Raw
|
|
17
|
+
$timestamp = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH-mm-ss')
|
|
18
|
+
$archiveName = "${timestamp}.md"
|
|
19
|
+
Move-Item $Pending (Join-Path $HandoffDir $archiveName) -Force
|
|
20
|
+
|
|
21
|
+
if (Test-Path $Urgent) { Remove-Item $Urgent -Force }
|
|
22
|
+
|
|
23
|
+
$header = "## Session restored from handoff ($archiveName)`n`n"
|
|
24
|
+
$ctx = $header + $content
|
|
25
|
+
$out = @{
|
|
26
|
+
hookSpecificOutput = @{
|
|
27
|
+
hookEventName = 'SessionStart'
|
|
28
|
+
additionalContext = $ctx
|
|
29
|
+
}
|
|
30
|
+
} | ConvertTo-Json -Compress -Depth 4
|
|
31
|
+
|
|
32
|
+
Write-Output $out
|
|
33
|
+
exit 0
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Claude Code SessionStart hook — auto-restore from handoff.
|
|
3
|
+
#
|
|
4
|
+
# Checks for `.rulebook/handoff/_pending.md`. If present, emits its
|
|
5
|
+
# contents as additionalContext so the new session begins with full
|
|
6
|
+
# prior-session context loaded, then archives the file to
|
|
7
|
+
# `.rulebook/handoff/<ISO-timestamp>.md` for history.
|
|
8
|
+
|
|
9
|
+
set -euo pipefail
|
|
10
|
+
|
|
11
|
+
PROJECT_ROOT="$(pwd)"
|
|
12
|
+
HANDOFF_DIR="${PROJECT_ROOT}/.rulebook/handoff"
|
|
13
|
+
PENDING="${HANDOFF_DIR}/_pending.md"
|
|
14
|
+
URGENT="${HANDOFF_DIR}/.urgent"
|
|
15
|
+
CONFIG_FILE="${PROJECT_ROOT}/.rulebook/rulebook.json"
|
|
16
|
+
|
|
17
|
+
# No pending handoff — nothing to inject
|
|
18
|
+
if [[ ! -f "$PENDING" ]]; then
|
|
19
|
+
printf '%s' '{}'
|
|
20
|
+
exit 0
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
content="$(cat "$PENDING")"
|
|
24
|
+
|
|
25
|
+
# Archive the pending file with ISO timestamp
|
|
26
|
+
timestamp=$(date -u +"%Y-%m-%dT%H-%M-%S")
|
|
27
|
+
archive_name="${timestamp}.md"
|
|
28
|
+
mv "$PENDING" "${HANDOFF_DIR}/${archive_name}"
|
|
29
|
+
|
|
30
|
+
# Clear urgent sentinel if present
|
|
31
|
+
rm -f "$URGENT"
|
|
32
|
+
|
|
33
|
+
# Prune old handoff files (keep max N, default 50)
|
|
34
|
+
max_history=50
|
|
35
|
+
if [[ -f "$CONFIG_FILE" ]] && command -v jq &>/dev/null; then
|
|
36
|
+
max_history=$(jq -r '.handoff.maxHistoryFiles // 50' "$CONFIG_FILE" 2>/dev/null || echo 50)
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
# Count and prune (oldest first, skip _pending.md and .urgent)
|
|
40
|
+
history_count=$(find "$HANDOFF_DIR" -maxdepth 1 -name "*.md" -type f 2>/dev/null | wc -l)
|
|
41
|
+
if [[ "$history_count" -gt "$max_history" ]]; then
|
|
42
|
+
excess=$(( history_count - max_history ))
|
|
43
|
+
find "$HANDOFF_DIR" -maxdepth 1 -name "*.md" -type f -printf '%T@ %p\n' 2>/dev/null \
|
|
44
|
+
| sort -n | head -"$excess" | awk '{print $2}' | xargs rm -f
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# Emit the handoff content as additionalContext
|
|
48
|
+
header="## Session restored from handoff (${archive_name})\n\nThe following context was saved by the previous session's /handoff skill:\n\n"
|
|
49
|
+
jq -nc --arg ctx "${header}${content}" '{
|
|
50
|
+
hookSpecificOutput: {
|
|
51
|
+
hookEventName: "SessionStart",
|
|
52
|
+
additionalContext: $ctx
|
|
53
|
+
}
|
|
54
|
+
}'
|
|
55
|
+
exit 0
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<!-- Generated by @hivehub/rulebook v5.3.0 — delete this comment to prevent regeneration on `rulebook update` -->
|
|
2
|
+
|
|
3
|
+
# Consult analysis before implementing
|
|
4
|
+
|
|
5
|
+
When you start working on any task whose `proposal.md` contains a
|
|
6
|
+
`Source: docs/analysis/<slug>/` reference, you MUST first:
|
|
7
|
+
|
|
8
|
+
1. Read the referenced analysis README and findings
|
|
9
|
+
2. Run `rulebook_knowledge_list` (or `rulebook knowledge list`) and
|
|
10
|
+
scan for entries tagged `analysis:<slug>`
|
|
11
|
+
3. Run `rulebook_memory_search` with query `analysis:<slug>` to
|
|
12
|
+
retrieve any prior session context about this analysis
|
|
13
|
+
|
|
14
|
+
Only after reviewing these results may you begin implementation.
|
|
15
|
+
|
|
16
|
+
## Why
|
|
17
|
+
|
|
18
|
+
Analyses accumulate institutional knowledge (patterns, anti-patterns,
|
|
19
|
+
architectural decisions, validated findings). Implementing without
|
|
20
|
+
consulting them means repeating mistakes or contradicting decisions
|
|
21
|
+
that were already made based on evidence.
|
|
22
|
+
|
|
23
|
+
This rule is part of the `/analysis` workflow (v5.3.0 F-NEW-4).
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.cpp"
|
|
4
|
+
- "**/*.cc"
|
|
5
|
+
- "**/*.cxx"
|
|
6
|
+
- "**/*.hpp"
|
|
7
|
+
- "**/*.hh"
|
|
8
|
+
- "**/*.h"
|
|
9
|
+
- "CMakeLists.txt"
|
|
10
|
+
- "**/CMakeLists.txt"
|
|
11
|
+
- "**/*.cmake"
|
|
12
|
+
---
|
|
13
|
+
<!-- Generated by @hivehub/rulebook v5.3.0 — delete this comment to prevent regeneration on `rulebook update` -->
|
|
14
|
+
|
|
15
|
+
# C / C++ rules
|
|
16
|
+
|
|
17
|
+
Loaded by Claude Code when touching C/C++ or CMake sources.
|
|
18
|
+
|
|
19
|
+
## Non-negotiables
|
|
20
|
+
|
|
21
|
+
1. **Build before test.** Run the compiler (`cmake --build <build>` or equivalent) before running tests. Link errors and missing symbols surface at build time — do not waste time running a binary that cannot link.
|
|
22
|
+
2. **Treat warnings as errors.** `-Wall -Wextra -Werror` (gcc/clang) or `/W4 /WX` (MSVC). If a warning is a false positive, document it with a pragma and a comment.
|
|
23
|
+
3. **Use smart pointers.** `std::unique_ptr` by default, `std::shared_ptr` only when ownership is genuinely shared. Raw `new`/`delete` requires justification.
|
|
24
|
+
4. **RAII for every resource.** File handles, sockets, locks, GPU resources — wrap in a class with a destructor. Never match `open`/`close` pairs by hand.
|
|
25
|
+
5. **No undefined behavior shortcuts.** No signed overflow reliance, no strict-aliasing violations, no reinterpret_cast across unrelated types without `memcpy`.
|
|
26
|
+
|
|
27
|
+
## Conventions
|
|
28
|
+
|
|
29
|
+
- C++17 baseline; C++20 features only if the project's CMake confirms support.
|
|
30
|
+
- Header guards via `#pragma once` unless the project uses traditional `#ifndef` blocks.
|
|
31
|
+
- `const` everywhere you can — parameters, methods, locals.
|
|
32
|
+
- `auto` for types that are obvious from RHS (iterators, lambdas); spell the type when it aids the reader.
|
|
33
|
+
- Avoid `using namespace std;` in headers (acceptable in .cpp with a tight scope).
|
|
34
|
+
|
|
35
|
+
## Testing
|
|
36
|
+
|
|
37
|
+
- Use the project's framework (GoogleTest, Catch2, doctest) — do not add a new one.
|
|
38
|
+
- Run under ASan / UBSan on CI (`-fsanitize=address,undefined`).
|
|
39
|
+
- Prefer property-based / fuzz tests for parsers and serializers.
|
|
40
|
+
|
|
41
|
+
## Build & tooling
|
|
42
|
+
|
|
43
|
+
- Out-of-source builds only. `build/` is gitignored.
|
|
44
|
+
- `clang-format` from a committed `.clang-format` is the only formatting authority.
|
|
45
|
+
- `compile_commands.json` exported (`-DCMAKE_EXPORT_COMPILE_COMMANDS=ON`) for clangd / tooling.
|
|
46
|
+
- Never commit object files, binaries, or PDBs.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.cs"
|
|
4
|
+
- "**/*.csproj"
|
|
5
|
+
- "**/*.sln"
|
|
6
|
+
- "Directory.Build.props"
|
|
7
|
+
- "Directory.Build.targets"
|
|
8
|
+
- "global.json"
|
|
9
|
+
---
|
|
10
|
+
<!-- Generated by @hivehub/rulebook v5.3.0 — delete this comment to prevent regeneration on `rulebook update` -->
|
|
11
|
+
|
|
12
|
+
# C# rules
|
|
13
|
+
|
|
14
|
+
Loaded by Claude Code when touching C# sources or MSBuild files.
|
|
15
|
+
|
|
16
|
+
## Non-negotiables
|
|
17
|
+
|
|
18
|
+
1. **Build before test.** `dotnet build` before `dotnet test`. Compilation errors surface faster and cheaper than test failures.
|
|
19
|
+
2. **Nullable reference types enabled.** `<Nullable>enable</Nullable>` in the csproj. Treat warnings as errors where the project configures it.
|
|
20
|
+
3. **No `!` (null-forgiving) without a comment** explaining why the compiler is wrong.
|
|
21
|
+
4. **`async` all the way.** No `.Result` / `.Wait()` in async code paths — deadlocks are the inevitable consequence.
|
|
22
|
+
5. **Dispose or `using`.** Every `IDisposable` is either wrapped in `using` / `await using` or explicitly disposed in a `finally`.
|
|
23
|
+
|
|
24
|
+
## Conventions
|
|
25
|
+
|
|
26
|
+
- PascalCase for public members, camelCase for parameters and locals, `_camelCase` for private fields.
|
|
27
|
+
- `var` when the type is obvious from RHS; spell the type otherwise.
|
|
28
|
+
- Prefer records for DTOs (C# 9+); sealed classes by default.
|
|
29
|
+
- `CancellationToken` as the last parameter of async methods.
|
|
30
|
+
- Do not catch `Exception` — catch the specific type or rethrow.
|
|
31
|
+
|
|
32
|
+
## Testing
|
|
33
|
+
|
|
34
|
+
- xUnit, NUnit, or MSTest per project config — do not add a new one.
|
|
35
|
+
- FluentAssertions for readable asserts where already used.
|
|
36
|
+
- `[Theory]` / parameterized tests for input-table coverage.
|
|
37
|
+
- Mocks via Moq / NSubstitute; avoid heavy mocking frameworks.
|
|
38
|
+
|
|
39
|
+
## Build & tooling
|
|
40
|
+
|
|
41
|
+
- `dotnet format` before committing.
|
|
42
|
+
- Commit `.csproj`, never `bin/` or `obj/`.
|
|
43
|
+
- Target framework pinned via `global.json` when multiple SDKs are installed.
|
|
44
|
+
- Run `dotnet build --warnaserror` on CI.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<!-- Generated by @hivehub/rulebook v5.3.0 — delete this comment to prevent regeneration on `rulebook update` -->
|
|
2
|
+
|
|
3
|
+
# Check before test (diagnostic-first)
|
|
4
|
+
|
|
5
|
+
**Always run diagnostic tools before the test suite.**
|
|
6
|
+
|
|
7
|
+
| Language | Check command | Run BEFORE |
|
|
8
|
+
|----------|--------------|------------|
|
|
9
|
+
| TypeScript | `tsc --noEmit` / `npm run type-check` | `npm test` |
|
|
10
|
+
| Rust | `cargo check` | `cargo test` |
|
|
11
|
+
| Python | `mypy .` / `pyright` | `pytest` |
|
|
12
|
+
| Go | `go vet ./...` | `go test ./...` |
|
|
13
|
+
| C/C++ | `cmake --build <dir>` | `ctest` |
|
|
14
|
+
| Java | `mvn compile` | `mvn test` |
|
|
15
|
+
| C# | `dotnet build` | `dotnet test` |
|
|
16
|
+
| TML | `mcp__tml__check` (MCP) / `scripts/build.bat` | `mcp__tml__test` |
|
|
17
|
+
|
|
18
|
+
## Why
|
|
19
|
+
|
|
20
|
+
Diagnostic tools (type-checkers, linters, compilers) are **5–10x faster**
|
|
21
|
+
than test suites and catch a different class of errors. Running them first:
|
|
22
|
+
|
|
23
|
+
1. Surfaces errors that tests would catch slower (or not at all)
|
|
24
|
+
2. Avoids wasting a full test cycle on code that can't compile
|
|
25
|
+
3. Provides faster feedback loops per iteration
|
|
26
|
+
|
|
27
|
+
**Evidence**: a single "check before test" prompt rule raised diagnostic
|
|
28
|
+
tool adoption from 8.8% to 25.3% in 10 days, accelerating rather than
|
|
29
|
+
plateauing. Default-on features reach 95.7% adoption vs 11.1% for opt-in.
|
|
30
|
+
(Source: LLM-IR-Debugging paper, §5–6)
|
|
31
|
+
|
|
32
|
+
## Rule
|
|
33
|
+
|
|
34
|
+
Before running the project's test suite:
|
|
35
|
+
1. Run the project's configured type-checker or compiler
|
|
36
|
+
2. Fix any errors it reports
|
|
37
|
+
3. Only then run tests
|
|
38
|
+
|
|
39
|
+
This applies to every iteration, not just the final commit check.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<!-- Generated by @hivehub/rulebook v5.3.0 — delete this comment to prevent regeneration on `rulebook update` -->
|
|
2
|
+
|
|
3
|
+
# Fail twice → escalate
|
|
4
|
+
|
|
5
|
+
If a fix attempt fails **twice with the same approach**, you MUST:
|
|
6
|
+
|
|
7
|
+
1. **Stop** — do not try a third variation of the same approach
|
|
8
|
+
2. **Analyze** what went wrong — identify root causes, not symptoms
|
|
9
|
+
3. **Escalate** — choose one:
|
|
10
|
+
- Open a **Team** (`TeamCreate`) and bring in a specialist agent
|
|
11
|
+
- **Research** the problem (read source code, search docs, use diagnostic tools)
|
|
12
|
+
- **Ask the user** for guidance (only if research does not resolve it)
|
|
13
|
+
4. **Record** the failed approach as context so the next attempt is informed
|
|
14
|
+
|
|
15
|
+
## Why
|
|
16
|
+
|
|
17
|
+
LLMs in agentic loops tend to retry the same approach with minor
|
|
18
|
+
variations until the iteration limit is reached. This wastes cycles
|
|
19
|
+
and produces cascading patches that are harder to debug than a clean
|
|
20
|
+
restart. The "fail twice → escalate" pattern breaks the loop early.
|
|
21
|
+
|
|
22
|
+
**Evidence**: UzEngine's "RULE -3" (FAIL TWICE → OPEN TEAM) has been
|
|
23
|
+
field-validated across 30+ specialized sub-agents. The LLM-IR-debugging
|
|
24
|
+
paper (§6) documents the same failure mode and confirms that structural
|
|
25
|
+
escape mechanisms are effective.
|
|
26
|
+
|
|
27
|
+
## What counts as "the same approach"
|
|
28
|
+
|
|
29
|
+
Two attempts are "the same approach" if:
|
|
30
|
+
- They modify the same file(s) in the same function/block
|
|
31
|
+
- They produce the same category of error (e.g. both fail the type-checker)
|
|
32
|
+
- The second attempt is a small variation of the first (e.g. changing a
|
|
33
|
+
parameter value, adding a cast, swapping an operator)
|
|
34
|
+
|
|
35
|
+
Two attempts are "different approaches" if:
|
|
36
|
+
- They target different root causes
|
|
37
|
+
- They modify different subsystems
|
|
38
|
+
- The second attempt was informed by new diagnostic information not
|
|
39
|
+
available during the first
|
|
40
|
+
|
|
41
|
+
## Interaction with other rules
|
|
42
|
+
|
|
43
|
+
- **incremental-implementation.md**: "spend more than 3 failed attempts"
|
|
44
|
+
is the outer limit; this rule fires earlier (at 2)
|
|
45
|
+
- **research-first.md**: escalation via research satisfies both rules
|
|
46
|
+
- **git-safety.md**: never revert as an "escalation" — fix forward
|