kibi-opencode 0.5.4 → 0.6.1

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/dist/path-kind.js CHANGED
@@ -14,7 +14,7 @@ const KIBI_DOC_PATTERNS = [
14
14
  ];
15
15
  export function analyzePath(
16
16
  // implements REQ-opencode-kibi-plugin-v1
17
- filePath, cwd) {
17
+ filePath, cwd = process.cwd()) {
18
18
  const rel = path.isAbsolute(filePath)
19
19
  ? path.relative(cwd, filePath).split(path.sep).join("/")
20
20
  : filePath.split(path.sep).join("/");
@@ -46,15 +46,23 @@ filePath, cwd) {
46
46
  else if (patternPrefix.includes("facts"))
47
47
  kind = "fact";
48
48
  else if (patternPrefix.includes("events"))
49
- kind = "fact"; // events map to fact for routing
49
+ kind = "event";
50
50
  else if (patternPrefix.includes("flags"))
51
- kind = "fact"; // flags map to fact for routing
51
+ kind = "flag";
52
52
  else if (patternPrefix.includes("symbols"))
53
- kind = "fact";
53
+ kind = "symbol";
54
54
  }
55
55
  break;
56
56
  }
57
57
  }
58
+ if (kind === "unknown") {
59
+ const isTestPath = normalized.includes("/__tests__/") ||
60
+ normalized.startsWith("tests/") ||
61
+ /(?:^|\/)[^/]+\.(test|spec)\.[^.]+$/i.test(normalized);
62
+ if (isTestPath) {
63
+ kind = "test";
64
+ }
65
+ }
58
66
  // Check for code files
