@rune-kit/rune 2.11.0 → 2.12.2
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/README.md +58 -1
- package/compiler/__tests__/detect-invariants.test.js +136 -0
- package/compiler/__tests__/doctor-mesh.test.js +229 -0
- package/compiler/__tests__/hook-dispatch.test.js +91 -0
- package/compiler/__tests__/hooks-antigravity.test.js +120 -0
- package/compiler/__tests__/hooks-cursor.test.js +141 -0
- package/compiler/__tests__/hooks-install.test.js +307 -0
- package/compiler/__tests__/hooks-merge.test.js +204 -0
- package/compiler/__tests__/hooks-tiers.test.js +620 -0
- package/compiler/__tests__/hooks-windsurf.test.js +117 -0
- package/compiler/__tests__/inject-claude-md.test.js +152 -0
- package/compiler/__tests__/load-invariants.test.js +408 -0
- package/compiler/__tests__/onboard-invariants.test.js +240 -0
- package/compiler/adapters/hooks/antigravity.js +140 -0
- package/compiler/adapters/hooks/claude.js +166 -0
- package/compiler/adapters/hooks/cursor.js +191 -0
- package/compiler/adapters/hooks/index.js +82 -0
- package/compiler/adapters/hooks/tier-emitter.js +182 -0
- package/compiler/adapters/hooks/windsurf.js +202 -0
- package/compiler/bin/rune.js +196 -6
- package/compiler/commands/hook-dispatch.js +87 -0
- package/compiler/commands/hooks/install.js +120 -0
- package/compiler/commands/hooks/merge.js +211 -0
- package/compiler/commands/hooks/presets.js +116 -0
- package/compiler/commands/hooks/status.js +112 -0
- package/compiler/commands/hooks/tiers.js +323 -0
- package/compiler/commands/hooks/uninstall.js +94 -0
- package/compiler/doctor.js +236 -0
- package/package.json +2 -2
- package/skills/ba/SKILL.md +85 -1
- package/skills/brainstorm/SKILL.md +39 -1
- package/skills/browser-pilot/SKILL.md +1 -0
- package/skills/context-engine/SKILL.md +6 -2
- package/skills/design/SKILL.md +1 -0
- package/skills/docs-seeker/SKILL.md +1 -0
- package/skills/fix/SKILL.md +4 -2
- package/skills/hallucination-guard/SKILL.md +1 -0
- package/skills/journal/SKILL.md +1 -0
- package/skills/logic-guardian/SKILL.md +22 -4
- package/skills/marketing/SKILL.md +62 -1
- package/skills/neural-memory/SKILL.md +13 -16
- package/skills/onboard/SKILL.md +30 -2
- package/skills/onboard/references/invariants-template.md +76 -0
- package/skills/onboard/scripts/detect-invariants.js +439 -0
- package/skills/onboard/scripts/inject-claude-md.js +150 -0
- package/skills/onboard/scripts/onboard-invariants.js +196 -0
- package/skills/perf/SKILL.md +1 -0
- package/skills/plan/SKILL.md +2 -0
- package/skills/preflight/SKILL.md +1 -1
- package/skills/research/SKILL.md +4 -0
- package/skills/review/SKILL.md +4 -2
- package/skills/scope-guard/SKILL.md +4 -1
- package/skills/scout/SKILL.md +6 -0
- package/skills/sentinel/SKILL.md +2 -0
- package/skills/session-bridge/SKILL.md +53 -1
- package/skills/session-bridge/scripts/load-invariants.js +397 -0
- package/skills/slides/SKILL.md +19 -0
- package/skills/team/SKILL.md +2 -1
- package/skills/test/SKILL.md +6 -0
- package/skills/verification/SKILL.md +8 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* onboard-invariants.js — Orchestrate invariant detection, INVARIANTS.md
|
|
5
|
+
* generation (merge-preserving), and CLAUDE.md pointer injection.
|
|
6
|
+
*
|
|
7
|
+
* Writes/updates:
|
|
8
|
+
* - .rune/INVARIANTS.md (seeded from template, append-only on re-run)
|
|
9
|
+
* - CLAUDE.md (pointer block between markers)
|
|
10
|
+
*
|
|
11
|
+
* Safe re-runs:
|
|
12
|
+
* - Existing user sections above the auto-detected block are preserved.
|
|
13
|
+
* - New detections land under `## Auto-detected (new)` — never overwrite.
|
|
14
|
+
*
|
|
15
|
+
* Usage as CLI:
|
|
16
|
+
* node onboard-invariants.js --root <project-root> [--dry]
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { existsSync } from 'node:fs';
|
|
20
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
21
|
+
import path from 'node:path';
|
|
22
|
+
import { fileURLToPath } from 'node:url';
|
|
23
|
+
import { parseArgs } from 'node:util';
|
|
24
|
+
import { detectInvariants, renderInvariants } from './detect-invariants.js';
|
|
25
|
+
import { applyInvariantsPointer } from './inject-claude-md.js';
|
|
26
|
+
|
|
27
|
+
const AUTO_HEADER = '## Auto-detected (new)';
|
|
28
|
+
const TEMPLATE_REL_PATH = '../references/invariants-template.md';
|
|
29
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Locate the next `## `-level section boundary in `text`, ignoring any `##`
|
|
33
|
+
* lines that appear inside fenced code blocks (``` or ~~~).
|
|
34
|
+
* Returns the index of the start of the boundary line, or -1 if none.
|
|
35
|
+
*/
|
|
36
|
+
function findNextSectionOffset(text) {
|
|
37
|
+
let offset = 0;
|
|
38
|
+
let inFence = false;
|
|
39
|
+
let fenceDelim = null;
|
|
40
|
+
while (offset < text.length) {
|
|
41
|
+
const eol = text.indexOf('\n', offset);
|
|
42
|
+
const lineEnd = eol === -1 ? text.length : eol;
|
|
43
|
+
const line = text.slice(offset, lineEnd);
|
|
44
|
+
const trimmed = line.trimStart();
|
|
45
|
+
if (inFence) {
|
|
46
|
+
if (trimmed.startsWith(fenceDelim)) {
|
|
47
|
+
inFence = false;
|
|
48
|
+
fenceDelim = null;
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
if (trimmed.startsWith('```') || trimmed.startsWith('~~~')) {
|
|
52
|
+
inFence = true;
|
|
53
|
+
fenceDelim = trimmed.startsWith('```') ? '```' : '~~~';
|
|
54
|
+
} else if (line.startsWith('## ') && !line.startsWith(AUTO_HEADER)) {
|
|
55
|
+
return offset;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (eol === -1) break;
|
|
59
|
+
offset = eol + 1;
|
|
60
|
+
}
|
|
61
|
+
return -1;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function loadTemplate(templatePath) {
|
|
65
|
+
const resolved = templatePath ?? path.resolve(__dirname, TEMPLATE_REL_PATH);
|
|
66
|
+
return readFile(resolved, 'utf8');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function mergeInvariantsContent({ existing, autoDetected, template }) {
|
|
70
|
+
const freshBody = renderAutoDetectedBlock(autoDetected);
|
|
71
|
+
|
|
72
|
+
if (!existing || existing.trim().length === 0) {
|
|
73
|
+
return replaceAutoBlock(template, freshBody, { seeded: true });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!existing.includes(AUTO_HEADER)) {
|
|
77
|
+
const trailing = existing.endsWith('\n') ? '' : '\n';
|
|
78
|
+
const appended = `${existing}${trailing}\n---\n\n${AUTO_HEADER}\n\n${freshBody}\n`;
|
|
79
|
+
return { content: appended, seeded: false, replaced: false, appended: true };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return replaceAutoBlock(existing, freshBody, { seeded: false });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function replaceAutoBlock(source, freshBody, { seeded }) {
|
|
86
|
+
const headerIdx = source.indexOf(AUTO_HEADER);
|
|
87
|
+
if (headerIdx === -1) {
|
|
88
|
+
const trailing = source.endsWith('\n') ? '' : '\n';
|
|
89
|
+
return {
|
|
90
|
+
content: `${source}${trailing}\n${AUTO_HEADER}\n\n${freshBody}\n`,
|
|
91
|
+
seeded,
|
|
92
|
+
replaced: false,
|
|
93
|
+
appended: true,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const afterHeader = source.slice(headerIdx + AUTO_HEADER.length);
|
|
98
|
+
const nextOffsetRaw = findNextSectionOffset(afterHeader);
|
|
99
|
+
const nextOffset = nextOffsetRaw === -1 ? afterHeader.length : nextOffsetRaw;
|
|
100
|
+
|
|
101
|
+
const before = source.slice(0, headerIdx);
|
|
102
|
+
const after = afterHeader.slice(nextOffset);
|
|
103
|
+
const replaced = `${before}${AUTO_HEADER}\n\n${freshBody}\n\n${after.replace(/^\n+/, '')}`;
|
|
104
|
+
|
|
105
|
+
return { content: replaced, seeded, replaced: true, appended: false };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function renderAutoDetectedBlock(result) {
|
|
109
|
+
const total =
|
|
110
|
+
(result?.danger?.length ?? 0) +
|
|
111
|
+
(result?.critical?.length ?? 0) +
|
|
112
|
+
(result?.state?.length ?? 0) +
|
|
113
|
+
(result?.cross?.length ?? 0);
|
|
114
|
+
if (total === 0) return '_No new detections on this run._';
|
|
115
|
+
return renderInvariants(result).trimEnd();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function collectPointerGlobs(result, limit = 8) {
|
|
119
|
+
const danger = (result?.danger ?? []).map((e) => firstWhere(e)).filter(Boolean);
|
|
120
|
+
const critical = (result?.critical ?? []).map((e) => firstWhere(e)).filter(Boolean);
|
|
121
|
+
return Array.from(new Set([...danger, ...critical])).slice(0, limit);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function firstWhere(entry) {
|
|
125
|
+
if (!entry) return null;
|
|
126
|
+
if (Array.isArray(entry.where)) return entry.where[0] ?? null;
|
|
127
|
+
return entry.where ?? null;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export async function runOnboardInvariants({ root, dryRun = false, templatePath } = {}) {
|
|
131
|
+
if (!root) throw new Error('root is required');
|
|
132
|
+
|
|
133
|
+
const runeDir = path.join(root, '.rune');
|
|
134
|
+
const invariantsPath = path.join(runeDir, 'INVARIANTS.md');
|
|
135
|
+
const claudeMdPath = path.join(root, 'CLAUDE.md');
|
|
136
|
+
|
|
137
|
+
const result = await detectInvariants({ root });
|
|
138
|
+
const rendered = renderInvariants(result);
|
|
139
|
+
const template = await loadTemplate(templatePath);
|
|
140
|
+
|
|
141
|
+
const existing = existsSync(invariantsPath) ? await readFile(invariantsPath, 'utf8') : '';
|
|
142
|
+
const merged = mergeInvariantsContent({ existing, autoDetected: result, template });
|
|
143
|
+
|
|
144
|
+
if (!dryRun) {
|
|
145
|
+
await mkdir(runeDir, { recursive: true });
|
|
146
|
+
await writeFile(invariantsPath, merged.content, 'utf8');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const globs = collectPointerGlobs(result);
|
|
150
|
+
const pointer = await applyInvariantsPointer({
|
|
151
|
+
claudeMdPath,
|
|
152
|
+
globs,
|
|
153
|
+
invariantsPath: path.relative(root, invariantsPath).replaceAll('\\', '/'),
|
|
154
|
+
dryRun,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
invariants: {
|
|
159
|
+
path: invariantsPath,
|
|
160
|
+
action: merged.seeded ? 'seeded' : merged.replaced ? 'replaced' : merged.appended ? 'appended' : 'noop',
|
|
161
|
+
stats: result.stats ?? null,
|
|
162
|
+
detected: {
|
|
163
|
+
danger: result.danger?.length ?? 0,
|
|
164
|
+
critical: result.critical?.length ?? 0,
|
|
165
|
+
state: result.state?.length ?? 0,
|
|
166
|
+
cross: result.cross?.length ?? 0,
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
claudeMd: {
|
|
170
|
+
path: pointer.path,
|
|
171
|
+
action: pointer.action,
|
|
172
|
+
reason: pointer.reason ?? null,
|
|
173
|
+
},
|
|
174
|
+
rendered,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async function main() {
|
|
179
|
+
const { values } = parseArgs({
|
|
180
|
+
options: {
|
|
181
|
+
root: { type: 'string' },
|
|
182
|
+
dry: { type: 'boolean', default: false },
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const root = values.root ?? process.cwd();
|
|
187
|
+
const result = await runOnboardInvariants({ root, dryRun: values.dry });
|
|
188
|
+
console.log(JSON.stringify(result, null, 2));
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith('onboard-invariants.js')) {
|
|
192
|
+
main().catch((err) => {
|
|
193
|
+
console.error(err.message);
|
|
194
|
+
process.exit(1);
|
|
195
|
+
});
|
|
196
|
+
}
|
package/skills/perf/SKILL.md
CHANGED
|
@@ -37,6 +37,7 @@ Performance regression gate. Analyzes code changes for patterns that cause measu
|
|
|
37
37
|
- `audit` (L2): performance dimension delegation
|
|
38
38
|
- `review` (L2): performance patterns detected in diff
|
|
39
39
|
- `deploy` (L2): pre-deploy perf regression check
|
|
40
|
+
- `adversary` (L2): scalability stress test when bottleneck patterns detected in plan
|
|
40
41
|
|
|
41
42
|
## References
|
|
42
43
|
|
package/skills/plan/SKILL.md
CHANGED
|
@@ -97,6 +97,8 @@ High-level multi-feature planning — organize features into milestones.
|
|
|
97
97
|
- `scaffold` (L1): Phase 3 architecture planning
|
|
98
98
|
- `skill-forge` (L2): plan structure for new skill
|
|
99
99
|
- User: `/rune plan` direct invocation
|
|
100
|
+
- `debug` (L2): when root cause requires architectural changes
|
|
101
|
+
- `retro` (L2): reference past plans during retrospective analysis
|
|
100
102
|
|
|
101
103
|
## Data Flow
|
|
102
104
|
|
|
@@ -3,7 +3,7 @@ name: preflight
|
|
|
3
3
|
description: Pre-commit quality gate that catches "almost right" code. Goes beyond linting — checks logic correctness, error handling, regressions, and completeness.
|
|
4
4
|
metadata:
|
|
5
5
|
author: runedev
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "1.0.0"
|
|
7
7
|
layer: L2
|
|
8
8
|
model: sonnet
|
|
9
9
|
group: quality
|
package/skills/research/SKILL.md
CHANGED
|
@@ -27,6 +27,10 @@ None — pure L3 utility using `WebSearch` and `WebFetch` tools directly.
|
|
|
27
27
|
- `marketing` (L2): competitor analysis, SEO data
|
|
28
28
|
- `hallucination-guard` (L3): verify package existence on npm/pypi
|
|
29
29
|
- `autopsy` (L2): research best practices for legacy patterns
|
|
30
|
+
- `ba` (L2): research similar products and integrations
|
|
31
|
+
- `graft` (L2): research source repo patterns before grafting
|
|
32
|
+
- `mcp-builder` (L2): research MCP standards and existing implementations
|
|
33
|
+
- `scaffold` (L1): research project templates and best practices
|
|
30
34
|
|
|
31
35
|
## Execution
|
|
32
36
|
|
package/skills/review/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: review
|
|
|
3
3
|
description: Code quality review — patterns, security, performance, correctness. Finds bugs, suggests improvements, triggers fix for issues found. Escalates to opus for security-critical code.
|
|
4
4
|
metadata:
|
|
5
5
|
author: runedev
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "1.0.0"
|
|
7
7
|
layer: L2
|
|
8
8
|
model: sonnet
|
|
9
9
|
group: development
|
|
@@ -52,6 +52,8 @@ Every review MUST cite at least one specific concern, suggestion, or explicit ap
|
|
|
52
52
|
- User: `/rune review` direct invocation
|
|
53
53
|
- `surgeon` (L2): review refactored code quality
|
|
54
54
|
- `rescue` (L1): review refactored code quality
|
|
55
|
+
- `design` (L2): review UI/design implementation quality
|
|
56
|
+
- `graft` (L2): review grafted code integration
|
|
55
57
|
|
|
56
58
|
## Cross-Hub Connections
|
|
57
59
|
|
|
@@ -564,7 +566,7 @@ Append to Code Review Report when invoked standalone. Suppress when called as su
|
|
|
564
566
|
```yaml
|
|
565
567
|
chain_metadata:
|
|
566
568
|
skill: "rune:review"
|
|
567
|
-
version: "0.
|
|
569
|
+
version: "1.0.0"
|
|
568
570
|
status: "[DONE | DONE_WITH_CONCERNS]"
|
|
569
571
|
domain: "[area reviewed]"
|
|
570
572
|
files_changed: [] # review doesn't change files
|
|
@@ -19,7 +19,10 @@ Passive scope monitor. Reads the original task plan, inspects current git diff t
|
|
|
19
19
|
|
|
20
20
|
## Called By (inbound)
|
|
21
21
|
|
|
22
|
-
-
|
|
22
|
+
- `cook` (L1): Phase 6.6 scope drift detection when files touched > planned
|
|
23
|
+
- `team` (L1): after each parallel workstream completes, before merge
|
|
24
|
+
- `rescue` (L1): during safeguard phase to detect unplanned changes
|
|
25
|
+
- `plan` (L2): optional scope validation after plan acceptance
|
|
23
26
|
|
|
24
27
|
## Calls (outbound)
|
|
25
28
|
|
package/skills/scout/SKILL.md
CHANGED
|
@@ -198,6 +198,12 @@ None — pure scanner using Glob, Grep, Read, and Bash tools directly. Does not
|
|
|
198
198
|
- `perf` (L2): find hotpath files and performance-critical code
|
|
199
199
|
- `review-intake` (L2): scan codebase for review context
|
|
200
200
|
- `skill-forge` (L2): scan existing skills for patterns when creating new skills
|
|
201
|
+
- `ba` (L2): scan existing codebase for context before requirements elicitation
|
|
202
|
+
- `retro` (L2): scan commit history and codebase for retrospective analysis
|
|
203
|
+
- `graft` (L2): scan target codebase before grafting code from external repo
|
|
204
|
+
- `docs` (L2): scan codebase structure for documentation generation
|
|
205
|
+
- `logic-guardian` (L2): scan business logic modules for protection mapping
|
|
206
|
+
- `adversary` (L2): scan codebase before red-team analysis
|
|
201
207
|
|
|
202
208
|
## Output Format
|
|
203
209
|
|
package/skills/sentinel/SKILL.md
CHANGED
|
@@ -47,6 +47,8 @@ If status is BLOCK, output the report and STOP. Do not hand off to commit. The c
|
|
|
47
47
|
- `audit` (L2): Phase 2 full security audit
|
|
48
48
|
- `incident` (L2): security dimension check during incident response
|
|
49
49
|
- `review-intake` (L2): security scan on code submitted for structured review
|
|
50
|
+
- `adversary` (L2): deep security analysis when attack vectors identified in plan
|
|
51
|
+
- `scaffold` (L1): security baseline for new projects
|
|
50
52
|
|
|
51
53
|
## Severity Levels
|
|
52
54
|
|
|
@@ -3,12 +3,13 @@ name: session-bridge
|
|
|
3
3
|
description: Universal context persistence across sessions. Auto-saves decisions, conventions, and progress to .rune/ files. Loads state at session start. Use when any skill makes architectural decisions or establishes patterns that must survive session boundaries.
|
|
4
4
|
metadata:
|
|
5
5
|
author: runedev
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.7.0"
|
|
7
7
|
layer: L3
|
|
8
8
|
model: haiku
|
|
9
9
|
group: state
|
|
10
10
|
tools: "Read, Write, Edit, Glob, Grep"
|
|
11
11
|
listen: phase.complete, checkpoint.request
|
|
12
|
+
emit: invariants.loaded
|
|
12
13
|
---
|
|
13
14
|
|
|
14
15
|
# session-bridge
|
|
@@ -37,6 +38,8 @@ Solve the #1 developer complaint: context loss across sessions. Session-bridge a
|
|
|
37
38
|
- `cook` (L1): auto-save decisions during feature implementation
|
|
38
39
|
- `rescue` (L1): state management throughout refactoring
|
|
39
40
|
- `context-engine` (L3): save state before compaction
|
|
41
|
+
- `context-pack` (L3): coordinate state for sub-agent handoff
|
|
42
|
+
- `neural-memory` (L3): sync key decisions back to `.rune/` files after Capture Mode
|
|
40
43
|
|
|
41
44
|
## State Files Managed
|
|
42
45
|
|
|
@@ -354,6 +357,54 @@ Handle results:
|
|
|
354
357
|
- `SUSPICIOUS` → present warning to user with specific findings. Ask: "Suspicious patterns detected in .rune/ files. Load anyway?" If user approves → proceed. If not → exit load mode.
|
|
355
358
|
- `TAINTED` → **BLOCK load**. Report: ".rune/ integrity check FAILED — possible poisoning detected. Run `/rune integrity` for details."
|
|
356
359
|
|
|
360
|
+
#### Step 1.7 — Load invariants (auto-discipline)
|
|
361
|
+
|
|
362
|
+
Before loading the usual state files, run the invariants loader so the agent sees active discipline rules without being told to look:
|
|
363
|
+
|
|
364
|
+
```
|
|
365
|
+
Execute: node skills/session-bridge/scripts/load-invariants.js --root <project-root> --json
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
The loader:
|
|
369
|
+
- Reads `.rune/INVARIANTS.md` (silent no-op if missing)
|
|
370
|
+
- Strips the `## Archived` section (retired rules don't re-activate)
|
|
371
|
+
- Parses active rules into `{ section, title, what, where, why }`
|
|
372
|
+
- Returns a token-budgeted preview (≤ 500 tokens by default)
|
|
373
|
+
- Flags staleness when mtime > 30 days
|
|
374
|
+
|
|
375
|
+
**Emit signal**: `invariants.loaded` with payload `{ loaded, count, rules, stats, stale, overflow, path }` where:
|
|
376
|
+
- `loaded` (boolean) — whether any active rules were parsed
|
|
377
|
+
- `count` (number) — total active rules (convenience alias for `stats.total`)
|
|
378
|
+
- `rules` (array) — full rule objects `[{ section, title, what, where: string[], why }]` — consumers cache these for glob matching
|
|
379
|
+
- `stats` — `{ danger, critical, state, cross, total, archivedSkipped }`
|
|
380
|
+
- `stale` (boolean) — mtime > 30 days
|
|
381
|
+
- `overflow` (number) — rules present but not shown in preview (budget overflow)
|
|
382
|
+
- `path` (string) — absolute path to `.rune/INVARIANTS.md`
|
|
383
|
+
|
|
384
|
+
Downstream listeners (`logic-guardian`, Pro `autopilot`) consume `rules[]` directly — no second file read needed.
|
|
385
|
+
|
|
386
|
+
**Present to agent** (injected verbatim into the Load Mode summary):
|
|
387
|
+
|
|
388
|
+
```
|
|
389
|
+
📎 Active Invariants (.rune/INVARIANTS.md)
|
|
390
|
+
⚠ skills/skill-router/** — L0 router, never bypass
|
|
391
|
+
🔒 compiler/parser.js — IR schema is the adapter contract
|
|
392
|
+
🔁 compiler/hooks/dispatch.js — phase order is pre → run → post
|
|
393
|
+
🔗 .claude-plugin/marketplace.json — mirrors plugin.json
|
|
394
|
+
…+2 more rules in .rune/INVARIANTS.md
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
**Staleness warning** (emit ONCE per session, not per tool call):
|
|
398
|
+
|
|
399
|
+
```
|
|
400
|
+
⚠ Invariants file is stale (> 30 days since last onboard). Consider `rune onboard --refresh`.
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
**Failure modes**:
|
|
404
|
+
- Missing file → silent no-op (no preview, no error). Don't nag fresh repos.
|
|
405
|
+
- Malformed file → `loaded: false, rules: []`. Log a single-line warning, continue.
|
|
406
|
+
- File fails `integrity-check` in Step 1.5 → this step is skipped entirely (load already blocked).
|
|
407
|
+
|
|
357
408
|
#### Step 2 — Load files
|
|
358
409
|
|
|
359
410
|
Use `Read` on all four state files in parallel:
|
|
@@ -474,6 +525,7 @@ At Load Mode Step 1, after checking `.rune/*.md` existence, also check for `.run
|
|
|
474
525
|
## Session Bridge — Loaded
|
|
475
526
|
- **Last session**: [date and summary]
|
|
476
527
|
- **Checkpoint**: [detected — resume point] | [none]
|
|
528
|
+
- **Invariants**: [N loaded from .rune/INVARIANTS.md] | [none] | [stale — run rune onboard --refresh]
|
|
477
529
|
- **Decisions on file**: [count]
|
|
478
530
|
- **Conventions on file**: [count]
|
|
479
531
|
- **Learnings on file**: [count] (top 5 surfaced if 10+)
|