@rune-kit/rune 2.4.0 → 2.7.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 (49) hide show
  1. package/README.md +47 -17
  2. package/compiler/__tests__/executive-dashboards.test.js +285 -0
  3. package/compiler/__tests__/inject.test.js +128 -0
  4. package/compiler/__tests__/orchestrators.test.js +151 -0
  5. package/compiler/__tests__/org-templates.test.js +447 -0
  6. package/compiler/__tests__/pack-split.test.js +141 -1
  7. package/compiler/__tests__/parser.test.js +147 -1
  8. package/compiler/__tests__/scripts-bundling.test.js +10 -11
  9. package/compiler/__tests__/skill-index.test.js +218 -0
  10. package/compiler/__tests__/status.test.js +336 -0
  11. package/compiler/__tests__/templates.test.js +245 -0
  12. package/compiler/__tests__/visualizer.test.js +325 -0
  13. package/compiler/adapters/antigravity.js +18 -4
  14. package/compiler/bin/rune.js +90 -1
  15. package/compiler/doctor.js +283 -2
  16. package/compiler/emitter.js +490 -17
  17. package/compiler/parser.js +255 -4
  18. package/compiler/status.js +342 -0
  19. package/compiler/visualizer.js +622 -0
  20. package/hooks/hooks.json +12 -0
  21. package/hooks/intent-router/index.cjs +108 -0
  22. package/hooks/pre-tool-guard/index.cjs +177 -68
  23. package/package.json +63 -63
  24. package/skills/autopsy/SKILL.md +48 -1
  25. package/skills/brainstorm/SKILL.md +2 -0
  26. package/skills/completion-gate/SKILL.md +26 -1
  27. package/skills/context-engine/SKILL.md +93 -2
  28. package/skills/cook/SKILL.md +794 -648
  29. package/skills/debug/SKILL.md +409 -392
  30. package/skills/deploy/SKILL.md +2 -0
  31. package/skills/docs/SKILL.md +28 -3
  32. package/skills/fix/SKILL.md +284 -281
  33. package/skills/mcp-builder/SKILL.md +53 -1
  34. package/skills/onboard/SKILL.md +58 -1
  35. package/skills/perf/SKILL.md +34 -1
  36. package/skills/plan/SKILL.md +372 -342
  37. package/skills/preflight/SKILL.md +396 -360
  38. package/skills/retro/SKILL.md +95 -1
  39. package/skills/review/SKILL.md +535 -489
  40. package/skills/scope-guard/SKILL.md +1 -0
  41. package/skills/scout/SKILL.md +1 -0
  42. package/skills/sentinel/SKILL.md +353 -299
  43. package/skills/sentinel/references/policy-driven-constraints.md +424 -0
  44. package/skills/session-bridge/SKILL.md +58 -2
  45. package/skills/session-bridge/references/evolutionary-memory-patterns.md +312 -0
  46. package/skills/team/SKILL.md +16 -1
  47. package/skills/test/SKILL.md +587 -585
  48. package/skills/verification/SKILL.md +1 -0
  49. package/skills/watchdog/SKILL.md +2 -0