59
67
  if (kind === "unknown") {
60
68
  const ext = path.extname(rel).toLowerCase();
package/dist/prompt.d.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  import type { CommentAnalysisResult } from "./comment-analysis.js";
2
2
  import type { KibiConfig } from "./config.js";
3
+ import type { GuidanceCache } from "./guidance-cache.js";
3
4
  import type { PathKind } from "./path-kind.js";
5
+ import type { RepoPosture } from "./repo-posture.js";
6
+ import type { RiskClass } from "./risk-classifier.js";
4
7
  import type { WorkspaceHealth } from "./workspace-health.js";
5
8
  declare const SENTINEL = "<!-- kibi-opencode -->";
6
9
  export interface PromptContext {
@@ -11,9 +14,27 @@ export interface PromptContext {
11
14
  workspaceHealth?: WorkspaceHealth;
12
15
  hasRecentKbEdit?: boolean;
13
16
  recentCommentSuggestion?: CommentAnalysisResult | null;
17
+ /** Posture detected by repo-posture detection */
18
+ posture?: RepoPosture;
19
+ /** Risk class from risk-classifier */
20
+ riskClass?: RiskClass;
21
+ /** Cache instance for skip-repeated-guidance */
22
+ cache?: GuidanceCache;
23
+ /** Workspace root for cache key */
24
+ workspaceRoot?: string;
25
+ /** Branch for cache key */
26
+ branch?: string;
27
+ /** Whether to append completion reminder for risky classes */
28
+ completionReminder?: boolean;
29
+ /** Merged maintenance-degraded state (static + runtime overlay) */
30
+ maintenanceDegraded?: boolean;
31
+ /** Degraded-mode logging policy */
32
+ degradedMode?: "warn-once" | "structured-only";
33
+ /** Whether to show the degraded advisory block this invocation */
34
+ showDegradedAdvisory?: boolean;
14
35
  }
15
36
  /**
16
- * Build prompt with contextual guidance based on recent edits and workspace state.
37
+ * Build prompt with contextual guidance based on posture, risk class, and cache state.
17
38
  */
18
39
  export declare function buildPrompt(context?: PromptContext): string;
19
40
  /**
package/dist/prompt.js CHANGED
@@ -1,163 +1,339 @@
1
+ import * as path from "node:path";
1
2
  import { isPluginEnabled } from "./config.js";
3
+ import { getSourceLinkedRequirementIds } from "./source-linked-guidance.js";
2
4
  const SENTINEL = "<!-- kibi-opencode -->";
3
- /**
4
- * Build prompt guidance block based on path kind.
5
- */
6
- // implements REQ-opencode-kibi-plugin-v1, REQ-opencode-agent-mcp-only
7
- function buildContextualGuidance(context) {
8
- const parts = [SENTINEL];
9
- if (context.hasRecentKbEdit) {
10
- parts.push(`
11
- ⚠️ **WARNING: Do not edit .kb/** files manually.**
5
+ // ── Token budget enforcement ───────────────────────────────────────────
6
+ const MAX_BULLETS = 5;
7
+ const MAX_WORDS = 117; // Reserve 3 words for sentinel so total injected prompt stays ≤ 120
8
+ function countWords(text) {
9
+ return text.split(/\s+/).filter(Boolean).length;
10
+ }
11
+ function countBullets(lines) {
12
+ return lines.filter((l) => l.startsWith("-")).length;
13
+ }
14
+ function enforceBudget(block) {
15
+ const lines = block.split("\n");
16
+ if (countBullets(lines) > MAX_BULLETS || countWords(block) > MAX_WORDS) {
17
+ // Trim to budget: keep header + first MAX_BULLETS bullet lines
18
+ const header = [];
19
+ const bullets = [];
20
+ for (const line of lines) {
21
+ if (line.startsWith("-") && bullets.length < MAX_BULLETS) {
22
+ bullets.push(line);
23
+ }
24
+ else if (!line.startsWith("-")) {
25
+ if (bullets.length === 0)
26
+ header.push(line);
27
+ }
28
+ }
29
+ const trimmed = [...header, ...bullets].join("\n");
30
+ if (countWords(trimmed) <= MAX_WORDS)
31
+ return trimmed;
32
+ // Hard truncate to MAX_WORDS
33
+ const words = trimmed.split(/\s+/).slice(0, MAX_WORDS);
34
+ return words.join(" ");
35
+ }
36
+ return block;
37
+ }
38
+ // ── File bucket derivation ─────────────────────────────────────────────
39
+ function deriveFileBucket(pathKind) {
40
+ return pathKind;
41
+ }
42
+ // ── Guidance blocks by risk class ──────────────────────────────────────
43
+ const GUIDANCE_BY_RISK = {
44
+ safe_docs_only: null,
45
+ safe_test_only: null,
46
+ kb_doc_structural: `📚 **Kibi documentation changes detected**
47
+
48
+ When editing KB documentation:
49
+ - Maintain traceability — link entities using relationships: specified_by, verified_by, etc.
50
+ - Validate — Use kb_check after making changes to catch integrity issues.
51
+ - Follow entity patterns — ensure each entity has proper frontmatter.`,
52
+ req_policy_candidate: `📋 **Requirement changes detected**
53
+
54
+ Requirement edits need policy alignment. Run kb_check with required-fields and no-dangling-refs. For priority:must requirements, also run must-priority-coverage.
55
+ - Keep artifacts separate (REQ, SCEN, TEST)
56
+ - Add verification: create or update linked SCEN and TEST entities`,
57
+ behavior_candidate: `📝 **Code changes detected**
58
+
59
+ Code changes need traceability. Use kb_search for context. For test/e2e symbols, prefer durable relationships (e.g. via symbols.yaml with covered_by + validates/verified_by); inline // implements REQ-xxx comments remain optional and backward-compatible.`,
60
+ traceability_candidate: `📝 **Code changes detected**
12
61
 
13
- The Kibi knowledge base is managed through public MCP tools and internal maintenance flows. Direct manual edits to files under .kb/** can cause inconsistencies and should be avoided.
62
+ Code changes need traceability. Use kb_search for context. For test/e2e symbols, prefer durable relationships (e.g. via symbols.yaml with covered_by + validates/verified_by); inline // implements REQ-xxx comments remain optional and backward-compatible.
63
+ - Durable knowledge comment detected — route to KB instead of inline comments
64
+ - Use kb_upsert for FACT, ADR, or REQ entities as appropriate`,
65
+ manual_kb_edit: `⚠️ **WARNING: Direct .kb/ edits bypass validation**
14
66
 
15
- Instead:
16
- - Use kb_search to discover relevant entities
67
+ The Kibi knowledge base is managed through public MCP tools. Direct manual edits to .kb/** can cause inconsistencies.
17
68
  - Use kb_upsert to create/update entities
18
- - Use kb_query for exact lookup and source-linked follow-up
19
- - Use kb_check to validate consistency
20
- `);
69
+ - Use kb_delete to remove entities
70
+ - Use kb_check to validate consistency`,
71
+ };
72
+ // ── Posture overrides ──────────────────────────────────────────────────
73
+ function postureGuidance(posture) {
74
+ switch (posture) {
75
+ case "vendored_only":
76
+ // Minimal guidance only, no bootstrap nags
77
+ return null;
78
+ case "root_uninitialized":
79
+ return `🔧 **Bootstrap required**
80
+
81
+ This repository does not appear to have Kibi initialized. Agents should:
82
+ - Use \`/init-kibi\` for retroactive bootstrap of existing repos (preferred MCP command)
83
+ - Ask the user/operator to run setup or repair outside this session if \`/init-kibi\` is insufficient
84
+
85
+ Do not run \`kibi\` CLI commands directly; use the public MCP tools (kb_search, kb_query, kb_status, kb_find_gaps, kb_coverage, kb_graph, kb_upsert, kb_delete, kb_check).`;
86
+ case "root_partial":
87
+ return `⚠️ **Partial KB setup detected**
88
+
89
+ Root .kb/config.json exists but some configured KB targets are missing. Guidance remains advisory until the user/operator restores the configured KB targets.`;
90
+ default:
91
+ return null;
92
+ }
93
+ }
94
+ // ── Main guidance builder ──────────────────────────────────────────────
95
+ /**
96
+ * Build prompt guidance block based on posture, risk class, and cache state.
97
+ */
98
+ function buildContextualGuidance(context) {
99
+ const posture = context.posture ?? "root_active";
100
+ const riskClass = context.riskClass;
101
+ const showDegraded = context.showDegradedAdvisory === true &&
102
+ context.maintenanceDegraded === true &&
103
+ context.degradedMode === "warn-once";
104
+ // ── Single-block priority selection ──
105
+ // Priority order (highest wins): manual_kb_edit > posture > risk_class > safe/none
106
+ let selectedBlock = null;
107
+ // Priority 1: vendored_only → sentinel only (unless degraded advisory forced)
108
+ if (posture === "vendored_only" && !showDegraded) {
109
+ return SENTINEL;
110
+ }
111
+ // Priority 2: manual_kb_edit — always fires, never cache-suppressed
112
+ if (context.hasRecentKbEdit || riskClass === "manual_kb_edit") {
113
+ selectedBlock = GUIDANCE_BY_RISK.manual_kb_edit;
21
114
  }
22
- if (context.workspaceHealth?.needsBootstrap) {
23
- parts.push(`
24
- 🔧 **Bootstrap required**
115
+ // Priority 3: Posture warnings for non-active states — not cache-suppressed
116
+ else if (posture === "root_uninitialized" || posture === "root_partial") {
117
+ const postureBlock = postureGuidance(posture);
118
+ if (postureBlock)
119
+ selectedBlock = postureBlock;
120
+ }
121
+ // Priority 4: Legacy workspace health bootstrap (only when no posture) — not cache-suppressed
122
+ else if (!context.posture && context.workspaceHealth?.needsBootstrap) {
123
+ selectedBlock = `🔧 **Bootstrap required**
25
124
 
26
125
  This repository does not appear to have Kibi initialized. Agents should:
27
126
  - Use \`/init-kibi\` for retroactive bootstrap of existing repos (preferred MCP command)
28
127
  - Ask the user/operator to run setup or repair outside this session if \`/init-kibi\` is insufficient
29
128
 
30
- Do not run \`kibi\` CLI commands directly; use the public MCP tools (kb_search, kb_query, kb_status, kb_find_gaps, kb_coverage, kb_graph, kb_upsert, kb_delete, kb_check).
31
- `);
129
+ Do not run \`kibi\` CLI commands directly; use the public MCP tools (kb_search, kb_query, kb_status, kb_find_gaps, kb_coverage, kb_graph, kb_upsert, kb_delete, kb_check).`;
32
130
  }
33
- const codeEdits = context.recentEdits.filter((e) => e.kind === "code");
34
- const reqEdits = context.recentEdits.filter((e) => e.kind === "requirement");
35
- const kbDocEdits = context.recentEdits.filter((e) => ["requirement", "scenario", "test", "adr", "fact"].includes(e.kind));
36
- if (codeEdits.length > 0) {
37
- const suggestion = context.recentCommentSuggestion;
38
- if (suggestion) {
39
- let routingMessage = "";
40
- switch (suggestion.suggestionType) {
41
- case "fact":
42
- routingMessage = `🎯 **Durable knowledge detected: FACT**
131
+ // Advisory guidance: check cache before selecting, since these blocks can be safely suppressed
132
+ else {
133
+ // Cache check: skip repeated advisory guidance only after critical signals are handled above
134
+ // Allow degraded advisory to bypass cache so it is always visible
135
+ if (!showDegraded &&
136
+ context.cache &&
137
+ context.workspaceRoot &&
138
+ context.branch &&
139
+ riskClass) {
140
+ const lastEdit = context.recentEdits[context.recentEdits.length - 1];
141
+ const key = {
142
+ workspaceRoot: context.workspaceRoot,
143
+ branch: context.branch,
144
+ posture,
145
+ riskClass,
146
+ fileBucket: deriveFileBucket(lastEdit?.kind ?? "unknown"),
147
+ };
148
+ if (context.cache.isSatisfied(key)) {
149
+ return SENTINEL; // skip guidance — recently satisfied
150
+ }
151
+ }
152
+ // Priority 5: Risk-class-driven guidance (for non-safe classes)
153
+ if (riskClass &&
154
+ riskClass !== "safe_docs_only" &&
155
+ riskClass !== "safe_test_only") {
156
+ // For behavior/traceability with comment suggestions, use suggestion guidance
157
+ if ((riskClass === "behavior_candidate" ||
158
+ riskClass === "traceability_candidate") &&
159
+ context.recentCommentSuggestion) {
160
+ selectedBlock = buildCommentSuggestionGuidance(context.recentCommentSuggestion);
161
+ }
162
+ else {
163
+ const block = GUIDANCE_BY_RISK[riskClass];
164
+ if (block)
165
+ selectedBlock = block;
166
+ }
167
+ }
168
+ // Priority 6: Legacy path-kind fallback (when no risk class)
169
+ else if (!riskClass) {
170
+ const codeEdits = context.recentEdits.filter((e) => e.kind === "code");
171
+ const reqEdits = context.recentEdits.filter((e) => e.kind === "requirement");
172
+ const kbDocEdits = context.recentEdits.filter((e) => [
173
+ "requirement",
174
+ "scenario",
175
+ "test",
176
+ "adr",
177
+ "fact",
178
+ "flag",
179
+ "event",
180
+ "symbol",
181
+ ].includes(e.kind));
182
+ if (codeEdits.length > 0) {
183
+ const suggestion = context.recentCommentSuggestion;
184
+ if (suggestion) {
185
+ selectedBlock = buildCommentSuggestionGuidance(suggestion);
186
+ }
187
+ else {
188
+ selectedBlock = `📝 **Code changes detected**
189
+
190
+ Before implementing or explaining code:
191
+ 1. **Discover first** - Run kb_search to find related requirements, ADRs, tests, facts, and symbols.
192
+ 2. **Follow up exactly** - Run kb_query by sourceFile, id, type, or tags once you know what you need.
193
+ 3. **Prefer Kibi over comments** - Store durable knowledge in KB entities instead of inline comments.
194
+ 4. **Add traceability** - For test/e2e symbols, prefer durable symbol/test/requirement relationships (e.g. via symbols.yaml with covered_by + validates/verified_by); inline // implements REQ-xxx comments remain optional and backward-compatible for quick code-only changes.
195
+
196
+ If you're adding long explanatory comments, consider routing that knowledge to:
197
+ - \`FACT\` for domain invariants, properties, limits, cardinalities
198
+ - \`ADR\` for technical decisions, tradeoffs, rationale
199
+ - \`REQ\` for system behavior requirements`;
200
+ }
201
+ }
202
+ else if (reqEdits.length > 0) {
203
+ selectedBlock = GUIDANCE_BY_RISK.req_policy_candidate;
204
+ }
205
+ else if (kbDocEdits.length > 0) {
206
+ selectedBlock = GUIDANCE_BY_RISK.kb_doc_structural;
207
+ }
208
+ }
209
+ }
210
+ // Source-linked micro-brief: insert after header line for code risk classes
211
+ // Inserting after the header (not prepending before it) preserves the header
212
+ // under enforceBudget's trimming logic, which only collects non-bullet lines
213
+ // before the first bullet.
214
+ if (selectedBlock &&
215
+ (riskClass === "behavior_candidate" ||
216
+ riskClass === "traceability_candidate") &&
217
+ context.workspaceRoot) {
218
+ try {
219
+ const lastEdit = context.recentEdits[context.recentEdits.length - 1];
220
+ if (lastEdit?.path) {
221
+ const editedPath = lastEdit.path;
222
+ const absEdited = path.isAbsolute(editedPath)
223
+ ? editedPath
224
+ : path.join(context.workspaceRoot, editedPath);
225
+ const linkedIds = getSourceLinkedRequirementIds(context.workspaceRoot, absEdited);
226
+ if (linkedIds.length >= 1 && linkedIds.length <= 3) {
227
+ const headerEnd = selectedBlock.indexOf("\n");
228
+ if (headerEnd !== -1) {
229
+ selectedBlock = `${selectedBlock.slice(0, headerEnd + 1)}- Existing Kibi links: ${linkedIds.join(", ")}\n${selectedBlock.slice(headerEnd + 1)}`;
230
+ }
231
+ else {
232
+ selectedBlock = `${selectedBlock}\n- Existing Kibi links: ${linkedIds.join(", ")}`;
233
+ }
234
+ }
235
+ }
236
+ }
237
+ catch {
238
+ // Non-fatal: source-linked brief is best-effort
239
+ }
240
+ }
241
+ // Inject degraded advisory block for warn-once mode
242
+ if (showDegraded) {
243
+ const advisory = `⚠️ **Maintenance degraded**
244
+
245
+ The Kibi workspace is in a maintenance-degraded state. Guidance remains advisory.`;
246
+ if (selectedBlock) {
247
+ selectedBlock = `${advisory}\n\n${selectedBlock}`;
248
+ }
249
+ else {
250
+ selectedBlock = advisory;
251
+ }
252
+ }
253
+ // Record cache after generating (advisory, non-blocking)
254
+ // Do not cache degraded-advisory-only emissions
255
+ if (!showDegraded &&
256
+ context.cache &&
257
+ context.workspaceRoot &&
258
+ context.branch &&
259
+ riskClass) {
260
+ const lastEdit = context.recentEdits[context.recentEdits.length - 1];
261
+ const key = {
262
+ workspaceRoot: context.workspaceRoot,
263
+ branch: context.branch,
264
+ posture,
265
+ riskClass,
266
+ fileBucket: deriveFileBucket(lastEdit?.kind ?? "unknown"),
267
+ };
268
+ context.cache.recordSatisfied(key, "guidance");
269
+ }
270
+ // Append completion reminder for risky classes when enabled
271
+ const REMINDER_RISK_CLASSES = [
272
+ "behavior_candidate",
273
+ "traceability_candidate",
274
+ "req_policy_candidate",
275
+ ];
276
+ if (selectedBlock &&
277
+ context.completionReminder === true &&
278
+ !context.maintenanceDegraded &&
279
+ riskClass &&
280
+ REMINDER_RISK_CLASSES.includes(riskClass) &&
281
+ posture !== "root_uninitialized" &&
282
+ posture !== "root_partial") {
283
+ selectedBlock = `${selectedBlock}\n- Run \`kb_check\` before completing this task.`;
284
+ }
285
+ // Return: sentinel + one targeted block (or just sentinel if no block)
286
+ return selectedBlock
287
+ ? `${SENTINEL}\n\n${enforceBudget(selectedBlock)}`
288
+ : SENTINEL;
289
+ }
290
+ // ── Comment suggestion guidance (legacy compat) ────────────────────────
291
+ function buildCommentSuggestionGuidance(suggestion) {
292
+ switch (suggestion.suggestionType) {
293
+ case "fact":
294
+ return `🎯 **Durable knowledge detected: FACT**
43
295
 
44
296
  Your recent code edit contains a comment that looks like a **domain invariant** (properties, limits, defaults, or cardinality constraints).
45
297
 
46
298
  **Action**: Instead of inline comments, route this to a FACT entity:
47
299
  - Create \`documentation/facts/FACT-xxx.md\` with the invariant
48
- - Link it to relevant requirements using \`constrains\` or \`requires_property\` relationships
49
- - Reference the FACT in code with a comment (e.g., \`// constrained by FACT-xxx\` in JS/TS or a docstring comment in Python)
300
+ - Link it to relevant requirements
301
+ - Reference the FACT in code with a comment
50
302
 
51
303
  This keeps domain truths centralized and searchable.`;
52
- break;
53
- case "adr":
54
- routingMessage = `🎯 **Durable knowledge detected: ADR**
304
+ case "adr":
305
+ return `🎯 **Durable knowledge detected: ADR**
55
306
 
56
307
  Your recent code edit contains a comment that looks like a **technical decision** (tradeoffs, rationale, or architecture choices).
57
308
 
58
309
  **Action**: Instead of inline comments, route this to an ADR entity:
59
310
  - Create \`documentation/adr/ADR-xxx.md\` documenting the decision
60
311
  - Include context, options considered, and the chosen approach
61
- - Link to constrained code symbols using \`constrained_by\` relationships
312
+ - Link to constrained code symbols
62
313
 
63
314
  This preserves decision context for future maintainers.`;
64
- break;
65
- case "req":
66
- routingMessage = `🎯 **Durable knowledge detected: REQ**
315
+ case "req":
316
+ return `🎯 **Durable knowledge detected: REQ**
67
317
 
68
318
  Your recent code edit contains a comment that looks like **behavior intent** (system capabilities or user-facing requirements).
69
319
 
70
320
  **Action**: Instead of inline comments, route this to a REQ entity:
71
321
  - Create \`documentation/requirements/REQ-xxx.md\` with the behavior description
72
322
  - Add SCEN and TEST entities for specification and verification
73
- - Link code to requirements using traceability comments (e.g., \`// implements REQ-xxx\` in JS/TS or docstring references in Python)
323
+ - Link code to requirements: for test/e2e symbols prefer durable relationships (e.g. via symbols.yaml with covered_by + validates/verified_by); inline // implements REQ-xxx comments remain optional and backward-compatible
74
324
 
75
325
  This ensures behavior is documented and traceable.`;
76
- break;
77
- default:
78
- routingMessage = `📝 **Code changes detected**
79
-
80
- Before implementing or explaining code:
81
- 1. **Discover first** - Run kb_search to find related requirements, ADRs, tests, facts, and symbols.
82
- 2. **Follow up exactly** - Run kb_query by sourceFile, id, type, or tags once you know what you need.
83
- 3. **Check freshness when needed** - Run kb_status if you need branch or stale-state confirmation.
84
- 4. **Prefer Kibi over comments** - Store durable knowledge in KB entities instead of inline comments.
85
- 5. **Add traceability** - Add traceability comments to new or modified functions/classes so the pre-commit hook can verify coverage (e.g., \`// implements REQ-xxx\` in JS/TS or docstring references in Python).`;
86
- }
87
- parts.push(routingMessage);
88
- }
89
- else {
90
- parts.push(`
91
- 📝 **Code changes detected**
326
+ default:
327
+ return `📝 **Code changes detected**
92
328
 
93
329
  Before implementing or explaining code:
94
330
  1. **Discover first** - Run kb_search to find related requirements, ADRs, tests, facts, and symbols.
95
331
  2. **Follow up exactly** - Run kb_query by sourceFile, id, type, or tags once you know what you need.
96
- 3. **Check freshness when needed** - Run kb_status if you need branch or stale-state confirmation.
97
- 4. **Prefer Kibi over comments** - Store durable knowledge in KB entities instead of inline comments.
98
- 5. **Add traceability** - Add traceability comments to new or modified functions/classes (e.g., \`// implements REQ-xxx\` in JS/TS or docstring references in Python) so the pre-commit hook can verify coverage.
99
-
100
- If you're adding long explanatory comments, consider routing that knowledge to:
101
- - \`FACT\` for domain invariants, properties, limits, cardinalities
102
- - \`ADR\` for technical decisions, tradeoffs, rationale
103
- - \`REQ\` for system behavior requirements
104
- - \`SCEN\` for behavior examples and flows
105
- - \`TEST\` for verification intent
106
- `);
107
- }
108
- }
109
- if (reqEdits.length > 0) {
110
- parts.push(`
111
- 📋 **Requirement changes detected**
112
-
113
- When editing requirements:
114
- 1. **Keep artifacts separate** - Do not embed scenarios or tests inside requirement files.
115
- 2. **Add verification** - Create or update linked \`SCEN\` and \`TEST\` entities.
116
- 3. **Check coverage** - For \`priority: must\` requirements, ensure both scenario and test coverage.
117
-
118
- Preferred structure:
119
- - \`REQ-xxx.md\` contains the requirement statement
120
- - \`SCEN-xxx.md\` specifies behavior via Given/When/Then
121
- - \`TEST-xxx.md\` verifies the requirement
122
- `);
123
- }
124
- if (kbDocEdits.length > 0 && reqEdits.length === 0) {
125
- parts.push(`
126
- 📚 **Kibi documentation changes detected**
127
-
128
- When editing KB documentation:
129
- 1. **Maintain traceability** - Link entities using relationships: specified_by (req→scenario), verified_by (req→test), etc.
130
- 2. **Validate** - Use \`kb_check\` after making changes to catch integrity issues.
131
- 3. **Follow entity patterns** - Ensure each entity has proper frontmatter with required fields.
132
- `);
133
- }
134
- if (parts.length === 1) {
135
- parts.push(`This project uses Kibi (via MCP). Prefer storing durable knowledge in Kibi over code comments.
136
-
137
- Before changing behavior: use kb_search for discovery, then kb_query by sourceFile, id, type, or tags for exact follow-up; do not rely on undocumented tools.
138
-
139
- Keep changed symbols traceable: add \`// implements REQ-xxx\` to every new or modified function/class so the pre-commit hook can verify coverage.
140
-
141
- Run kb_check after KB mutations.
142
-
143
- Dogfood note for this repo: OpenCode here uses local built \`kibi-mcp\` and \`kibi-opencode\` artifacts. If you change package versions or local package wiring, run \`bun run build\` before relying on OpenCode in this workspace.
144
-
145
- **Kibi-first workflow:**
146
- 1. **Discover**: Run kb_search to find relevant requirements, ADRs, tests, facts, and symbols.
147
- 2. **Confirm**: Run kb_query with sourceFile, id, type, or tags once you know the exact follow-up target.
148
- 3. **Inspect freshness**: Run kb_status when branch or stale-state confidence matters.
149
- 4. **Document intent**: If you are about to explain code, STOP. Route that explanation to kb_upsert instead of inline comments.
150
- 5. **Link during work**: When creating KB entities, include relationship rows: specified_by (req→scenario), verified_by (req→test), implements (symbol→req), covered_by (symbol→test).
151
- 6. **Validate**: Run kb_check after KB mutations to catch violations early.
152
-
153
- **Public Kibi tools only:** kb_search, kb_query, kb_status, kb_find_gaps, kb_coverage, kb_graph, kb_upsert, kb_delete, kb_check.
154
-
155
- Do not invoke Kibi CLI commands directly from the agent.
156
-
157
- Bootstrap existing repos: use \`/init-kibi\` to run the retroactive initialization workflow.`);
332
+ 3. **Prefer Kibi over comments** - Store durable knowledge in KB entities instead of inline comments.
333
+ 4. **Add traceability** - For test/e2e symbols, prefer durable symbol/test/requirement relationships (e.g. via symbols.yaml with covered_by + validates/verified_by); inline // implements REQ-xxx comments remain optional and backward-compatible for quick code-only changes.`;
158
334
  }
159
- return parts.join("\n\n").trim();
160
335
  }
