@vodailoc/kilo-kit-mcp 1.2.0 β 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -6
- package/mcp/README.md +10 -9
- package/mcp/dist/formatters.js +5 -7
- package/mcp/dist/orchestrator.js +20 -31
- package/mcp/dist/server.js +5 -3
- package/mcp/dist/smoke.js +10 -13
- package/mcp/package.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
|
|
24
24
|
# π Kilo-Kit: Professional AI Agent Development Framework
|
|
25
25
|
|
|
26
|
-
> **Version:** 1.
|
|
27
|
-
> **Author:** Kilo-Kit Team
|
|
26
|
+
> **Version:** 1.3.0
|
|
27
|
+
> **Author:** Kilo-Kit Team
|
|
28
28
|
> **License:** Apache 2.0
|
|
29
29
|
|
|
30
30
|
## π― What is Kilo-Kit?
|
|
@@ -196,11 +196,11 @@ Skills are automatically loaded when your task matches their keywords. See the [
|
|
|
196
196
|
|
|
197
197
|
## π MCP Integration
|
|
198
198
|
|
|
199
|
-
Kilo-Kit v1.
|
|
199
|
+
Kilo-Kit v1.3.0 includes a read-only MCP server that exposes the skill library as an adaptive routing service for MCP-capable agents.
|
|
200
200
|
|
|
201
201
|
| MCP Surface | Purpose |
|
|
202
202
|
|-------------|---------|
|
|
203
|
-
| `kilo_orchestrate_task` | C4 central gate:
|
|
203
|
+
| `kilo_orchestrate_task` | C4 central gate: require the real `/brainstorming` skill first, then log/route the approved task and release the post-brainstorming workflow |
|
|
204
204
|
| `kilo_route_intent` | Route the current chat request to skills, workflow order, rule hierarchy, and decision trail |
|
|
205
205
|
| `kilo_search_skills` | Search the skill catalog by task or keyword |
|
|
206
206
|
| `kilo_get_skill` | Load one exact `SKILL.md` with context-safe truncation |
|
|
@@ -277,7 +277,7 @@ Kilo-Kit publishes `@vodailoc/kilo-kit-mcp` through npm Trusted Publishing. Conf
|
|
|
277
277
|
| Repository | `VoDaiLocz/KILO-KIT` |
|
|
278
278
|
| Workflow filename | `publish.yml` |
|
|
279
279
|
|
|
280
|
-
After that, run the GitHub Actions workflow `Publish npm package`, or push a version tag such as `v1.
|
|
280
|
+
After that, run the GitHub Actions workflow `Publish npm package`, or push a version tag such as `v1.3.0`. The workflow uses OIDC, so it does not need an npm token or interactive OTP.
|
|
281
281
|
|
|
282
282
|
## π Skill Dispatch Table
|
|
283
283
|
|
|
@@ -435,7 +435,8 @@ We welcome contributions! Please read [CONTRIBUTING.md](./CONTRIBUTING.md) for:
|
|
|
435
435
|
|
|
436
436
|
- [x] v1.0.0 - Core Cognitive Flow Architecture
|
|
437
437
|
- [x] v1.1.0 - MCP Integration
|
|
438
|
-
- [
|
|
438
|
+
- [x] v1.2.0 - Multi-Agent Orchestration
|
|
439
|
+
- [x] v1.3.0 - Primary Brainstorming Gate for C4
|
|
439
440
|
- [ ] v2.0.0 - Visual Workflow Builder
|
|
440
441
|
|
|
441
442
|
## π License
|
package/mcp/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# π Kilo-Kit MCP Server
|
|
2
2
|
|
|
3
|
-
> **Version:** 1.
|
|
3
|
+
> **Version:** 1.3.0
|
|
4
4
|
> **Mode:** Read-only Skill Registry + Validator
|
|
5
5
|
> **Transport:** stdio
|
|
6
6
|
|
|
@@ -12,7 +12,7 @@ The Kilo-Kit MCP server exposes the `skills/` workflow surface to MCP-capable ag
|
|
|
12
12
|
|
|
13
13
|
| Capability | MCP Tool | Purpose |
|
|
14
14
|
|------------|----------|---------|
|
|
15
|
-
| C4 orchestration | `kilo_orchestrate_task` |
|
|
15
|
+
| C4 orchestration | `kilo_orchestrate_task` | Require the real `/brainstorming` skill before substantive work, then log/route the approved task and release the post-brainstorming workflow |
|
|
16
16
|
| Skill discovery | `kilo_search_skills` | Search the skill library by task/query |
|
|
17
17
|
| Intent routing | `kilo_route_intent` | Recommend skills, workflow order, rule hierarchy, and decision trail for the current chat context |
|
|
18
18
|
| Skill loading | `kilo_get_skill` | Load one exact `SKILL.md` with output limits |
|
|
@@ -91,7 +91,7 @@ KILO_KIT_MEMORY_PATH=/absolute/path/orchestrator.sqlite
|
|
|
91
91
|
KILO_KIT_ORCHESTRATION_AUDIT_PATH=/absolute/path/orchestration-audit.jsonl
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
-
`kilo_orchestrate_task` uses the C4 Brainstorming-First Gate
|
|
94
|
+
`kilo_orchestrate_task` uses the C4 Brainstorming-First Gate as a skill gate, not a separate C4 questionnaire. Substantive work starts by loading and following `productivity/brainstorming`. After the user approves the brainstorming direction, call `kilo_orchestrate_task` again with `brainstormingApproved=true`; C4 then checks memory suggestions and releases the post-brainstorming workflow.
|
|
95
95
|
|
|
96
96
|
### Codex CLI on Windows
|
|
97
97
|
|
|
@@ -120,8 +120,8 @@ Configure the npm package once:
|
|
|
120
120
|
Then publish by running the GitHub Actions workflow `Publish npm package`, or by pushing a version tag:
|
|
121
121
|
|
|
122
122
|
```bash
|
|
123
|
-
git tag v1.
|
|
124
|
-
git push origin v1.
|
|
123
|
+
git tag v1.3.0
|
|
124
|
+
git push origin v1.3.0
|
|
125
125
|
```
|
|
126
126
|
|
|
127
127
|
The workflow runs build, typecheck, tests, smoke, skill validation, package dry-run, and then `npm publish --access public --ignore-scripts` through OIDC.
|
|
@@ -173,10 +173,11 @@ Use `.mcp/kilo-kit.example.json` as the portable template.
|
|
|
173
173
|
|
|
174
174
|
```text
|
|
175
175
|
User request
|
|
176
|
-
β
|
|
177
|
-
β
|
|
178
|
-
β
|
|
179
|
-
β
|
|
176
|
+
β kilo_get_skill(productivity, brainstorming)
|
|
177
|
+
β follow the real /brainstorming hard gate and get user approval
|
|
178
|
+
β kilo_orchestrate_task(message, context, brainstormingApproved=true)
|
|
179
|
+
β accept/reject memory suggestions when relevant
|
|
180
|
+
β kilo_get_skill(category, skill) for the first post-brainstorming workflow skill
|
|
180
181
|
β follow final workflow skills in order
|
|
181
182
|
β kilo_route_report when you need routing analytics
|
|
182
183
|
β kilo_memory_report when you need memory analytics
|
package/mcp/dist/formatters.js
CHANGED
|
@@ -137,11 +137,9 @@ export function formatOrchestration(result, format) {
|
|
|
137
137
|
if (format === "json") {
|
|
138
138
|
return JSON.stringify(result, null, 2);
|
|
139
139
|
}
|
|
140
|
-
const
|
|
141
|
-
?
|
|
142
|
-
|
|
143
|
-
.join("\n")
|
|
144
|
-
: "No questions required.";
|
|
140
|
+
const brainstormingGate = result.state === "brainstorming_required"
|
|
141
|
+
? "Load `productivity/brainstorming` and follow the real skill hard-gate. C4 questions are not used as a separate questionnaire."
|
|
142
|
+
: "Brainstorming approval has been recorded or this is a read-only route.";
|
|
145
143
|
const workflow = result.workflow.length > 0
|
|
146
144
|
? result.workflow.map((step, index) => `${index + 1}. **${step.skill.id}** (${step.role})\n ${step.reason}`).join("\n")
|
|
147
145
|
: "No workflow selected.";
|
|
@@ -160,8 +158,8 @@ export function formatOrchestration(result, format) {
|
|
|
160
158
|
`State: \`${result.state}\``,
|
|
161
159
|
`Task mode: \`${result.taskMode}\``,
|
|
162
160
|
"",
|
|
163
|
-
"##
|
|
164
|
-
|
|
161
|
+
"## Brainstorming Gate",
|
|
162
|
+
brainstormingGate,
|
|
165
163
|
"",
|
|
166
164
|
"## Workflow",
|
|
167
165
|
workflow,
|
package/mcp/dist/orchestrator.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { createNoopOrchestrationAudit } from "./orchestration-audit.js";
|
|
3
|
-
import { selectQuestionTemplate } from "./question-templates.js";
|
|
4
3
|
import { routeIntent } from "./router.js";
|
|
5
4
|
export function createOrchestrator(options) {
|
|
6
5
|
const sessions = new Map();
|
|
@@ -9,18 +8,18 @@ export function createOrchestrator(options) {
|
|
|
9
8
|
orchestrate(input) {
|
|
10
9
|
const session = getOrCreateSession(sessions, options.registry, input);
|
|
11
10
|
mergeInput(session, input);
|
|
12
|
-
const missingInfo =
|
|
11
|
+
const missingInfo = [];
|
|
13
12
|
const suggestions = ensureMemorySuggestions(options.memory, session);
|
|
14
13
|
const pendingSuggestions = suggestions.filter((suggestion) => session.memoryConfirmations[suggestion.key] === undefined);
|
|
15
14
|
const acceptedSuggestions = suggestions.filter((suggestion) => session.memoryConfirmations[suggestion.key] === "accepted");
|
|
16
|
-
const state = selectState(session,
|
|
15
|
+
const state = selectState(session, pendingSuggestions);
|
|
17
16
|
for (const [suggestionKey, decision] of Object.entries(input.memoryConfirmations ?? {})) {
|
|
18
17
|
options.memory.recordDecision({ suggestionKey, decision });
|
|
19
18
|
}
|
|
20
19
|
const verificationGate = buildVerificationGate(acceptedSuggestions);
|
|
21
|
-
const finalWorkflow = state === "ready" ? session
|
|
22
|
-
const firstSkillToLoad = finalWorkflow?.[0]?.skill;
|
|
23
|
-
const nextAction = buildNextAction(state, session,
|
|
20
|
+
const finalWorkflow = state === "ready" ? executableWorkflow(session) : undefined;
|
|
21
|
+
const firstSkillToLoad = state === "brainstorming_required" ? findSkillById(options.registry, "productivity/brainstorming") : finalWorkflow?.[0]?.skill;
|
|
22
|
+
const nextAction = buildNextAction(state, session, pendingSuggestions, firstSkillToLoad);
|
|
24
23
|
persistSession(options.memory, session, state, verificationGate, finalWorkflow);
|
|
25
24
|
const auditRef = audit.record({
|
|
26
25
|
sessionId: session.sessionId,
|
|
@@ -34,7 +33,7 @@ export function createOrchestrator(options) {
|
|
|
34
33
|
state,
|
|
35
34
|
message: session.message,
|
|
36
35
|
taskMode: session.route.taskMode,
|
|
37
|
-
questions:
|
|
36
|
+
questions: [],
|
|
38
37
|
missingInfo,
|
|
39
38
|
route: session.route,
|
|
40
39
|
workflow: session.workflow,
|
|
@@ -66,18 +65,13 @@ function getOrCreateSession(sessions, registry, input) {
|
|
|
66
65
|
limit: 5,
|
|
67
66
|
});
|
|
68
67
|
const workflow = ensureBrainstormingFirst(registry, route.workflow, input);
|
|
69
|
-
const template = selectQuestionTemplate({
|
|
70
|
-
taskMode: route.taskMode,
|
|
71
|
-
workflowSkillIds: workflow.map((step) => step.skill.id),
|
|
72
|
-
recommendedSkillIds: route.recommended.map((item) => item.skill.id),
|
|
73
|
-
});
|
|
74
68
|
const session = {
|
|
75
69
|
sessionId: input.sessionId ?? randomUUID(),
|
|
76
70
|
message: input.message,
|
|
77
71
|
createdAt: new Date().toISOString(),
|
|
78
72
|
route,
|
|
79
73
|
workflow,
|
|
80
|
-
|
|
74
|
+
brainstormingApproved: input.brainstormingApproved === true,
|
|
81
75
|
answers: {},
|
|
82
76
|
memorySuggestions: [],
|
|
83
77
|
memoryConfirmations: {},
|
|
@@ -94,7 +88,7 @@ function persistSession(memory, session, state, verificationGate, finalWorkflow)
|
|
|
94
88
|
message: session.message,
|
|
95
89
|
taskMode: session.route.taskMode,
|
|
96
90
|
route: toJsonObject(session.route),
|
|
97
|
-
questions:
|
|
91
|
+
questions: [],
|
|
98
92
|
answers: { ...session.answers },
|
|
99
93
|
memorySuggestions: session.memorySuggestions.map((suggestion) => ({ ...suggestion })),
|
|
100
94
|
finalWorkflow: toJsonArray(finalWorkflow ?? []),
|
|
@@ -116,6 +110,7 @@ function persistSession(memory, session, state, verificationGate, finalWorkflow)
|
|
|
116
110
|
function mergeInput(session, input) {
|
|
117
111
|
session.message = input.message || session.message;
|
|
118
112
|
session.answers = { ...session.answers, ...(input.answers ?? {}) };
|
|
113
|
+
session.brainstormingApproved = session.brainstormingApproved || input.brainstormingApproved === true;
|
|
119
114
|
session.memoryConfirmations = { ...session.memoryConfirmations, ...(input.memoryConfirmations ?? {}) };
|
|
120
115
|
if (input.context) {
|
|
121
116
|
session.context = input.context;
|
|
@@ -132,13 +127,10 @@ function ensureMemorySuggestions(memory, session) {
|
|
|
132
127
|
});
|
|
133
128
|
return session.memorySuggestions;
|
|
134
129
|
}
|
|
135
|
-
function selectState(session,
|
|
136
|
-
if (isSubstantiveWork(session) &&
|
|
130
|
+
function selectState(session, pendingSuggestions) {
|
|
131
|
+
if (isSubstantiveWork(session) && !session.brainstormingApproved) {
|
|
137
132
|
return "brainstorming_required";
|
|
138
133
|
}
|
|
139
|
-
if (missingInfo.length > 0) {
|
|
140
|
-
return "questioning";
|
|
141
|
-
}
|
|
142
134
|
if (pendingSuggestions.length > 0) {
|
|
143
135
|
return "awaiting_memory_confirmation";
|
|
144
136
|
}
|
|
@@ -153,7 +145,7 @@ function ensureBrainstormingFirst(registry, workflow, input) {
|
|
|
153
145
|
const step = {
|
|
154
146
|
skill: brainstorming,
|
|
155
147
|
role: "prepare",
|
|
156
|
-
reason: "
|
|
148
|
+
reason: "Load and follow the real /brainstorming skill before substantive work.",
|
|
157
149
|
};
|
|
158
150
|
if (input.context?.mode === "brainstorming" || /\bbrainstorm(?:ing)?\b/i.test(input.message)) {
|
|
159
151
|
return [step, ...existing];
|
|
@@ -175,12 +167,6 @@ function findSkillById(registry, id) {
|
|
|
175
167
|
return undefined;
|
|
176
168
|
}
|
|
177
169
|
}
|
|
178
|
-
function missingRequiredQuestionIds(questions, answers) {
|
|
179
|
-
return questions
|
|
180
|
-
.filter((question) => question.required)
|
|
181
|
-
.filter((question) => !answers[question.id]?.trim())
|
|
182
|
-
.map((question) => question.id);
|
|
183
|
-
}
|
|
184
170
|
function buildVerificationGate(acceptedSuggestions) {
|
|
185
171
|
const commands = acceptedSuggestions.flatMap((suggestion) => {
|
|
186
172
|
const commands = suggestion.value.commands;
|
|
@@ -193,12 +179,9 @@ function buildVerificationGate(acceptedSuggestions) {
|
|
|
193
179
|
: "Default MCP verification gate for C4 orchestration.",
|
|
194
180
|
};
|
|
195
181
|
}
|
|
196
|
-
function buildNextAction(state, session,
|
|
182
|
+
function buildNextAction(state, session, pendingSuggestions, firstSkillToLoad) {
|
|
197
183
|
if (state === "brainstorming_required") {
|
|
198
|
-
return
|
|
199
|
-
}
|
|
200
|
-
if (state === "questioning") {
|
|
201
|
-
return `Answer missing C4 questions before workflow execution: ${missingInfo.join(", ")}.`;
|
|
184
|
+
return "Load productivity/brainstorming with kilo_get_skill, follow its hard-gate, get user approval, then call kilo_orchestrate_task again with brainstormingApproved=true.";
|
|
202
185
|
}
|
|
203
186
|
if (state === "awaiting_memory_confirmation") {
|
|
204
187
|
return `Accept or reject memory suggestions before execution: ${pendingSuggestions.map((item) => item.key).join(", ")}.`;
|
|
@@ -208,6 +191,12 @@ function buildNextAction(state, session, missingInfo, pendingSuggestions, firstS
|
|
|
208
191
|
}
|
|
209
192
|
return session.route.nextAction;
|
|
210
193
|
}
|
|
194
|
+
function executableWorkflow(session) {
|
|
195
|
+
if (!session.brainstormingApproved) {
|
|
196
|
+
return session.workflow;
|
|
197
|
+
}
|
|
198
|
+
return session.workflow.filter((step) => step.skill.id !== "productivity/brainstorming");
|
|
199
|
+
}
|
|
211
200
|
function isSubstantiveWork(session) {
|
|
212
201
|
return !isReadOnlyRequest(session.message);
|
|
213
202
|
}
|
package/mcp/dist/server.js
CHANGED
|
@@ -15,7 +15,7 @@ import { createInMemoryRouteAnalytics, createJsonlRouteAnalytics } from "./route
|
|
|
15
15
|
import { createSkillRegistry } from "./registry.js";
|
|
16
16
|
import { routeIntent } from "./router.js";
|
|
17
17
|
import { validateSkills } from "./validator.js";
|
|
18
|
-
const SERVER_VERSION = "1.
|
|
18
|
+
const SERVER_VERSION = "1.3.0";
|
|
19
19
|
const DEFAULT_REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
|
20
20
|
const formatSchema = z.enum(["markdown", "json"]).default("markdown");
|
|
21
21
|
export async function createKiloKitServer(options = {}) {
|
|
@@ -47,7 +47,7 @@ export async function createKiloKitServer(options = {}) {
|
|
|
47
47
|
});
|
|
48
48
|
server.registerTool("kilo_orchestrate_task", {
|
|
49
49
|
title: "Kilo-Kit C4 Orchestrate Task",
|
|
50
|
-
description: "Central C4 orchestration gate. Routes internally,
|
|
50
|
+
description: "Central C4 orchestration gate. Routes internally, requires the real /brainstorming skill before substantive work, checks memory suggestions, and releases the post-brainstorming workflow after approval.",
|
|
51
51
|
inputSchema: {
|
|
52
52
|
message: z.string().min(1).max(4000).describe("Current user request or task summary."),
|
|
53
53
|
context: z
|
|
@@ -59,6 +59,7 @@ export async function createKiloKitServer(options = {}) {
|
|
|
59
59
|
})
|
|
60
60
|
.optional(),
|
|
61
61
|
sessionId: z.string().min(1).max(120).optional(),
|
|
62
|
+
brainstormingApproved: z.boolean().optional(),
|
|
62
63
|
answers: z.record(z.string().max(2000)).optional(),
|
|
63
64
|
memoryConfirmations: z.record(z.enum(["accepted", "rejected"])).optional(),
|
|
64
65
|
format: formatSchema.optional(),
|
|
@@ -68,7 +69,7 @@ export async function createKiloKitServer(options = {}) {
|
|
|
68
69
|
destructiveHint: false,
|
|
69
70
|
idempotentHint: false,
|
|
70
71
|
},
|
|
71
|
-
}, async ({ message, context, sessionId, answers, memoryConfirmations, format }) => {
|
|
72
|
+
}, async ({ message, context, sessionId, brainstormingApproved, answers, memoryConfirmations, format }) => {
|
|
72
73
|
const result = orchestrator.orchestrate({
|
|
73
74
|
message,
|
|
74
75
|
...(context
|
|
@@ -82,6 +83,7 @@ export async function createKiloKitServer(options = {}) {
|
|
|
82
83
|
}
|
|
83
84
|
: {}),
|
|
84
85
|
...(sessionId ? { sessionId } : {}),
|
|
86
|
+
...(brainstormingApproved !== undefined ? { brainstormingApproved } : {}),
|
|
85
87
|
...(answers ? { answers } : {}),
|
|
86
88
|
...(memoryConfirmations ? { memoryConfirmations } : {}),
|
|
87
89
|
});
|
package/mcp/dist/smoke.js
CHANGED
|
@@ -59,31 +59,28 @@ try {
|
|
|
59
59
|
if (orchestrationResult.workflow?.[0]?.skill?.id !== "productivity/brainstorming") {
|
|
60
60
|
throw new Error(`Smoke orchestration did not start with brainstorming: ${orchestrationText}`);
|
|
61
61
|
}
|
|
62
|
-
if (
|
|
63
|
-
throw new Error(`Smoke orchestration did not
|
|
62
|
+
if (orchestrationResult.firstSkillToLoad?.id !== "productivity/brainstorming") {
|
|
63
|
+
throw new Error(`Smoke orchestration did not instruct loading brainstorming: ${orchestrationText}`);
|
|
64
|
+
}
|
|
65
|
+
if ((orchestrationResult.questions?.length ?? 0) !== 0 || (orchestrationResult.missingInfo?.length ?? 0) !== 0) {
|
|
66
|
+
throw new Error(`Smoke orchestration should not use C4 questions as a gate: ${orchestrationText}`);
|
|
64
67
|
}
|
|
65
68
|
const readyOrchestration = await client.callTool({
|
|
66
69
|
name: "kilo_orchestrate_task",
|
|
67
70
|
arguments: {
|
|
68
71
|
message: "Fix bug login, viαΊΏt test trΖ°α»c",
|
|
69
72
|
sessionId: orchestrationResult.sessionId,
|
|
70
|
-
|
|
71
|
-
goal: "Fix login failure",
|
|
72
|
-
scope: "src/auth/login.ts",
|
|
73
|
-
success_criteria: "login test passes",
|
|
74
|
-
failing_behavior: "valid credentials are rejected",
|
|
75
|
-
test_command: "npm test -- login",
|
|
76
|
-
},
|
|
73
|
+
brainstormingApproved: true,
|
|
77
74
|
format: "json",
|
|
78
75
|
},
|
|
79
76
|
});
|
|
80
77
|
const readyText = extractFirstText(readyOrchestration);
|
|
81
78
|
const readyResult = JSON.parse(readyText);
|
|
82
|
-
if (readyResult.state !== "ready" || readyResult.firstSkillToLoad?.id !== "
|
|
83
|
-
throw new Error(`Smoke orchestration did not release
|
|
79
|
+
if (readyResult.state !== "ready" || readyResult.firstSkillToLoad?.id !== "engineering/diagnose") {
|
|
80
|
+
throw new Error(`Smoke orchestration did not release post-brainstorming workflow after approval: ${readyText}`);
|
|
84
81
|
}
|
|
85
|
-
if (readyResult.finalWorkflow?.
|
|
86
|
-
throw new Error(`Smoke final workflow
|
|
82
|
+
if (readyResult.finalWorkflow?.some((step) => step.skill?.id === "productivity/brainstorming")) {
|
|
83
|
+
throw new Error(`Smoke final workflow should not repeat brainstorming after approval: ${readyText}`);
|
|
87
84
|
}
|
|
88
85
|
const memoryReport = await client.callTool({
|
|
89
86
|
name: "kilo_memory_report",
|
package/mcp/package.json
CHANGED