@@ -0,0 +1,108 @@
1
+ // Rune Intent Router Hook — Compiled Intent Mesh (CIM)
2
+ // Auto-suggests skill routing based on user prompt analysis
3
+ // Runs as UserPromptSubmit hook — scores prompt against compiled skill-index.json
4
+ //
5
+ // Key difference from runtime scoring approaches:
6
+ // - Compile-time generated index (zero runtime deps)
7
+ // - Mesh-aware chain prediction (uses actual connection graph)
8
+ // - Works on all platforms (index ships with every build)
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+
13
+ // Read user prompt from Claude Code hook stdin
14
+ let input = '';
15
+ process.stdin.setEncoding('utf-8');
16
+ process.stdin.on('data', (chunk) => { input += chunk; });
17
+ process.stdin.on('end', () => {
18
+ let userPrompt = '';
19
+ try {
20
+ const parsed = JSON.parse(input);
21
+ userPrompt = parsed.user_prompt || parsed.prompt || parsed.content || '';
22
+ } catch {
23
+ // Raw text input
24
+ userPrompt = input.trim();
25
+ }
26
+
27
+ if (!userPrompt || userPrompt.length < 3) {
28
+ process.exit(0);
29
+ }
30
+
31
+ // Find skill-index.json — check multiple locations
32
+ const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT || path.resolve(__dirname, '../..');
33
+ const candidates = [
34
+ path.join(pluginRoot, '.cursor', 'rules', 'skill-index.json'),
35
+ path.join(pluginRoot, '.windsurf', 'rules', 'skill-index.json'),
36
+ path.join(pluginRoot, 'dist', 'cursor', 'skill-index.json'),
37
+ path.join(pluginRoot, 'dist', 'generic', 'skill-index.json'),
38
+ // Also check .rune/ for locally cached index
39
+ path.join(process.cwd(), '.rune', 'skill-index.json'),
40
+ ];
41
+
42
+ let index = null;
43
+ for (const candidate of candidates) {
44
+ try {
45
+ if (fs.existsSync(candidate)) {
46
+ index = JSON.parse(fs.readFileSync(candidate, 'utf-8'));
47
+ break;
48
+ }
49
+ } catch {
50
+ // Try next candidate
51
+ }
52
+ }
53
+
54
+ if (!index || !index.intents) {
55
+ // No index available — exit silently (not an error, just not built yet)
56
+ process.exit(0);
57
+ }
58
+
59
+ // Score prompt against intent patterns
60
+ const promptLower = userPrompt.toLowerCase();
61
+ const scores = [];
62
+
63
+ for (const [skillName, intent] of Object.entries(index.intents)) {
64
+ let score = 0;
65
+
66
+ for (const keyword of intent.keywords) {
67
+ if (promptLower.includes(keyword)) {
68
+ // Exact word boundary match scores higher
69
+ const wordBoundary = new RegExp(`\\b${keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`, 'i');
70
+ score += wordBoundary.test(userPrompt) ? 3 : 1;
71
+ }
72
+ }
73
+
74
+ // Layer priority boost: L1 orchestrators get a small bonus (they're entry points)
75
+ if (intent.layer === 'L1') score += 1;
76
+
77
+ if (score > 0) {
78
+ scores.push({ skill: skillName, score, chain: intent.chain, model: intent.model, layer: intent.layer });
79
+ }
80
+ }
81
+
82
+ if (scores.length === 0) {
83
+ process.exit(0);
84
+ }
85
+
86
+ // Sort by score descending, take top match
87
+ scores.sort((a, b) => b.score - a.score);
88
+ const top = scores[0];
89
+
90
+ // Only suggest if confidence is reasonable (score >= 3 = at least one strong keyword match)
91
+ if (top.score < 3) {
92
+ process.exit(0);
93
+ }
94
+
95
+ // Format chain for display
96
+ const chainDisplay = top.chain.slice(0, 4).join(' → ');
97
+ const alternates = scores.slice(1, 3).map((s) => s.skill).join(', ');
98
+
99
+ // Output routing suggestion
100
+ console.log(`\n🧭 [Rune intent-router] Suggested: rune:${top.skill} (${top.layer}, ${top.model})`);
101
+ console.log(` Chain: ${chainDisplay}`);
102
+ if (alternates) {
103
+ console.log(` Also consider: ${alternates}`);
104
+ }
105
+ console.log('');
106
+
107
+ process.exit(0);
108
+ });
@@ -1,68 +1,177 @@
1
- // Rune Pre-Tool Guard Hook
2
- // Preventive security gate warns before AI reads/edits sensitive files
3
- // Runs as PreToolUse hook for Read, Write, Edit tools
4
-
5
- const path = require('path');
6
-
7
- // Read tool_input from Claude Code hook stdin
8
- let input = '';
9
- process.stdin.setEncoding('utf-8');
10
- process.stdin.on('data', (chunk) => { input += chunk; });
11
- process.stdin.on('end', () => {
12
- let toolInput = {};
13
- try {
14
- const parsed = JSON.parse(input);
15
- toolInput = parsed.tool_input || parsed;
16
- } catch {
17
- // If no stdin or parse fails, exit cleanly (non-blocking)
18
- process.exit(0);
19
- }
20
-
21
- const filePath = toolInput.file_path || toolInput.path || '';
22
- if (!filePath) process.exit(0);
23
-
24
- const basename = path.basename(filePath);
25
- const normalized = filePath.replace(/\\/g, '/');
26
-
27
- // Sensitive file patterns
28
- const sensitivePatterns = [
29
- /^\.env$/, // .env exactly
30
- /^\.env\.[^e]/, // .env.* but NOT .env.example
31
- /\.pem$/,
32
- /\.key$/,
33
- /\.p12$/,
34
- /\.pfx$/,
35
- /^credentials\.json$/,
36
- /\.secret$/,
37
- /^\.netrc$/,
38
- /^id_rsa$/,
39
- /^id_ed25519$/,
40
- /^id_ecdsa$/,
41
- /^\.ssh\//,
42
- /private.*key/i,
43
- /secret.*key/i,
44
- ];
45
-
46
- // Exclude safe exceptions
47
- const safeExceptions = [
48
- /\.env\.example$/,
49
- /\.env\.sample$/,
50
- /\.env\.template$/,
51
- /\.env\.test$/,
52
- /test.*credential/i,
53
- /fixture/i,
54
- /mock/i,
55
- ];
56
-
57
- const isSensitive = sensitivePatterns.some((p) => p.test(basename) || p.test(normalized));
58
- const isSafe = safeExceptions.some((p) => p.test(basename) || p.test(normalized));
59
-
60
- if (isSensitive && !isSafe) {
61
- // Output warning to user — does NOT hard-block (developer may legitimately need access)
62
- console.log(`\n⚠ [Rune pre-tool-guard] Sensitive file detected: ${filePath}`);
63
- console.log(' This file may contain secrets. Confirm this access is intentional.');
64
- console.log(' If scanning for secrets, use /rune sentinel instead.\n');
65
- }
66
-
67
- process.exit(0);
68
- });
1
+ // Rune Pre-Tool Guard Hook — Privacy Mesh
2
+ // Three-tier security gate: ALLOW / WARN / BLOCK
3
+ // Configurable via .rune/privacy.json per project
4
+ // Skill-aware: sentinel/review can access files other skills cannot
5
+ //
6
+ // Upgrades over basic path matching:
7
+ // - Per-project .rune/privacy.json config (custom patterns + overrides)
8
+ // - Three tiers: ALLOW (silent), WARN (log), BLOCK (exit code 2)
9
+ // - Content-aware: scans first bytes for secret patterns on WARN files
10
+
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+
14
+ // Read tool_input from Claude Code hook stdin
15
+ let input = '';
16
+ process.stdin.setEncoding('utf-8');
17
+ process.stdin.on('data', (chunk) => { input += chunk; });
18
+ process.stdin.on('end', () => {
19
+ let toolInput = {};
20
+ let toolName = '';
21
+ try {
22
+ const parsed = JSON.parse(input);
23
+ toolInput = parsed.tool_input || parsed;
24
+ toolName = parsed.tool_name || '';
25
+ } catch {
26
+ // If no stdin or parse fails, exit cleanly (non-blocking)
27
+ process.exit(0);
28
+ }
29
+
30
+ const filePath = toolInput.file_path || toolInput.path || '';
31
+ if (!filePath) process.exit(0);
32
+
33
+ const basename = path.basename(filePath);
34
+ const normalized = filePath.replace(/\\/g, '/');
35
+
36
+ // Load project-specific privacy config
37
+ const privacyConfig = loadPrivacyConfig();
38
+
39
+ // Default sensitive file patterns — BLOCK tier (hard block)
40
+ const blockPatterns = [
41
+ /^id_rsa$/,
42
+ /^id_ed25519$/,
43
+ /^id_ecdsa$/,
44
+ /\.p12$/,
45
+ /\.pfx$/,
46
+ /\.pem$/,
47
+ /^\.netrc$/,
48
+ /private[-_.]?key/i,
49
+ ...privacyConfig.block.map((p) => new RegExp(p)),
50
+ ];
51
+
52
+ // WARN tier (log warning, allow through)
53
+ const warnPatterns = [
54
+ /^\.env$/,
55
+ /^\.env\.[^e]/, // .env.* but NOT .env.example
56
+ /\.key$/,
57
+ /^credentials\.json$/,
58
+ /\.secret$/,
59
+ /secret[-_.]?key/i,
60
+ ...privacyConfig.warn.map((p) => new RegExp(p)),
61
+ ];
62
+
63
+ // Safe exceptions (always allow)
64
+ const safeExceptions = [
65
+ /\.env\.example$/,
66
+ /\.env\.sample$/,
67
+ /\.env\.template$/,
68
+ /\.env\.test$/,
69
+ /test.*credential/i,
70
+ /fixture/i,
71
+ /mock/i,
72
+ ...privacyConfig.allow.map((p) => new RegExp(p)),
73
+ ];
74
+
75
+ // Skills with elevated access (can read WARN-tier files without warning)
76
+ const elevatedSkills = new Set([
77
+ 'sentinel', 'review', 'audit', 'secrets-scan', 'onboard',
78
+ ...privacyConfig.elevatedSkills,
79
+ ]);
80
+
81
+ // Detect active skill from environment (set by metrics-collector or skill invocation)
82
+ const activeSkill = process.env.RUNE_ACTIVE_SKILL || '';
83
+ const isElevated = elevatedSkills.has(activeSkill);
84
+
85
+ const isSafe = safeExceptions.some((p) => p.test(basename) || p.test(normalized));
86
+ if (isSafe) process.exit(0);
87
+
88
+ const isBlocked = blockPatterns.some((p) => p.test(basename) || p.test(normalized));
89
+ if (isBlocked) {
90
+ console.log(`\n🚫 [Rune privacy-mesh] BLOCKED: ${filePath}`);
91
+ console.log(' This file matches a BLOCK-tier pattern (private keys, certificates).');
92
+ console.log(' Override: add path to .rune/privacy.json "allow" list if intentional.\n');
93
+ process.exit(2); // Exit code 2 = BLOCK
94
+ }
95
+
96
+ const isWarned = warnPatterns.some((p) => p.test(basename) || p.test(normalized));
97
+ if (isWarned && !isElevated) {
98
+ // Content-aware check: scan first 4KB for secret patterns
99
+ const contentWarning = scanContentForSecrets(filePath);
100
+
101
+ console.log(`\n⚠ [Rune privacy-mesh] Sensitive file: ${filePath}`);
102
+ if (contentWarning) {
103
+ console.log(` Content scan: ${contentWarning}`);
104
+ }
105
+ console.log(' This file may contain secrets. Confirm access is intentional.');
106
+ console.log(' Elevated skills (sentinel, review, audit) bypass this warning.\n');
107
+ }
108
+
109
+ process.exit(0);
110
+ });
111
+
112
+ /**
113
+ * Load .rune/privacy.json from project root
114
+ * Returns merged config with defaults
115
+ */
116
+ function loadPrivacyConfig() {
117
+ const defaults = { block: [], warn: [], allow: [], elevatedSkills: [] };
118
+
119
+ const candidates = [
120
+ path.join(process.cwd(), '.rune', 'privacy.json'),
121
+ path.join(process.cwd(), 'privacy.json'),
122
+ ];
123
+
124
+ for (const configPath of candidates) {
125
+ try {
126
+ if (fs.existsSync(configPath)) {
127
+ const raw = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
128
+ return {
129
+ block: Array.isArray(raw.block) ? raw.block : defaults.block,
130
+ warn: Array.isArray(raw.warn) ? raw.warn : defaults.warn,
131
+ allow: Array.isArray(raw.allow) ? raw.allow : defaults.allow,
132
+ elevatedSkills: Array.isArray(raw.elevatedSkills) ? raw.elevatedSkills : defaults.elevatedSkills,
133
+ };
134
+ }
135
+ } catch {
136
+ // Invalid config — use defaults
137
+ }
138
+ }
139
+
140
+ return defaults;
141
+ }
142
+
143
+ /**
144
+ * Scan first 4KB of a file for common secret patterns
145
+ * Returns a warning string if secrets detected, null otherwise
146
+ */
147
+ function scanContentForSecrets(filePath) {
148
+ try {
149
+ const fd = fs.openSync(filePath, 'r');
150
+ const buffer = Buffer.alloc(4096);
151
+ const bytesRead = fs.readSync(fd, buffer, 0, 4096, 0);
152
+ fs.closeSync(fd);
153
+
154
+ if (bytesRead === 0) return null;
155
+
156
+ const content = buffer.toString('utf-8', 0, bytesRead);
157
+
158
+ const secretPatterns = [
159
+ { pattern: /AKIA[0-9A-Z]{16}/, label: 'AWS access key' },
160
+ { pattern: /gh[ps]_[A-Za-z0-9_]{36,}/, label: 'GitHub token' },
161
+ { pattern: /sk_(live|test)_[0-9a-zA-Z]{24,}/, label: 'Stripe key' },
162
+ { pattern: /-----BEGIN .* PRIVATE KEY-----/, label: 'Private key' },
163
+ { pattern: /xox[bpors]-[0-9a-zA-Z-]{10,}/, label: 'Slack token' },
164
+ { pattern: /sk-[a-zA-Z0-9]{32,}/, label: 'OpenAI/API key' },
165
+ ];
166
+
167
+ for (const { pattern, label } of secretPatterns) {
168
+ if (pattern.test(content)) {
169
+ return `Found ${label} pattern in file content`;
170
+ }
171
+ }
172
+ } catch {
173
+ // Can't read file (doesn't exist yet, permissions, etc.) — skip silently
174
+ }
175
+
176
+ return null;
177
+ }
package/package.json CHANGED
@@ -1,63 +1,63 @@
1
- {
2
- "name": "@rune-kit/rune",
3
- "version": "2.4.0",
4
- "description": "60-skill mesh for AI coding assistants — 5-layer architecture, 200+ connections, 8 platforms (Claude Code, Cursor, Windsurf, Antigravity, Codex, OpenCode, OpenClaw, Generic)",
5
- "type": "module",
6
- "bin": {
7
- "rune": "./compiler/bin/rune.js"
8
- },
9
- "scripts": {
10
- "build": "node compiler/bin/rune.js build",
11
- "doctor": "node compiler/bin/rune.js doctor && node scripts/version-sync-check.js",
12
- "test": "node --test compiler/__tests__/*.test.js scripts/__tests__/*.test.js",
13
- "test:coverage": "c8 --reporter=text --reporter=lcov node --test compiler/__tests__/*.test.js scripts/__tests__/*.test.js",
14
- "lint": "biome check .",
15
- "lint:fix": "biome check --fix .",
16
- "format": "biome format --write .",
17
- "ci": "biome check . && node --test compiler/__tests__/*.test.js scripts/__tests__/*.test.js && node compiler/bin/rune.js doctor",
18
- "version-check": "node scripts/version-sync-check.js",
19
- "prepublishOnly": "node scripts/version-sync-check.js"
20
- },
21
- "keywords": [
22
- "claude-code",
23
- "cursor",
24
- "windsurf",
25
- "antigravity",
26
- "codex",
27
- "opencode",
28
- "openclaw",
29
- "ai-assistant",
30
- "ai-coding",
31
- "skills",
32
- "coding-agent",
33
- "tdd",
34
- "multi-platform"
35
- ],
36
- "author": "runedev",
37
- "license": "MIT",
38
- "repository": {
39
- "type": "git",
40
- "url": "https://github.com/rune-kit/rune"
41
- },
42
- "engines": {
43
- "node": ">=18"
44
- },
45
- "files": [
46
- "compiler/",
47
- "skills/",
48
- "extensions/",
49
- "contexts/",
50
- "commands/",
51
- "agents/",
52
- "hooks/",
53
- "references/"
54
- ],
55
- "homepage": "https://rune-kit.github.io/rune",
56
- "bugs": {
57
- "url": "https://github.com/rune-kit/rune/issues"
58
- },
59
- "devDependencies": {
60
- "@biomejs/biome": "^2.4.7",
61
- "c8": "^10.1.3"
62
- }
63
- }
1
+ {
2
+ "name": "@rune-kit/rune",
3
+ "version": "2.7.0",
4
+ "description": "61-skill mesh for AI coding assistants — 5-layer architecture, 200+ connections, 8 platforms (Claude Code, Cursor, Windsurf, Antigravity, Codex, OpenCode, OpenClaw, Generic)",
5
+ "type": "module",
6
+ "bin": {
7
+ "rune": "./compiler/bin/rune.js"
8
+ },
9
+ "scripts": {
10
+ "build": "node compiler/bin/rune.js build",
11
+ "doctor": "node compiler/bin/rune.js doctor && node scripts/version-sync-check.js",
12
+ "test": "node --test compiler/__tests__/*.test.js scripts/__tests__/*.test.js",
13
+ "test:coverage": "c8 --reporter=text --reporter=lcov node --test compiler/__tests__/*.test.js scripts/__tests__/*.test.js",
14
+ "lint": "biome check .",
15
+ "lint:fix": "biome check --fix .",
16
+ "format": "biome format --write .",
17
+ "ci": "biome check . && node --test compiler/__tests__/*.test.js scripts/__tests__/*.test.js && node compiler/bin/rune.js doctor",
18
+ "version-check": "node scripts/version-sync-check.js",
19
+ "prepublishOnly": "node scripts/version-sync-check.js"
20
+ },
21
+ "keywords": [
22
+ "claude-code",
23
+ "cursor",
24
+ "windsurf",
25
+ "antigravity",
26
+ "codex",
27
+ "opencode",
28
+ "openclaw",
29
+ "ai-assistant",
30
+ "ai-coding",
31
+ "skills",
32
+ "coding-agent",
33
+ "tdd",
34
+ "multi-platform"
35
+ ],
36
+ "author": "runedev",
37
+ "license": "MIT",
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/rune-kit/rune"
41
+ },
42
+ "engines": {
43
+ "node": ">=18"
44
+ },
45
+ "files": [
46
+ "compiler/",
47
+ "skills/",
48
+ "extensions/",
49
+ "contexts/",
50
+ "commands/",
51
+ "agents/",
52
+ "hooks/",
53
+ "references/"
54
+ ],
55
+ "homepage": "https://rune-kit.github.io/rune",
56
+ "bugs": {
57
+ "url": "https://github.com/rune-kit/rune/issues"
58
+ },
59
+ "devDependencies": {
60
+ "@biomejs/biome": "^2.4.7",
61
+ "c8": "^10.1.3"
62
+ }
63
+ }
@@ -3,7 +3,7 @@ name: autopsy
3
3
  description: Full codebase health assessment. Analyzes complexity, dependencies, dead code, tech debt, and git hotspots. Produces a health score and rescue plan.
