kanbango 2.4.0 → 2.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.
- package/.ai/lessons.jsonl +0 -0
- package/.ai/retro/close.json +1 -0
- package/.ai/retro/last-run.json +1 -0
- package/CHANGELOG.md +7 -0
- package/LLM_AGENTS.md +43 -16
- package/kanban.js +43 -0
- package/mcp-server.js +25 -11
- package/package.json +1 -1
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"goal":"push do npm","done":["session had mutations"],"next":[],"block":[],"lessons":[],"files":["/Users/mkorbas/projects/personal/markdown-kanban/mcp-server.js","/Users/mkorbas/projects/personal/markdown-kanban/kanban.js","/Users/mkorbas/projects/personal/markdown-kanban/tests/mcp-server.test.js","/Users/mkorbas/projects/personal/markdown-kanban/plan.js","/Users/mkorbas/projects/personal/markdown-kanban/CHANGELOG.md","/Users/mkorbas/projects/personal/markdown-kanban/bin/kanban.js","/Users/mkorbas/projects/personal/markdown-kanban/tests/update-tasks.test.js"],"verify":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"ts":"2026-07-29T09:29:19.070Z","sessionID":"ses_05beb2173ffe1rCJQhZBUHuLgs","added":[],"bumped":[],"error":"llm-parse-fallback"}
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,13 @@ All notable changes to kanbango will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.5.0] - 2026-07-27
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- Create field policy: only `title` is hard-required; `description`, `specs`, `in_scope`, `out_of_scope`, and `acceptance_criteria` are strongly recommended
|
|
12
|
+
- MCP `kanban_manage` create/plan_create returns `warnings` + `missing_recommended` when recommended fields are omitted (still succeeds)
|
|
13
|
+
- MCP tool descriptions and LLM agent docs push agents to always fill planning boundaries
|
|
14
|
+
|
|
8
15
|
## [2.4.0] - 2026-07-27
|
|
9
16
|
|
|
10
17
|
### Added
|
package/LLM_AGENTS.md
CHANGED
|
@@ -146,20 +146,22 @@ Create, move, or patch-update kanban tasks. Single tool for all mutations.
|
|
|
146
146
|
```json
|
|
147
147
|
{
|
|
148
148
|
"action": "create",
|
|
149
|
-
"title": "New feature", // Required
|
|
149
|
+
"title": "New feature", // Required (only hard requirement)
|
|
150
150
|
"col": "planned", // Optional, default "planned"
|
|
151
151
|
"epic": "Phase 1", // Optional, default "—"
|
|
152
|
-
"description": "Context and plan",
|
|
153
|
-
"specs": "Technical constraints",
|
|
154
|
-
"in_scope": ["What is included"],
|
|
155
|
-
"out_of_scope": ["What is excluded"],
|
|
156
|
-
"acceptance_criteria": ["Must work"],
|
|
157
|
-
"test_cases": ["Verify X"],
|
|
152
|
+
"description": "Context and plan", // Strongly recommended
|
|
153
|
+
"specs": "Technical constraints", // Strongly recommended
|
|
154
|
+
"in_scope": ["What is included"], // Strongly recommended
|
|
155
|
+
"out_of_scope": ["What is excluded"], // Strongly recommended
|
|
156
|
+
"acceptance_criteria": ["Must work"], // Strongly recommended
|
|
157
|
+
"test_cases": ["Verify X"], // Recommended
|
|
158
158
|
"subtasks": [{"text": "Do it", "done": false}],
|
|
159
159
|
"notes": "Freeform notes"
|
|
160
160
|
}
|
|
161
161
|
```
|
|
162
162
|
|
|
163
|
+
**Create field policy:** only `title` is hard-required (GUI/CLI quick-add stays usable). For agent work, always send the strongly recommended fields. If any are missing, create still succeeds and the response includes `warnings` + `missing_recommended`.
|
|
164
|
+
|
|
163
165
|
**Parameters (move):**
|
|
164
166
|
```json
|
|
165
167
|
{
|
|
@@ -189,7 +191,12 @@ Create a task:
|
|
|
189
191
|
"action": "create",
|
|
190
192
|
"title": "Database optimization",
|
|
191
193
|
"col": "planned",
|
|
192
|
-
"epic": "Performance"
|
|
194
|
+
"epic": "Performance",
|
|
195
|
+
"description": "Reduce N+1 queries on board list",
|
|
196
|
+
"specs": "Keep JSON storage; no new deps",
|
|
197
|
+
"in_scope": ["list query path"],
|
|
198
|
+
"out_of_scope": ["GUI redesign"],
|
|
199
|
+
"acceptance_criteria": ["list stays correct under load"]
|
|
193
200
|
}
|
|
194
201
|
```
|
|
195
202
|
|
|
@@ -365,8 +372,18 @@ Check status:
|
|
|
365
372
|
### Pattern 2: Task Creation Workflow
|
|
366
373
|
|
|
367
374
|
```json
|
|
368
|
-
// 1. Create task
|
|
369
|
-
{ "tool": "kanban_manage", "arguments": {
|
|
375
|
+
// 1. Create task with strongly recommended planning fields
|
|
376
|
+
{ "tool": "kanban_manage", "arguments": {
|
|
377
|
+
"action": "create",
|
|
378
|
+
"title": "New feature",
|
|
379
|
+
"col": "planned",
|
|
380
|
+
"epic": "Phase 1",
|
|
381
|
+
"description": "Why this exists",
|
|
382
|
+
"specs": "APIs and constraints",
|
|
383
|
+
"in_scope": ["Core path"],
|
|
384
|
+
"out_of_scope": ["Mobile"],
|
|
385
|
+
"acceptance_criteria": ["npm test passes"]
|
|
386
|
+
} }
|
|
370
387
|
|
|
371
388
|
// 2. Get task details to see generated ID
|
|
372
389
|
{ "tool": "kanban_read", "arguments": { "operation": "show", "task_id": "015" } }
|
|
@@ -394,8 +411,17 @@ Check status:
|
|
|
394
411
|
// List all tasks in an epic
|
|
395
412
|
{ "tool": "kanban_read", "arguments": { "operation": "list", "epic": "Performance" } }
|
|
396
413
|
|
|
397
|
-
// Create task in specific epic
|
|
398
|
-
{ "tool": "kanban_manage", "arguments": {
|
|
414
|
+
// Create task in specific epic (still include recommended fields)
|
|
415
|
+
{ "tool": "kanban_manage", "arguments": {
|
|
416
|
+
"action": "create",
|
|
417
|
+
"title": "Cache optimization",
|
|
418
|
+
"epic": "Performance",
|
|
419
|
+
"description": "Reduce repeated board reads",
|
|
420
|
+
"specs": "In-memory cache with TTL",
|
|
421
|
+
"in_scope": ["list endpoint"],
|
|
422
|
+
"out_of_scope": ["distributed cache"],
|
|
423
|
+
"acceptance_criteria": ["p95 list latency down"]
|
|
424
|
+
} }
|
|
399
425
|
```
|
|
400
426
|
|
|
401
427
|
---
|
|
@@ -406,10 +432,11 @@ Check status:
|
|
|
406
432
|
2. **Numeric task lookup** - Task IDs are zero-padded numbers (e.g. `"035"`). Unpadded numbers such as `"35"` also work in any `task_id` parameter.
|
|
407
433
|
3. **Use `col` filter** - Narrow down to relevant column when listing
|
|
408
434
|
4. **Use `epic` grouping** - Organize tasks by features/phases
|
|
409
|
-
5. **
|
|
410
|
-
6. **
|
|
411
|
-
7. **
|
|
412
|
-
8. **
|
|
435
|
+
5. **Create with planning fields** - Always include description, specs, in_scope, out_of_scope, acceptance_criteria; treat `warnings`/`missing_recommended` as a signal to fill gaps
|
|
436
|
+
6. **Work through subtasks** - Toggle each subtask as you complete them
|
|
437
|
+
7. **Move tasks through workflow** - planned → active → done progression
|
|
438
|
+
8. **Use `show` operation** - Get full task details including subtasks
|
|
439
|
+
9. **Handle task IDs** - Always use the full task ID returned from create/show
|
|
413
440
|
|
|
414
441
|
---
|
|
415
442
|
|
package/kanban.js
CHANGED
|
@@ -62,6 +62,16 @@ const VIEW_FIELDS = {
|
|
|
62
62
|
]
|
|
63
63
|
};
|
|
64
64
|
|
|
65
|
+
// Hard-required on create: title only (keeps GUI/CLI quick-add usable).
|
|
66
|
+
// Strongly recommended for agent/planned work — missing ones yield warnings, not errors.
|
|
67
|
+
const RECOMMENDED_CREATE_FIELDS = [
|
|
68
|
+
'description',
|
|
69
|
+
'specs',
|
|
70
|
+
'in_scope',
|
|
71
|
+
'out_of_scope',
|
|
72
|
+
'acceptance_criteria'
|
|
73
|
+
];
|
|
74
|
+
|
|
65
75
|
function createKanbanError(code, message, hint, details = {}, retryable = false, status = 400) {
|
|
66
76
|
const error = new Error(message);
|
|
67
77
|
error.code = code;
|
|
@@ -96,6 +106,36 @@ function normalizeStringArray(value) {
|
|
|
96
106
|
.filter(Boolean);
|
|
97
107
|
}
|
|
98
108
|
|
|
109
|
+
function isPresentCreateField(field, value) {
|
|
110
|
+
if (field === 'description' || field === 'specs' || field === 'notes') {
|
|
111
|
+
return Boolean(normalizeString(value));
|
|
112
|
+
}
|
|
113
|
+
if (
|
|
114
|
+
field === 'in_scope' ||
|
|
115
|
+
field === 'out_of_scope' ||
|
|
116
|
+
field === 'acceptance_criteria' ||
|
|
117
|
+
field === 'test_cases' ||
|
|
118
|
+
field === 'subtasks'
|
|
119
|
+
) {
|
|
120
|
+
if (field === 'subtasks') return normalizeSubtasks(value).length > 0;
|
|
121
|
+
return normalizeStringArray(value).length > 0;
|
|
122
|
+
}
|
|
123
|
+
return value !== undefined && value !== null && value !== '';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function missingRecommendedCreateFields(payload = {}) {
|
|
127
|
+
return RECOMMENDED_CREATE_FIELDS.filter((field) => !isPresentCreateField(field, payload[field]));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function createFieldWarnings(payload = {}) {
|
|
131
|
+
const missing = missingRecommendedCreateFields(payload);
|
|
132
|
+
if (missing.length === 0) return [];
|
|
133
|
+
return [
|
|
134
|
+
`Strongly recommended fields missing: ${missing.join(', ')}. ` +
|
|
135
|
+
'Fill them on create (or via update) so scope and done-criteria are explicit.'
|
|
136
|
+
];
|
|
137
|
+
}
|
|
138
|
+
|
|
99
139
|
function normalizeSubtasks(value) {
|
|
100
140
|
if (!Array.isArray(value)) return [];
|
|
101
141
|
return value.map((subtask, idx) => ({
|
|
@@ -855,6 +895,8 @@ module.exports = {
|
|
|
855
895
|
doUpdate,
|
|
856
896
|
doCreate,
|
|
857
897
|
createKanbanError,
|
|
898
|
+
createFieldWarnings,
|
|
899
|
+
missingRecommendedCreateFields,
|
|
858
900
|
getProgress,
|
|
859
901
|
resolveTaskId,
|
|
860
902
|
hashCwdToPort,
|
|
@@ -869,6 +911,7 @@ module.exports = {
|
|
|
869
911
|
COLS,
|
|
870
912
|
STATUS_MAP,
|
|
871
913
|
VIEW_FIELDS,
|
|
914
|
+
RECOMMENDED_CREATE_FIELDS,
|
|
872
915
|
GUI_PORT_MIN,
|
|
873
916
|
GUI_PORT_MAX
|
|
874
917
|
};
|
package/mcp-server.js
CHANGED
|
@@ -309,7 +309,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
309
309
|
},
|
|
310
310
|
{
|
|
311
311
|
name: 'kanban_manage',
|
|
312
|
-
description: 'Mutate tasks and accepted plans. Required
|
|
312
|
+
description: 'Mutate tasks and accepted plans. Required by action: create/plan_create -> title only; move -> task_id + column; update -> task_id + patch/shortcuts; plan_advance/plan_done/plan_status -> task_id; plan_evidence -> task_id + diff + test_command + stdout + stderr + exit_code. Strongly recommended on create/plan_create: description, specs, in_scope, out_of_scope, acceptance_criteria (missing fields return warnings, not errors). Example: {"action":"create","title":"Ship Docker image","description":"...","specs":"...","in_scope":["CLI"],"out_of_scope":["GUI"],"acceptance_criteria":["npm test passes"],"col":"planned","epic":"Release"}.',
|
|
313
313
|
inputSchema: {
|
|
314
314
|
type: 'object',
|
|
315
315
|
properties: {
|
|
@@ -335,30 +335,30 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
335
335
|
},
|
|
336
336
|
description: {
|
|
337
337
|
type: 'string',
|
|
338
|
-
description: "High-level context for 'create', 'update', or 'plan_create'."
|
|
338
|
+
description: "Strongly recommended. High-level context/why for 'create', 'update', or 'plan_create'."
|
|
339
339
|
},
|
|
340
340
|
specs: {
|
|
341
341
|
type: 'string',
|
|
342
|
-
description: "Technical constraints, APIs, and edge cases for 'create', 'update', or 'plan_create'."
|
|
342
|
+
description: "Strongly recommended. Technical constraints, APIs, and edge cases for 'create', 'update', or 'plan_create'."
|
|
343
343
|
},
|
|
344
344
|
in_scope: {
|
|
345
345
|
type: 'array',
|
|
346
|
-
description: "What this task includes for 'create', 'update', or 'plan_create'.",
|
|
346
|
+
description: "Strongly recommended. What this task includes (boundaries) for 'create', 'update', or 'plan_create'.",
|
|
347
347
|
items: { type: 'string' }
|
|
348
348
|
},
|
|
349
349
|
out_of_scope: {
|
|
350
350
|
type: 'array',
|
|
351
|
-
description: "Explicit non-goals / exclusions for 'create', 'update', or 'plan_create'.",
|
|
351
|
+
description: "Strongly recommended. Explicit non-goals / exclusions for 'create', 'update', or 'plan_create'.",
|
|
352
352
|
items: { type: 'string' }
|
|
353
353
|
},
|
|
354
354
|
acceptance_criteria: {
|
|
355
355
|
type: 'array',
|
|
356
|
-
description: "Completion requirements for 'create', 'update', or 'plan_create'.",
|
|
356
|
+
description: "Strongly recommended. Completion requirements for 'create', 'update', or 'plan_create'.",
|
|
357
357
|
items: { type: 'string' }
|
|
358
358
|
},
|
|
359
359
|
test_cases: {
|
|
360
360
|
type: 'array',
|
|
361
|
-
description: "Verification scenarios for 'create', 'update', or 'plan_create'.",
|
|
361
|
+
description: "Recommended. Verification scenarios for 'create', 'update', or 'plan_create'.",
|
|
362
362
|
items: { type: 'string' }
|
|
363
363
|
},
|
|
364
364
|
subtasks: {
|
|
@@ -505,7 +505,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
505
505
|
|
|
506
506
|
switch (action) {
|
|
507
507
|
case 'create': {
|
|
508
|
-
const
|
|
508
|
+
const createPayload = {
|
|
509
509
|
description: args.description,
|
|
510
510
|
specs: args.specs,
|
|
511
511
|
in_scope: args.in_scope,
|
|
@@ -514,8 +514,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
514
514
|
test_cases: args.test_cases,
|
|
515
515
|
subtasks: args.subtasks,
|
|
516
516
|
notes: args.notes
|
|
517
|
-
}
|
|
518
|
-
|
|
517
|
+
};
|
|
518
|
+
const created = await kanban.doCreate(args.title, args.col || 'planned', args.epic || '—', createPayload);
|
|
519
|
+
const shaped = kanban.shapeTask(created, { view: 'full' });
|
|
520
|
+
const warnings = kanban.createFieldWarnings(createPayload);
|
|
521
|
+
result = warnings.length > 0
|
|
522
|
+
? { ...shaped, warnings, missing_recommended: kanban.missingRecommendedCreateFields(createPayload) }
|
|
523
|
+
: shaped;
|
|
519
524
|
break;
|
|
520
525
|
}
|
|
521
526
|
|
|
@@ -564,9 +569,18 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
564
569
|
break;
|
|
565
570
|
}
|
|
566
571
|
|
|
567
|
-
case 'plan_create':
|
|
572
|
+
case 'plan_create': {
|
|
568
573
|
result = await plan.create(args);
|
|
574
|
+
const planWarnings = kanban.createFieldWarnings(args);
|
|
575
|
+
if (planWarnings.length > 0 && result && typeof result === 'object') {
|
|
576
|
+
result = {
|
|
577
|
+
...result,
|
|
578
|
+
warnings: planWarnings,
|
|
579
|
+
missing_recommended: kanban.missingRecommendedCreateFields(args)
|
|
580
|
+
};
|
|
581
|
+
}
|
|
569
582
|
break;
|
|
583
|
+
}
|
|
570
584
|
case 'plan_advance':
|
|
571
585
|
result = await plan.advance({ task_id: args.task_id, index: args.index });
|
|
572
586
|
break;
|