@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.
Files changed (157) hide show
  1. package/.claude/commands/analysis.md +35 -0
  2. package/.claude/commands/rulebook-task-apply.md +7 -25
  3. package/.claude/commands/rulebook-task-archive.md +10 -19
  4. package/.claude/commands/rulebook-task-create.md +1 -1
  5. package/README.md +354 -965
  6. package/dist/cli/commands/analysis.d.ts +8 -0
  7. package/dist/cli/commands/analysis.d.ts.map +1 -0
  8. package/dist/cli/commands/analysis.js +78 -0
  9. package/dist/cli/commands/analysis.js.map +1 -0
  10. package/dist/cli/commands/context-intelligence.d.ts +33 -0
  11. package/dist/cli/commands/context-intelligence.d.ts.map +1 -0
  12. package/dist/cli/commands/context-intelligence.js +181 -0
  13. package/dist/cli/commands/context-intelligence.js.map +1 -0
  14. package/dist/cli/commands/index.d.ts +19 -0
  15. package/dist/cli/commands/index.d.ts.map +1 -0
  16. package/dist/cli/commands/index.js +19 -0
  17. package/dist/cli/commands/index.js.map +1 -0
  18. package/dist/cli/commands/init.d.ts +15 -0
  19. package/dist/cli/commands/init.d.ts.map +1 -0
  20. package/dist/cli/commands/init.js +608 -0
  21. package/dist/cli/commands/init.js.map +1 -0
  22. package/dist/cli/commands/mcp.d.ts +10 -0
  23. package/dist/cli/commands/mcp.d.ts.map +1 -0
  24. package/dist/cli/commands/mcp.js +128 -0
  25. package/dist/cli/commands/mcp.js.map +1 -0
  26. package/dist/cli/commands/memory.d.ts +24 -0
  27. package/dist/cli/commands/memory.d.ts.map +1 -0
  28. package/dist/cli/commands/memory.js +265 -0
  29. package/dist/cli/commands/memory.js.map +1 -0
  30. package/dist/cli/commands/misc.d.ts +33 -0
  31. package/dist/cli/commands/misc.d.ts.map +1 -0
  32. package/dist/cli/commands/misc.js +576 -0
  33. package/dist/cli/commands/misc.js.map +1 -0
  34. package/dist/cli/commands/plans.d.ts +15 -0
  35. package/dist/cli/commands/plans.d.ts.map +1 -0
  36. package/dist/cli/commands/plans.js +266 -0
  37. package/dist/cli/commands/plans.js.map +1 -0
  38. package/dist/cli/commands/ralph.d.ts +45 -0
  39. package/dist/cli/commands/ralph.d.ts.map +1 -0
  40. package/dist/cli/commands/ralph.js +694 -0
  41. package/dist/cli/commands/ralph.js.map +1 -0
  42. package/dist/cli/commands/skills.d.ts +9 -0
  43. package/dist/cli/commands/skills.d.ts.map +1 -0
  44. package/dist/cli/commands/skills.js +249 -0
  45. package/dist/cli/commands/skills.js.map +1 -0
  46. package/dist/cli/commands/task.d.ts +16 -0
  47. package/dist/cli/commands/task.d.ts.map +1 -0
  48. package/dist/cli/commands/task.js +256 -0
  49. package/dist/cli/commands/task.js.map +1 -0
  50. package/dist/cli/commands/update.d.ts +14 -0
  51. package/dist/cli/commands/update.d.ts.map +1 -0
  52. package/dist/cli/commands/update.js +636 -0
  53. package/dist/cli/commands/update.js.map +1 -0
  54. package/dist/cli/commands/workspace.d.ts +6 -0
  55. package/dist/cli/commands/workspace.d.ts.map +1 -0
  56. package/dist/cli/commands/workspace.js +141 -0
  57. package/dist/cli/commands/workspace.js.map +1 -0
  58. package/dist/core/agent-template-engine.js +28 -28
  59. package/dist/core/analysis-manager.d.ts +56 -0
  60. package/dist/core/analysis-manager.d.ts.map +1 -0
  61. package/dist/core/analysis-manager.js +218 -0
  62. package/dist/core/analysis-manager.js.map +1 -0
  63. package/dist/core/claude-md-generator.d.ts +52 -0
  64. package/dist/core/claude-md-generator.d.ts.map +1 -0
  65. package/dist/core/claude-md-generator.js +104 -0
  66. package/dist/core/claude-md-generator.js.map +1 -0
  67. package/dist/core/claude-settings-manager.d.ts +37 -0
  68. package/dist/core/claude-settings-manager.d.ts.map +1 -0
  69. package/dist/core/claude-settings-manager.js +168 -0
  70. package/dist/core/claude-settings-manager.js.map +1 -0
  71. package/dist/core/compact-context-manager.d.ts +34 -0
  72. package/dist/core/compact-context-manager.d.ts.map +1 -0
  73. package/dist/core/compact-context-manager.js +60 -0
  74. package/dist/core/compact-context-manager.js.map +1 -0
  75. package/dist/core/doctor.d.ts +19 -0
  76. package/dist/core/doctor.d.ts.map +1 -0
  77. package/dist/core/doctor.js +163 -0
  78. package/dist/core/doctor.js.map +1 -0
  79. package/dist/core/generator.js +28 -28
  80. package/dist/core/mcp-reference-generator.d.ts +13 -0
  81. package/dist/core/mcp-reference-generator.d.ts.map +1 -0
  82. package/dist/core/mcp-reference-generator.js +66 -0
  83. package/dist/core/mcp-reference-generator.js.map +1 -0
  84. package/dist/core/merger.d.ts +35 -0
  85. package/dist/core/merger.d.ts.map +1 -1
  86. package/dist/core/merger.js +120 -0
  87. package/dist/core/merger.js.map +1 -1
  88. package/dist/core/prd-generator.d.ts.map +1 -1
  89. package/dist/core/prd-generator.js +7 -1
  90. package/dist/core/prd-generator.js.map +1 -1
  91. package/dist/core/ralph-manager.d.ts.map +1 -1
  92. package/dist/core/ralph-manager.js +17 -0
  93. package/dist/core/ralph-manager.js.map +1 -1
  94. package/dist/core/rules-generator.d.ts +73 -0
  95. package/dist/core/rules-generator.d.ts.map +1 -0
  96. package/dist/core/rules-generator.js +201 -0
  97. package/dist/core/rules-generator.js.map +1 -0
  98. package/dist/core/state-writer.d.ts +35 -0
  99. package/dist/core/state-writer.d.ts.map +1 -0
  100. package/dist/core/state-writer.js +81 -0
  101. package/dist/core/state-writer.js.map +1 -0
  102. package/dist/core/task-manager.d.ts +35 -0
  103. package/dist/core/task-manager.d.ts.map +1 -1
  104. package/dist/core/task-manager.js +135 -38
  105. package/dist/core/task-manager.js.map +1 -1
  106. package/dist/core/telemetry.d.ts +29 -0
  107. package/dist/core/telemetry.d.ts.map +1 -0
  108. package/dist/core/telemetry.js +57 -0
  109. package/dist/core/telemetry.js.map +1 -0
  110. package/dist/core/workflow-generator.d.ts.map +1 -1
  111. package/dist/core/workflow-generator.js +2 -177
  112. package/dist/core/workflow-generator.js.map +1 -1
  113. package/dist/index.js +28 -1
  114. package/dist/index.js.map +1 -1
  115. package/dist/mcp/rulebook-server.d.ts.map +1 -1
  116. package/dist/mcp/rulebook-server.js +190 -7
  117. package/dist/mcp/rulebook-server.js.map +1 -1
  118. package/dist/memory/memory-store.js +91 -91
  119. package/dist/types.d.ts +11 -0
  120. package/dist/types.d.ts.map +1 -1
  121. package/dist/utils/gitignore.d.ts +10 -0
  122. package/dist/utils/gitignore.d.ts.map +1 -0
  123. package/dist/utils/gitignore.js +38 -0
  124. package/dist/utils/gitignore.js.map +1 -0
  125. package/package.json +1 -1
  126. package/templates/compact-context/_default.md +23 -0
  127. package/templates/compact-context/cpp.md +26 -0
  128. package/templates/compact-context/go.md +26 -0
  129. package/templates/compact-context/python.md +26 -0
  130. package/templates/compact-context/rust.md +28 -0
  131. package/templates/compact-context/typescript.md +29 -0
  132. package/templates/core/CLAUDE_MD_v2.md +71 -0
  133. package/templates/hooks/check-context-and-handoff.ps1 +50 -0
  134. package/templates/hooks/check-context-and-handoff.sh +69 -0
  135. package/templates/hooks/enforce-mcp-for-tasks.sh +31 -0
  136. package/templates/hooks/enforce-no-deferred.sh +21 -0
  137. package/templates/hooks/enforce-no-shortcuts.sh +31 -0
  138. package/templates/hooks/enforce-team-for-background-agents.ps1 +63 -0
  139. package/templates/hooks/enforce-team-for-background-agents.sh +55 -0
  140. package/templates/hooks/on-compact-reinject.sh +34 -0
  141. package/templates/hooks/resume-from-handoff.ps1 +33 -0
  142. package/templates/hooks/resume-from-handoff.sh +55 -0
  143. package/templates/rules/consult-analysis-before-implementing.md +23 -0
  144. package/templates/rules/cpp.md +46 -0
  145. package/templates/rules/csharp.md +44 -0
  146. package/templates/rules/diagnostic-first.md +39 -0
  147. package/templates/rules/fail-twice-escalate.md +46 -0
  148. package/templates/rules/go.md +40 -0
  149. package/templates/rules/java.md +43 -0
  150. package/templates/rules/javascript.md +39 -0
  151. package/templates/rules/multi-agent-teams.md +75 -0
  152. package/templates/rules/python.md +43 -0
  153. package/templates/rules/respect-handoff-trigger.md +41 -0
  154. package/templates/rules/rust.md +40 -0
  155. package/templates/rules/typescript.md +40 -0
  156. package/templates/skills/dev/analysis/SKILL.md +19 -0
  157. 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