4
4
  metadata:
5
5
  author: runedev
6
- version: "0.2.0"
6
+ version: "0.3.0"
7
7
  layer: L2
8
8
  model: opus
9
9
  group: rescue
@@ -210,3 +210,50 @@ Known failure modes for this skill. Check these before declaring done.
210
210
  ~5000-10000 tokens input, ~2000-4000 tokens output. Opus for deep analysis. Most expensive L2 skill but runs once per rescue.
211
211
 
212
212
  **Scope guardrail:** autopsy assesses — it does not refactor. All surgery is delegated to `surgeon` after the report is complete.
213
+
214
+ ## Executive Mode (--executive)
215
+
216
+ When invoked as `/rune autopsy --executive`, generate a board-ready HTML health assessment. Requires Business tier.
217
+
218
+ ### Executive Execution Steps
219
+
220
+ 1. **Standard Autopsy**: Run Steps 1-5 (structure scan, module analysis, health scoring, risk assessment, RESCUE-REPORT.md)
221
+ 2. **Org Context**: Read `.rune/org/org.md` for team structure and governance level
222
+ 3. **Cross-Domain Impact**: Map module health to business domains (which team owns which modules)
223
+ 4. **Business Risk Translation**: Convert technical health scores to business risk language:
224
+ - Critical modules in revenue path → "Revenue infrastructure at risk"
225
+ - Low test coverage on auth → "Security compliance gap"
226
+ - High churn in customer-facing code → "Customer experience degradation risk"
227
+ 5. **HTML Render**: Load `report-templates/autopsy-executive.html` from Business pack and populate all `{{placeholder}}` fields:
228
+ - SVG health ring (score → stroke-dasharray calculation: `score / 100 * 440`)
229
+ - Dimension bars (6 dimensions with color coding)
230
+ - Module table (sorted by priority)
231
+ - Surgery queue (top 5 modules)
232
+ - Risk matrix (6 categories)
233
+ - Git archaeology summary
234
+ - Cross-domain impact table
235
+ - Recommended actions (numbered, prioritized)
236
+ 6. **Save**: Write HTML to `EXECUTIVE-HEALTH.html` at project root
237
+
238
+ ### Executive Output
239
+
240
+ ```
241
+ EXECUTIVE-HEALTH.html — Board-ready HTML report
242
+ RESCUE-REPORT.md — Detailed technical report (standard autopsy)
243
+ .rune/retros/{date}.json — Health metrics for trend tracking
244
+ ```
245
+
246
+ ### Color Coding
247
+
248
+ | Score Range | Color | Tier |
249
+ |-------------|-------|------|
250
+ | 80-100 | var(--success) #10b981 | Healthy |
251
+ | 60-79 | var(--warning) #f59e0b | Watch |
252
+ | 40-59 | #f97316 (orange) | At-risk |
253
+ | 0-39 | var(--danger) #ef4444 | Critical |
254
+
255
+ ### Graceful Degradation
256
+
257
+ - If no Business pack installed: skip executive mode, produce standard RESCUE-REPORT.md only
258
+ - If `.rune/org/org.md` missing: skip team mapping, show modules without domain ownership
259
+ - If org teams don't map to code modules: show "Unmapped" in cross-domain table
@@ -8,6 +8,8 @@ metadata:
8
8
  model: opus
