kibi-cursor 0.2.2 → 0.5.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 (41) hide show
  1. package/.cursor-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +71 -0
  3. package/README.md +7 -5
  4. package/dist/.cursor-plugin/plugin.json +1 -1
  5. package/dist/guidance.d.ts +10 -2
  6. package/dist/guidance.js +27 -17
  7. package/dist/hook-runner.d.ts +1 -0
  8. package/dist/hook-runner.js +41 -11
  9. package/dist/hook-state-storage.d.ts +11 -0
  10. package/dist/hook-state-storage.js +187 -0
  11. package/dist/hook-state.d.ts +9 -5
  12. package/dist/hook-state.js +14 -196
  13. package/dist/kb-mcp-tools.d.ts +9 -0
  14. package/dist/kb-mcp-tools.js +94 -0
  15. package/dist/messages.d.ts +4 -2
  16. package/dist/messages.js +33 -3
  17. package/dist/path-policy.d.ts +1 -0
  18. package/dist/path-policy.js +18 -0
  19. package/dist/rules/kibi-traceability.mdc +2 -0
  20. package/dist/rules/kibi-workflow.mdc +3 -3
  21. package/dist/skills/.canon-hash.json +10 -0
  22. package/dist/skills/init-kibi/SKILL.md +50 -11
  23. package/dist/skills/kibi-freshness/SKILL.md +32 -10
  24. package/dist/skills/kibi-traceability/SKILL.md +41 -9
  25. package/dist/skills/kibi-usage/SKILL.md +123 -95
  26. package/dist/skills/kibi-usage/resources/fact-lanes.md +225 -0
  27. package/dist/skills/kibi-usage/resources/operation-access.md +44 -0
  28. package/dist/skills/kibi-usage/resources/relationship-directions.md +119 -0
  29. package/dist/skills/kibi-usage/resources/workflows.md +65 -0
  30. package/package.json +2 -2
  31. package/rules/kibi-traceability.mdc +2 -0
  32. package/rules/kibi-workflow.mdc +3 -3
  33. package/skills/.canon-hash.json +10 -0
  34. package/skills/init-kibi/SKILL.md +50 -11
  35. package/skills/kibi-freshness/SKILL.md +32 -10
  36. package/skills/kibi-traceability/SKILL.md +41 -9
  37. package/skills/kibi-usage/SKILL.md +123 -95
  38. package/skills/kibi-usage/resources/fact-lanes.md +225 -0
  39. package/skills/kibi-usage/resources/operation-access.md +44 -0
  40. package/skills/kibi-usage/resources/relationship-directions.md +119 -0
  41. package/skills/kibi-usage/resources/workflows.md +65 -0
