@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 CHANGED
@@ -23,8 +23,8 @@
23
23
 
24
24
  # πŸš€ Kilo-Kit: Professional AI Agent Development Framework
25
25
 
26
- > **Version:** 1.0.0
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.2.0 includes a read-only MCP server that exposes the skill library as an adaptive routing service for MCP-capable agents.
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: route internally, require brainstorming, ask questions, check memory, and release final workflow |
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.2.0`. The workflow uses OIDC, so it does not need an npm token or interactive OTP.
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
- - [ ] v1.2.0 - Multi-Agent Orchestration
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.2.0
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` | Enforce brainstorming-first workflow, required questions, memory suggestions, and final workflow release |
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: substantive work starts with `productivity/brainstorming`, then required questions, then memory suggestions that require explicit accept/reject before a final workflow is released.
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.2.0
124
- git push origin v1.2.0
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
- β†’ kilo_orchestrate_task(message, context)
177
- β†’ answer required C4 questions
178
- β†’ accept/reject memory suggestions
179
- β†’ kilo_get_skill(category, skill) for the first workflow skill
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
@@ -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 questions = result.questions.length > 0
141
- ? result.questions
142
- .map((question, index) => `${index + 1}. **${question.id}**${question.required ? " (required)" : ""}\n ${question.prompt}`)
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
- "## Questions",
164
- questions,
161
+ "## Brainstorming Gate",
162
+ brainstormingGate,
165
163
  "",
166
164
  "## Workflow",
167
165
  workflow,
@@ -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 = missingRequiredQuestionIds(session.questions, session.answers);
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, missingInfo, pendingSuggestions);
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.workflow : undefined;
22
- const firstSkillToLoad = finalWorkflow?.[0]?.skill;
23
- const nextAction = buildNextAction(state, session, missingInfo, pendingSuggestions, firstSkillToLoad);
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: session.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
- questions: template.questions,
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: toJsonArray(session.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, missingInfo, pendingSuggestions) {
136
- if (isSubstantiveWork(session) && Object.keys(session.answers).length === 0) {
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: "C4 Brainstorming-First Gate requires design clarification before substantive work.",
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, missingInfo, pendingSuggestions, firstSkillToLoad) {
182
+ function buildNextAction(state, session, pendingSuggestions, firstSkillToLoad) {
197
183
  if (state === "brainstorming_required") {
198
- return `Start with productivity/brainstorming and answer required C4 questions: ${missingInfo.join(", ")}.`;
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
  }
@@ -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.2.0";
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, enforces brainstorming-first, asks required questions, checks memory suggestions, and releases a final workflow only after confirmation.",
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 (!orchestrationResult.questions?.some((question) => question.id === "test_command" || question.skillId === "engineering/tdd")) {
63
- throw new Error(`Smoke orchestration did not include TDD questions: ${orchestrationText}`);
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
- answers: {
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 !== "productivity/brainstorming") {
83
- throw new Error(`Smoke orchestration did not release final workflow after answers: ${readyText}`);
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?.[0]?.skill?.id !== "productivity/brainstorming") {
86
- throw new Error(`Smoke final workflow did not start with brainstorming: ${readyText}`);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kilo-kit/mcp",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Kilo-Kit MCP server for skill routing, skill loading, and validation.",
5
5
  "type": "module",
6
6
  "private": true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vodailoc/kilo-kit-mcp",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Kilo-Kit MCP server for adaptive skill routing, skill loading, and validation.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Kilo-Kit Team",