9
9
  group: creation
10
10
  tools: "Read, Glob, Grep"
11
+ emit: ideas.ready
12
+ listen: codebase.scanned
11
13
  ---
12
14
 
13
15
  # brainstorm
@@ -4,7 +4,7 @@ description: "Validates agent claims against evidence trail. Catches 'done' with
4
4
  user-invocable: false
5
5
  metadata:
6
6
  author: runedev
7
- version: "1.6.0"
7
+ version: "1.7.0"
8
8
  layer: L3
9
9
  model: haiku
10
10
  group: validation
@@ -210,6 +210,29 @@ Before emitting verdict, verify evidence quality:
210
210
  | Quote matches claim exactly | CONFIRMED |
211
211
  | Quote contradicts claim | CONTRADICTED |
212
212
 
213
+ ### Step 5.5 — Plan Diff Check
214
+
215
+ When validating a phase within a master plan, diff actual changes against the phase plan file:
216
+
217
+ 1. **Read the active phase plan** — `Glob` for `.rune/plan-*-phase*.md` matching the current phase
218
+ 2. **Extract `## Files Touched`** — build a list of expected files (new/modify/delete)
219
+ 3. **Extract `## Tasks`** — build a list of all `- [ ]` and `- [x]` items
220
+ 4. **Compare against actual changes** — `git diff --name-only` (or file system scan)
221
+ 5. **Report**:
222
+
223
+ | Check | Status |
224
+ |-------|--------|
225
+ | Unchecked task in phase plan (`- [ ]` still exists) | **INCOMPLETE** — task was not done |
226
+ | File in plan's "Files Touched" but not in actual diff | **MISSING** — planned file was never touched |
227
+ | File in actual diff but NOT in plan's "Files Touched" | **UNPLANNED** — scope creep (warn, not block) |
228
+ | All tasks `[x]` AND all planned files touched | **PLAN-ALIGNED** |
229
+
230
+ ```
231
+ Plan Diff: PLAN-ALIGNED | INCOMPLETE (2 unchecked tasks) | MISSING (1 file never touched)
232
+ ```
233
+
234
+ **Skip if**: No active phase plan found (single-task, no master plan). **MANDATORY** for multi-phase master plans.
235
+
213
236
  ## Verdict Rules