336
+ // ── Base guidance (no context) ─────────────────────────────────────────
161
337
  /**
162
338
  * Build the static guidance block (original behavior).
163
339
  */
@@ -166,7 +342,7 @@ This project uses Kibi (via MCP). Prefer storing durable knowledge in Kibi over
166
342
 
167
343
  Before changing behavior: use kb_search for discovery, then kb_query by sourceFile, id, type, or tags for exact follow-up; do not rely on undocumented tools.
168
344
 
169
- Keep changed symbols traceable: add \`// implements REQ-xxx\` to every new or modified function/class so the pre-commit hook can verify coverage.
345
+ Keep changed symbols traceable: for test and e2e code, prefer durable symbol/test/requirement relationships (e.g. via \`symbols.yaml\`); inline \`// implements REQ-xxx\` comments remain optional and backward-compatible for quick code-only changes.
170
346
 
171
347
  Run kb_check after KB mutations.
172
348
 
@@ -186,7 +362,7 @@ Do not invoke Kibi CLI commands directly from the agent.
186
362
 
187
363
  Bootstrap existing repos: use \`/init-kibi\` to run the retroactive initialization workflow.`;
188
364
  /**
189
- * Build prompt with contextual guidance based on recent edits and workspace state.
365
+ * Build prompt with contextual guidance based on posture, risk class, and cache state.
190
366
  */
191
367
  export function buildPrompt(context) {
192
368
  if (!context) {
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Classification of the repository's Kibi posture — how Kibi is (or isn't)
3
+ * set up relative to the active workspace root.
4
+ */
5
+ export type RepoPosture = "root_active" | "root_partial" | "root_uninitialized" | "vendored_only" | "hybrid_root_plus_vendored";
6
+ export interface PostureResult {
7
+ state: RepoPosture;
8
+ needsBootstrap: boolean;
9
+ reason: string;
10
+ maintenanceDegraded: boolean;
11
+ }
12
+ export declare function detectPosture(cwd: string): PostureResult;