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.
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": { "action": "create", "title": "New feature", "col": "planned", "epic": "Phase 1" } }
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": { "action": "create", "title": "Cache optimization", "epic": "Performance" } }
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. **Work through subtasks** - Toggle each subtask as you complete them
410
- 6. **Move tasks through workflow** - planned active done progression
411
- 7. **Use `show` operation** - Get full task details including subtasks
412
- 8. **Handle task IDs** - Always use the full task ID returned from create/show
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 fields by action: create -> title; move -> task_id + column; update -> task_id plus patch or field shortcuts; plan_create -> title; plan_advance/plan_done/plan_status -> task_id; plan_evidence -> task_id + diff + test_command + stdout + stderr + exit_code. Example create: {"action":"create","title":"Ship Docker image","col":"planned","epic":"Release"}.',
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 created = await kanban.doCreate(args.title, args.col || 'planned', args.epic || '—', {
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
- result = kanban.shapeTask(created, { view: 'full' });
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kanbango",
3
- "version": "2.4.0",
3
+ "version": "2.5.0",
4
4
  "description": "JSON-first local Kanban board with web GUI, CLI, and MCP server",
5
5
  "main": "index.js",
6
6
  "bin": {