214
237
 
215
238
  ```
@@ -245,6 +268,7 @@ Completion Gate Report with status (CONFIRMED/UNCONFIRMED/CONTRADICTED), claim v
245
268
  | Rubber-stamping — all CONFIRMED without scrutiny | HIGH | Default-FAIL mindset: actively seek 3-5 issues. Zero issues = red flag, apply skeptic sweep on weakest 2 claims |
246
269
  | Partial completion claimed as full — 80% done but "implemented" | HIGH | Adversarial checklist: check for partial completion, scope mismatch, evidence-claim alignment |
247
270
  | Self-Validation skipped — skill has checks but gate ignores them | HIGH | Step 1c: extract Self-Validation from skill's SKILL.md, treat each as implicit claim. Missing = UNCONFIRMED |
271
+ | Plan says done but phase file has unchecked tasks | HIGH | Step 5.5: diff changed files vs phase plan's Files Touched + Tasks sections |
248
272
 
249
273
  ## Done When
250
274
 
@@ -252,6 +276,7 @@ Completion Gate Report with status (CONFIRMED/UNCONFIRMED/CONTRADICTED), claim v
252
276
  - Each claim matched against tool output evidence
253
277
  - Verdict table emitted with claim/evidence/verdict for each item
254
278
  - All 3 verification axes (Completeness/Correctness/Coherence) have at least one claim checked
279
+ - Plan diff check passed (if multi-phase): all tasks checked, all planned files touched
255
280
  - Overall verdict: CONFIRMED / UNCONFIRMED / CONTRADICTED
256
281
  - If not CONFIRMED: specific gaps listed with remediation steps
257
282