@@ -1,195 +1,5 @@
1
- // implements REQ-cursor-kibi-plugin-v1
2
- import { randomUUID } from "node:crypto";
3
- import fs from "node:fs";
4
- import os from "node:os";
5
- import path from "node:path";
6
- const stateFileName = "hook-state.json";
7
- const lockFileName = "hook-state.lock";
8
- const maxDirtyPaths = 50;
9
- const maxGuidedPaths = 100;
10
- const lockRetryCount = 100;
11
- const lockRetryDelayMs = 5;
12
- const staleLockAgeMs = 30_000;
13
- function statePath(pluginData) {
14
- return path.join(pluginData, stateFileName);
15
- }
16
- function lockPath(pluginData) {
17
- return path.join(pluginData, lockFileName);
18
- }
19
- function isRecord(value) {
20
- return typeof value === "object" && value !== null && !Array.isArray(value);
21
- }
22
- function normalizePath(dirtyPath) {
23
- return dirtyPath.trim().replaceAll("\\", "/");
24
- }
25
- function sleepSync(milliseconds) {
26
- const buffer = new SharedArrayBuffer(4);
27
- const view = new Int32Array(buffer);
28
- Atomics.wait(view, 0, 0, milliseconds);
29
- }
30
- function uniqueTempPath(pluginData) {
31
- return path.join(pluginData, `${stateFileName}.${process.pid}.${Date.now()}.${randomUUID()}.tmp`);
32
- }
33
- function mergeStringPaths(existingPaths, nextPaths) {
34
- const merged = [...existingPaths, ...nextPaths]
35
- .map(normalizePath)
36
- .filter((dirtyPath) => dirtyPath.length > 0);
37
- return [...new Set(merged)].slice(-maxGuidedPaths);
38
- }
39
- const maxKbMutationTools = 20;
40
- function emptyHookState() {
41
- return {
42
- dirtyPaths: [],
43
- guidedReadPaths: [],
44
- guidedWritePaths: [],
45
- kbMutationTools: [],
46
- kbCheckRun: false,
47
- };
48
- }
49
- function acquireLock(pluginData) {
50
- const targetLockPath = lockPath(pluginData);
51
- for (let attempt = 0; attempt < lockRetryCount; attempt++) {
52
- try {
53
- return fs.openSync(targetLockPath, "wx");
54
- }
55
- catch (error) {
56
- if (error instanceof Error &&
57
- "code" in error &&
58
- error.code === "EEXIST") {
59
- if (removeStaleLock(targetLockPath)) {
60
- continue;
61
- }
62
- sleepSync(lockRetryDelayMs);
63
- continue;
64
- }
65
- return undefined;
66
- }
67
- }
68
- return undefined;
69
- }
70
- function removeStaleLock(targetLockPath) {
71
- let stats;
72
- try {
73
- stats = fs.statSync(targetLockPath);
74
- }
75
- catch {
76
- return false;
77
- }
78
- if (Date.now() - stats.mtimeMs < staleLockAgeMs) {
79
- return false;
80
- }
81
- try {
82
- fs.unlinkSync(targetLockPath);
83
- return true;
84
- }
85
- catch {
86
- return false;
87
- }
88
- }
89
- function releaseLock(pluginData, fileDescriptor) {
90
- try {
91
- fs.closeSync(fileDescriptor);
92
- }
93
- catch {
94
- // Ignore close failures; unlink still gives future hook runs a chance.
95
- }
96
- try {
97
- fs.unlinkSync(lockPath(pluginData));
98
- }
99
- catch {
100
- // A missing lock file is safe: bounded retries prevent permanent blocking.
101
- }
102
- }
103
- function coerceHookState(value) {
104
- if (!isRecord(value)) {
105
- return emptyHookState();
106
- }
107
- const dirtyPaths = Array.isArray(value.dirtyPaths)
108
- ? value.dirtyPaths
109
- .filter((dirtyPath) => typeof dirtyPath === "string")
110
- .map(normalizePath)
111
- .filter((dirtyPath) => dirtyPath.length > 0)
112
- : [];
113
- const guidedReadPaths = Array.isArray(value.guidedReadPaths)
114
- ? value.guidedReadPaths
115
- .filter((entry) => typeof entry === "string")
116
- .map(normalizePath)
117
- .filter((entry) => entry.length > 0)
118
- : [];
119
- const guidedWritePaths = Array.isArray(value.guidedWritePaths)
120
- ? value.guidedWritePaths
121
- .filter((entry) => typeof entry === "string")
122
- .map(normalizePath)
123
- .filter((entry) => entry.length > 0)
124
- : [];
125
- const kbMutationTools = Array.isArray(value.kbMutationTools)
126
- ? value.kbMutationTools
127
- .filter((entry) => typeof entry === "string")
128
- .map((entry) => entry.trim())
129
- .filter((entry) => entry.length > 0)
130
- : [];
131
- const kbCheckRun = value.kbCheckRun === true;
132
- return {
133
- dirtyPaths: [...new Set(dirtyPaths)].slice(-maxDirtyPaths),
134
- guidedReadPaths: [...new Set(guidedReadPaths)].slice(-maxGuidedPaths),
135
- guidedWritePaths: [...new Set(guidedWritePaths)].slice(-maxGuidedPaths),
136
- kbMutationTools: [...new Set(kbMutationTools)].slice(-maxKbMutationTools),
137
- kbCheckRun,
138
- };
139
- }
140
- export function resolveStateDir(pluginData, conversationId) {
141
- if (pluginData) {
142
- return pluginData;
143
- }
144
- if (!conversationId) {
145
- return undefined;
146
- }
147
- return path.join(os.tmpdir(), "kibi-cursor-hook-state", conversationId.replaceAll(/[^a-zA-Z0-9._-]/g, "_"));
148
- }
149
- export function loadHookState(stateDir) {
150
- if (!stateDir) {
151
- return emptyHookState();
152
- }
153
- try {
154
- return coerceHookState(JSON.parse(fs.readFileSync(statePath(stateDir), "utf8")));
155
- }
156
- catch {
157
- return emptyHookState();
158
- }
159
- }
160
- export function saveHookState(stateDir, state) {
161
- if (!stateDir) {
162
- return;
163
- }
164
- fs.mkdirSync(stateDir, { recursive: true });
165
- const boundedState = coerceHookState(state);
166
- const tempPath = uniqueTempPath(stateDir);
167
- fs.writeFileSync(tempPath, `${JSON.stringify(boundedState)}\n`);
168
- fs.renameSync(tempPath, statePath(stateDir));
169
- }
170
- export function updateHookState(stateDir, updater) {
171
- const initialState = loadHookState(stateDir);
172
- if (!stateDir) {
173
- return updater(initialState);
174
- }
175
- fs.mkdirSync(stateDir, { recursive: true });
176
- const lockFileDescriptor = acquireLock(stateDir);
177
- if (lockFileDescriptor === undefined) {
178
- return updater(initialState);
179
- }
180
- try {
181
- const lockedState = loadHookState(stateDir);
182
- const nextState = updater(lockedState);
183
- saveHookState(stateDir, nextState);
184
- return nextState;
185
- }
186
- catch {
187
- return updater(initialState);
188
- }
189
- finally {
190
- releaseLock(stateDir, lockFileDescriptor);
191
- }
192
- }
1
+ import { emptyHookState, loadHookState, maxDirtyPaths, maxKbMutationTools, mergeStringPaths, normalizePath, updateHookState, } from "./hook-state-storage.js";
2
+ export { loadHookState, resolveStateDir, saveHookState, updateHookState, } from "./hook-state-storage.js";
193
3
  export function addDirtyPaths(stateDir, dirtyPaths) {
194
4
  return updateHookState(stateDir, (state) => ({
195
5
  ...state,
@@ -219,24 +29,32 @@ export function hasGuidedPath(state, kind, guidedPath) {
219
29
  const bucket = kind === "read" ? state.guidedReadPaths : state.guidedWritePaths;
220
30
  return bucket.includes(normalized);
221
31
  }
222
- export function recordKbMcpTool(stateDir, toolName) {
32
+ export function recordKbMcpTool(stateDir, toolName, options = {}) {
223
33
  const normalized = toolName.trim();
224
34
  if (normalized.length === 0) {
225
35
  return loadHookState(stateDir);
226
36
  }
227
37
  return updateHookState(stateDir, (state) => {
38
+ const observedState = { ...state, mcpState: "observed" };
228
39
  if (normalized === "kb_check") {
229
- return { ...state, kbCheckRun: true };
40
+ return {
41
+ ...observedState,
42
+ kbCheckRun: true,
43
+ impactCheckRun: state.impactCheckRun || options.impactCheckRun === true,
44
+ impactCheckedPaths: options.impactCheckRun === true
45
+ ? mergeStringPaths(state.impactCheckedPaths, options.sourceFiles ?? [])
46
+ : state.impactCheckedPaths,
47
+ };
230
48
  }
231
49
  if (normalized === "kb_upsert" || normalized === "kb_delete") {
232
50
  return {
233
- ...state,
51
+ ...observedState,
234
52
  kbMutationTools: mergeStringPaths(state.kbMutationTools, [
235
53
  normalized,
236
54
  ]).slice(-maxKbMutationTools),
237
55
  };
238
56
  }
239
- return state;
57
+ return observedState;
240
58
  });
241
59
  }
242
60
  export function clearSessionHookState(stateDir) {
@@ -1 +1,10 @@
1
+ export type KbMcpToolCall = {
2
+ toolName: string;
3
+ impactCheckRun: boolean;
4
+ sourceFiles: string[];
5
+ };
6
+ export type McpState = "observed" | "unknown";
7
+ export type KibiInterface = "mcp" | "cli" | "setup";
8
+ export declare function resolveKibiInterface(mcpState: McpState, workspaceTrusted: boolean): KibiInterface;
9
+ export declare function extractKbMcpToolCall(toolName: string | undefined, toolInput: unknown): KbMcpToolCall | undefined;
1
10
  export declare function extractKbMcpToolName(toolName: string | undefined, toolInput: unknown): string | undefined;
@@ -11,7 +11,101 @@ function readString(record, keys) {
11
11
  }
12
12
  return undefined;
13
13
  }
14
+ function readBoolean(record, keys) {
15
+ for (const key of keys) {
16
+ const value = record[key];
17
+ if (typeof value === "boolean") {
18
+ return value;
19
+ }
20
+ }
21
+ return undefined;
22
+ }
23
+ function readStringArray(record, keys) {
24
+ for (const key of keys) {
25
+ const value = record[key];
26
+ if (!Array.isArray(value)) {
27
+ continue;
28
+ }
29
+ return value.filter((item) => typeof item === "string" && item.length > 0);
30
+ }
31
+ return [];
32
+ }
33
+ function readRecord(record, keys) {
34
+ for (const key of keys) {
35
+ const value = record[key];
36
+ if (isRecord(value)) {
37
+ return value;
38
+ }
39
+ }
40
+ return undefined;
41
+ }
42
+ export function resolveKibiInterface(mcpState, workspaceTrusted) {
43
+ if (mcpState === "observed") {
44
+ return "mcp";
45
+ }
46
+ return workspaceTrusted ? "cli" : "setup";
47
+ }
48
+ export function extractKbMcpToolCall(toolName, toolInput) {
49
+ const directToolName = toolName?.trim();
50
+ let normalizedToolName = directToolName?.startsWith("kb_")
51
+ ? directToolName
52
+ : undefined;
53
+ if (isRecord(toolInput)) {
54
+ normalizedToolName ??= readString(toolInput, [
55
+ "toolName",
56
+ "tool_name",
57
+ "name",
58
+ ]);
59
+ const args = readRecord(toolInput, ["arguments", "args"]);
60
+ const payload = args ?? toolInput;
61
+ const includeImpactDiagnostics = readBoolean(payload, [
62
+ "includeImpactDiagnostics",
63
+ "include_impact_diagnostics",
64
+ ]);
65
+ const includeWorkingTreeDiff = readBoolean(payload, [
66
+ "includeWorkingTreeDiff",
67
+ "include_working_tree_diff",
68
+ ]);
69
+ const sourceFiles = readStringArray(payload, [
70
+ "sourceFiles",
71
+ "source_files",
72
+ ]);
73
+ if (normalizedToolName?.startsWith("kb_")) {
74
+ return {
75
+ toolName: normalizedToolName,
76
+ impactCheckRun: normalizedToolName === "kb_check" &&
77
+ includeImpactDiagnostics === true &&
78
+ includeWorkingTreeDiff === true &&
79
+ sourceFiles.length > 0,
80
+ sourceFiles,
81
+ };
82
+ }
83
+ const nestedArgs = toolInput.arguments ?? toolInput.args;
84
+ if (isRecord(nestedArgs)) {
85
+ const nestedTool = readString(nestedArgs, [
86
+ "toolName",
87
+ "tool_name",
88
+ "name",
89
+ ]);
90
+ if (nestedTool?.startsWith("kb_")) {
91
+ return { toolName: nestedTool, impactCheckRun: false, sourceFiles: [] };
92
+ }
93
+ }
94
+ }
95
+ if (normalizedToolName?.startsWith("kb_")) {
96
+ return {
97
+ toolName: normalizedToolName,
98
+ impactCheckRun: false,
99
+ sourceFiles: [],
100
+ };
101
+ }
102
+ return undefined;
103
+ }
14
104
  export function extractKbMcpToolName(toolName, toolInput) {
105
+ const toolCall = extractKbMcpToolCall(toolName, toolInput);
106
+ if (toolCall) {
107
+ return toolCall.toolName;
108
+ }
15
109
  if (toolName) {
16
110
  const normalized = toolName.trim();
17
111
  if (normalized.startsWith("kb_")) {
@@ -1,6 +1,8 @@
1
1
  import type { HookState } from "./hook-state.js";
2
- export declare const BOOTSTRAP_REMINDER = "Kibi config was not found at the Cursor workspace root. Use the Kibi MCP /init-kibi workflow to bootstrap project memory before relying on KB lookups; do not edit .kb/ files directly.";
3
- export declare const DIRECT_KB_EDIT_WARNING = "Avoid direct edits to .kb/. Use Kibi MCP tools for KB discovery and mutations so project memory stays valid.";
2
+ import { type McpState } from "./kb-mcp-tools.js";
3
+ export declare const BOOTSTRAP_REMINDER = "Kibi config was not found at the Cursor workspace root. Use visible Kibi MCP tools, or a trusted project-local CLI JSON route with --input when MCP is unavailable, to bootstrap project memory; if neither interface is available, tell the operator. Do not read or edit `.kb/` files directly. Query before mutate, run kb_upsert sequentially, and run kb_check before completion.";
4
+ export declare const DIRECT_KB_EDIT_WARNING = "Do not read or edit `.kb/` files directly. Use visible Kibi MCP tools, or trusted project-local CLI JSON routes with --input when MCP is unavailable. Query before mutate, run kb_upsert sequentially, and run kb_check before completion.";
5
+ export declare function interfaceAdvisory(mcpState: McpState, workspaceTrusted: boolean): string | undefined;
4
6
  export declare function stopFollowupMessage(state: HookState): string | undefined;
5
7
  /** @deprecated Use stopFollowupMessage */
6
8
  export declare function freshnessReminder(dirtyPaths: readonly string[]): string;
package/dist/messages.js CHANGED
@@ -1,11 +1,31 @@
1
- import { isKbFreshnessRelevantPath } from "./path-policy.js";
2
- export const BOOTSTRAP_REMINDER = "Kibi config was not found at the Cursor workspace root. Use the Kibi MCP /init-kibi workflow to bootstrap project memory before relying on KB lookups; do not edit .kb/ files directly.";
3
- export const DIRECT_KB_EDIT_WARNING = "Avoid direct edits to .kb/. Use Kibi MCP tools for KB discovery and mutations so project memory stays valid.";
1
+ import { resolveKibiInterface } from "./kb-mcp-tools.js";
2
+ import { isKbFreshnessRelevantPath, isSourceImpactRelevantPath, } from "./path-policy.js";
3
+ export const BOOTSTRAP_REMINDER = "Kibi config was not found at the Cursor workspace root. Use visible Kibi MCP tools, or a trusted project-local CLI JSON route with --input when MCP is unavailable, to bootstrap project memory; if neither interface is available, tell the operator. Do not read or edit `.kb/` files directly. Query before mutate, run kb_upsert sequentially, and run kb_check before completion.";
4
+ export const DIRECT_KB_EDIT_WARNING = "Do not read or edit `.kb/` files directly. Use visible Kibi MCP tools, or trusted project-local CLI JSON routes with --input when MCP is unavailable. Query before mutate, run kb_upsert sequentially, and run kb_check before completion.";
5
+ export function interfaceAdvisory(mcpState, workspaceTrusted) {
6
+ const selectedInterface = resolveKibiInterface(mcpState, workspaceTrusted);
7
+ switch (selectedInterface) {
8
+ case "mcp":
9
+ return undefined;
10
+ case "cli":
11
+ return "Kibi MCP has not been observed in this session. In this explicitly trusted workspace, the project-local CLI is an advisory fallback: use npx --no-install kibi or bunx --no-install kibi. Do not use global or installing runners.";
12
+ case "setup":
13
+ return "Kibi MCP has not been observed in this session and workspace trust is unknown. Do not probe or execute a CLI fallback; ask the operator to enable MCP or explicitly approve the trusted project-local CLI workflow.";
14
+ }
15
+ }
4
16
  export function stopFollowupMessage(state) {
5
17
  if (state.kbMutationTools.length > 0) {
6
18
  const tools = [...new Set(state.kbMutationTools)];
7
19
  return `Kibi KB updated (${tools.join(", ")}).`;
8
20
  }
21
+ const sourceImpactPaths = state.dirtyPaths.filter(isSourceImpactRelevantPath);
22
+ const uncheckedSourcePaths = sourceImpactPaths.filter((sourcePath) => !state.impactCheckedPaths.includes(sourcePath));
23
+ if (uncheckedSourcePaths.length > 0 && !state.impactCheckRun) {
24
+ return impactCheckFollowup(uncheckedSourcePaths);
25
+ }
26
+ if (uncheckedSourcePaths.length > 0) {
27
+ return impactCheckFollowup(uncheckedSourcePaths);
28
+ }
9
29
  const freshnessPaths = state.dirtyPaths.filter(isKbFreshnessRelevantPath);
10
30
  if (freshnessPaths.length === 0 || state.kbCheckRun) {
11
31
  return undefined;
@@ -14,6 +34,16 @@ export function stopFollowupMessage(state) {
14
34
  const noun = fileCount === 1 ? "file" : "files";
15
35
  return `Kibi: sync or record no-impact after ${fileCount} edited ${noun}.`;
16
36
  }
37
+ function impactCheckFollowup(sourcePaths) {
38
+ const fileCount = sourcePaths.length;
39
+ const noun = fileCount === 1 ? "file" : "files";
40
+ const sourceFiles = JSON.stringify(sourcePaths.slice(0, 10));
41
+ return [
42
+ `Kibi: run impact-enabled kb_check after ${fileCount} edited source ${noun}.`,
43
+ `Use kb_check({sourceFiles:${sourceFiles}, includeImpactDiagnostics:true, includeWorkingTreeDiff:true}).`,
44
+ "Review symbol granularity and semantic review of linked requirements/tests before stopping.",
45
+ ].join("\n");
46
+ }
17
47
  /** @deprecated Use stopFollowupMessage */
18
48
  export function freshnessReminder(dirtyPaths) {
19
49
  const fileCount = dirtyPaths.length;
@@ -3,5 +3,6 @@ export declare function isDirectKbPath(candidate: string): boolean;
3
3
  export declare function isMeaningfulTrackedPath(candidate: string): boolean;
4
4
  /** Paths whose edits should trigger a KB freshness stop follow-up. */
5
5
  export declare function isKbFreshnessRelevantPath(candidate: string): boolean;
6
+ export declare function isSourceImpactRelevantPath(candidate: string): boolean;
6
7
  export declare function isDocumentationTrackedPath(candidate: string): boolean;
7
8
  export declare function toRepoRelativePath(candidate: string, cwd: string | undefined): string;
@@ -29,6 +29,7 @@ const sourceExtensions = new Set([
29
29
  ".mjs",
30
30
  ".mts",
31
31
  ".php",
32
+ ".pl",
32
33
  ".py",
33
34
  ".rb",
34
35
  ".rs",
@@ -122,6 +123,23 @@ export function isKbFreshnessRelevantPath(candidate) {
122
123
  segments[1] === "core" &&
123
124
  segments[2] === "src");
124
125
  }
126
+ export function isSourceImpactRelevantPath(candidate) {
127
+ const normalized = normalizePath(candidate);
128
+ const segments = pathSegments(normalized);
129
+ if (segments.includes(".kb") ||
130
+ segments.includes("dist") ||
131
+ segments.includes("tests") ||
132
+ segments.includes("test") ||
133
+ segments.includes("docs") ||
134
+ segments.includes("documentation")) {
135
+ return false;
136
+ }
137
+ const basename = segments.at(-1) ?? "";
138
+ const extension = basename.includes(".")
139
+ ? `.${basename.split(".").at(-1) ?? ""}`
140
+ : "";
141
+ return segments.includes("src") && sourceExtensions.has(extension);
142
+ }
125
143
  export function isDocumentationTrackedPath(candidate) {
126
144
  const normalized = normalizePath(candidate);
127
145
  const segments = pathSegments(normalized);
@@ -7,6 +7,8 @@ alwaysApply: false
7
7
 
8
8
  Before changing production code, discover linked requirements with `kb_search` and `kb_query(sourceFile=...)`.
9
9
 
10
+ After meaningful source edits, run `kb_check({sourceFiles:[...], includeImpactDiagnostics:true, includeWorkingTreeDiff:true})` while the edit context is fresh. Review symbol granularity and whether linked requirements, scenarios, and tests still cover the changed behavior or UI copy.
11
+
10
12
  Preserve the canonical chain `REQ-* -> SCEN-* -> TEST-*` when modeling behavior.
11
13
 
12
14
  Prefer symbol manifest + `executable_for` for test/e2e code. Inline `// implements REQ-xxx` remains acceptable for quick code-only changes.
@@ -1,9 +1,9 @@
1
1
  ---
2
- description: Kibi MCP discovery-first workflow and KB mutation discipline
2
+ description: Kibi capability-based discovery-first workflow and KB mutation discipline
3
3
  alwaysApply: true
4
4
  ---
5
5
 
6
- Use Kibi via MCP tools only. Do not manually read or edit `.kb/` files.
6
+ Use Kibi via MCP tools when available, or via CLI JSON routes when MCP is unavailable. If MCP tools are visible, use MCP. If MCP availability is unknown and a trusted project-local CLI is available, use `kibi <route> --input <file|->`. If neither interface is available, stop and tell the operator. Do not infer MCP availability from config file existence. Do not read or edit `.kb/` files directly.
7
7
 
8
8
  Discovery workflow:
9
9
  - Start with `kb_search` for broad discovery.
@@ -13,7 +13,7 @@ Discovery workflow:
13
13
  Mutation workflow:
14
14
  - Query before mutate.
15
15
  - Create relationship endpoints before linking.
16
- - Use `kb_upsert` sequentially, then `kb_check`.
16
+ - Use `kb_upsert` sequentially. Run `kb_check` before completion.
17
17
  - Use `kb_delete` only for intentional removals with dependency awareness.
18
18
 
19
19
  Completion must state KB freshness outcome: updated, no-impact with rationale, or deferred/failed.
@@ -0,0 +1,10 @@
1
+ {
2
+ "init-kibi/SKILL.md": "4e936774cd31cf366e9e17452e9030fdaeabab345bce5ee163656e0fe5dc73d7",
3
+ "kibi-freshness/SKILL.md": "68345a514233503f8f78d53e7d602d8a5fc566e1ec118388c7393716c9f7490d",
4
+ "kibi-traceability/SKILL.md": "a621553397c1f8813f05fd9552fc30a5e8ed118442e019add35804de7d43a0b1",
5
+ "kibi-usage/SKILL.md": "f4a713d8c95d9c9a254e2f23b27013293f0caacb4009409409e56c7deeccc8a5",
6
+ "kibi-usage/resources/fact-lanes.md": "8b2f835775e57427db980c5412d6e58840a53e71e8e508ae39f14ebfa693e4b8",
7
+ "kibi-usage/resources/operation-access.md": "d8653b544305d4c00734c737b1156110208a9a82fbec6b04726d25b973f2b840",
8
+ "kibi-usage/resources/relationship-directions.md": "aecbde048bb84e210318e4aca98e07f8370168c640c3a9d65696d2195c8598ec",
9
+ "kibi-usage/resources/workflows.md": "36e50fe83fc7ac6bc68fcf51d2c2175e09c68815b6bbebed8cfa1d5611617913"
10
+ }
@@ -1,23 +1,62 @@
1
1
  ---
2
+ id: init-kibi
2
3
  name: init-kibi
3
4
  description: Bootstrap and model knowledge safely using approved Kibi MCP initialization and mutation workflow.
5
+ version: 1.0.0
6
+ kibiCompatibility: "*"
7
+ tags:
8
+ - kibi
9
+ - mcp
10
+ - bootstrap
11
+ - agent-guidance
4
12
  ---
5
-
6
13
  ## Goal
7
14
 
8
- Set up or refresh Kibi knowledge for the current branch without manual filesystem edits.
15
+ Set up or refresh Kibi knowledge for the current branch through approved Kibi interfaces only. Maintain source-file traceability for every repository-backed claim, and require explicit operator approval before any mutation.
16
+
17
+ ## Interface Selection
18
+
19
+ 1. If approved Kibi MCP tools are visible, use the MCP route.
20
+ 2. Otherwise, in a trusted workspace, use the canonical project-local CLI fallback: `npx --no-install kibi ...` or `bunx --no-install kibi ...`.
21
+ 3. If neither approved MCP tools nor the project-local CLI are available, stop and tell the operator to enable or install Kibi for this workspace.
22
+ 4. Never use a global fallback, an installing runner, or any route outside the approved Kibi interface.
23
+
24
+ Use `kibi-usage/resources/operation-access.md` for the exact operation-to-route mapping. The CLI preview route accepts the same JSON object as `kb_autopilot_generate`:
25
+
26
+ ```bash
27
+ echo '{"maxCandidates":25,"minConfidence":0.8}' | npx --no-install kibi autopilot-generate --input -
28
+ ```
9
29
 
10
- ## MCP workflow
30
+ ## Capability Workflow
11
31
 
12
- - Run `kb_autopilot_generate` for suggested initial facts and claims.
13
- - Show the generated preview and get explicit approval before writes.
14
- - Use `kb_upsert` for reviewed entity creation or updates.
15
- - If cleanup is needed, use `kb_delete` only after checking dependencies.
16
- - Finish with `kb_check` to validate the branch snapshot.
32
+ - Generate a read-only bootstrap preview with `kb_autopilot_generate`, or the dedicated CLI route `autopilot-generate --input`.
33
+ - Show the generated preview and obtain explicit approval before writes.
34
+ - Apply reviewed entity creation or updates with `kb_upsert`, or `upsert --input`.
35
+ - If cleanup is needed, use `kb_delete`, or `delete --input`, only after checking dependencies and obtaining approval for the specific removal.
36
+ - Finish with `kb_check`, or `check --input`, to validate the branch snapshot.
17
37
 
18
38
  ## Guidance
19
39
 
20
- - Keep mutation requests explicit and small.
21
- - Use source-linked entities where possible so future `kb_query` lookups can verify context.
22
- - Do not edit `.kb/**` files directly; all changes go through MCP calls.
40
+ - Keep mutation requests explicit, small, and sequential.
41
+ - Prefer source-linked entities so future `kb_query` lookups can verify repository context against source files.
42
+ - Preserve traceability by linking facts, claims, scenarios, and tests to concrete project files whenever repository evidence supports it.
43
+ - Do not read or edit files inside `.kb` directly; all changes go through the selected Kibi interface.
23
44
  - Ask at most four bounded context questions, and only when repository evidence is insufficient.
45
+ - Stop at the documented operator repair boundary if the setup appears partial, inconsistent, or unsupported by the approved interface.
46
+
47
+ ## Public Training Trajectories
48
+
49
+ - `init-kibi-bootstrap-analysis-train-1`: Analyze the cold-start repository and produce a read-only bootstrap preview using only the public Kibi MCP surface.
50
+ - `init-kibi-bootstrap-analysis-train-2`: Analyze the cold-start repository and produce a read-only bootstrap preview using only the public Kibi MCP surface.
51
+ - `init-kibi-bounded-context-questions-train-1`: Ask only the bounded context questions needed before bootstrap synthesis using only the public Kibi MCP surface.
52
+ - `init-kibi-bounded-context-questions-train-2`: Ask only the bounded context questions needed before bootstrap synthesis using only the public Kibi MCP surface.
53
+ - `init-kibi-approval-sequential-writes-train-1`: Apply the approved bootstrap plan sequentially and finish with validation using only the public Kibi MCP surface.
54
+ - `init-kibi-approval-sequential-writes-train-2`: Apply the approved bootstrap plan sequentially and finish with validation using only the public Kibi MCP surface.
55
+ - `init-kibi-repair-escalation-train-1`: Identify the partial setup and stop at the documented operator repair boundary using only the public Kibi MCP surface.
56
+ - `init-kibi-repair-escalation-train-2`: Identify the partial setup and stop at the documented operator repair boundary using only the public Kibi MCP surface.
57
+
58
+ ## Training Data
59
+
60
+ ```json
61
+ [{"taskId":"init-kibi-bootstrap-analysis-train-1","family":"bootstrap-analysis","reflection":"Analyze the cold-start repository and produce a read-only bootstrap preview. This is train case 1; use only the public Kibi MCP surface."},{"taskId":"init-kibi-bootstrap-analysis-train-2","family":"bootstrap-analysis","reflection":"Analyze the cold-start repository and produce a read-only bootstrap preview. This is train case 2; use only the public Kibi MCP surface."},{"taskId":"init-kibi-bounded-context-questions-train-1","family":"bounded-context-questions","reflection":"Ask only the bounded context questions needed before bootstrap synthesis. This is train case 1; use only the public Kibi MCP surface."},{"taskId":"init-kibi-bounded-context-questions-train-2","family":"bounded-context-questions","reflection":"Ask only the bounded context questions needed before bootstrap synthesis. This is train case 2; use only the public Kibi MCP surface."},{"taskId":"init-kibi-approval-sequential-writes-train-1","family":"approval-sequential-writes","reflection":"Apply the approved bootstrap plan sequentially and finish with validation. This is train case 1; use only the public Kibi MCP surface."},{"taskId":"init-kibi-approval-sequential-writes-train-2","family":"approval-sequential-writes","reflection":"Apply the approved bootstrap plan sequentially and finish with validation. This is train case 2; use only the public Kibi MCP surface."},{"taskId":"init-kibi-repair-escalation-train-1","family":"repair-escalation","reflection":"Identify the partial setup and stop at the documented operator repair boundary. This is train case 1; use only the public Kibi MCP surface."},{"taskId":"init-kibi-repair-escalation-train-2","family":"repair-escalation","reflection":"Identify the partial setup and stop at the documented operator repair boundary. This is train case 2; use only the public Kibi MCP surface."}]
62
+ ```
@@ -1,22 +1,44 @@
1
1
  ---
2
+ id: kibi-freshness
2
3
  name: kibi-freshness
3
4
  description: Check branch freshness and source linkage quality before decisions or risky writes.
5
+ version: 1.0.0
6
+ kibiCompatibility: "*"
7
+ tags:
8
+ - kibi
9
+ - mcp
10
+ - freshness
11
+ - agent-guidance
4
12
  ---
5
-
6
13
  ## Goal
7
14
 
8
- Help agents decide whether KB context is current enough to support safe changes.
15
+ Help agents decide whether Kibi knowledge is current enough to support safe changes while preserving source-file traceability and approved interface boundaries.
16
+
17
+ ## Interface Selection
18
+
19
+ 1. If Kibi MCP tools are visible and approved for the workspace, use the MCP surface only.
20
+ 2. Otherwise, in a trusted workspace, use the canonical project-local CLI fallback through `npx --no-install kibi ...` or `bunx --no-install kibi ...`.
21
+ 3. If the project-local CLI is unavailable or too old, stop and tell the operator to enable or install Kibi.
22
+ 4. Never use a global fallback or an installing runner.
23
+
24
+ Use `kibi-usage/resources/operation-access.md` for exact dedicated routes. A project-local CLI freshness check is executable as:
25
+
26
+ ```bash
27
+ echo '{}' | npx --no-install kibi status --input -
28
+ ```
9
29
 
10
- ## MCP workflow
30
+ ## Capability Workflow
11
31
 
12
- - Use `kb_status` first to confirm branch attachment and freshness state.
13
- - Use `kb_query` with `sourceFile`/text refs for source-linked discovery.
14
- - Re-run `kb_search` after sync gaps are detected.
15
- - If knowledge must change, update it with `kb_upsert` or `kb_delete` and finish with `kb_check`.
32
+ - Use `kb_status`, or `status --input`, first to confirm branch attachment, freshness state, dirty-worktree evidence, and whether the knowledge snapshot is safe to rely on.
33
+ - Use `kb_query`, or `query --input`, with `sourceFile` and text references for source-linked discovery.
34
+ - Re-run `kb_search`, or `search --input`, after sync gaps or stale context are detected.
35
+ - If knowledge must change, use the selected interface's `kb_upsert`/`upsert` or `kb_delete`/`delete` operation sequentially, then finish with `kb_check`/`check`.
16
36
 
17
37
  ## Guidance
18
38
 
39
+ - Prefer the public Kibi MCP surface whenever it is available and approved.
19
40
  - Never proceed with broad changes when freshness is stale and unresolved.
20
- - If entities look stale, prefer refreshing context via MCP flows and then re-query.
21
- - Avoid direct `.kb` editing; use `kb_status` and other MCP checks instead.
22
- - Completion must state one freshness outcome: KB updated, no KB impact with rationale, or deferred/failed.
41
+ - If entities look stale, refresh context through an approved Kibi capability and then re-query.
42
+ - Preserve source-file traceability by carrying `sourceFile`, text references, and validation evidence through discovery, mutation, and completion.
43
+ - Do not read or edit files inside `.kb` directly; use the selected Kibi interface instead.
44
+ - Completion must state one freshness outcome: KB updated, no KB impact with rationale, or deferred/failed.