@gzmagyari/kanbanboard 1.0.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/.env.example +48 -0
- package/API.md +1256 -0
- package/README.md +138 -0
- package/bin/cli.mjs +437 -0
- package/cron-sync.mjs +9 -0
- package/db.mjs +378 -0
- package/docs/project-manager-chat.md +202 -0
- package/kanban-mcp-server.mjs +377 -0
- package/kanban.mjs +127 -0
- package/lib/paths.mjs +136 -0
- package/llm.mjs +307 -0
- package/package.json +52 -0
- package/public/index.html +4747 -0
- package/repo-grounding.mjs +417 -0
- package/server.mjs +8607 -0
package/API.md
ADDED
|
@@ -0,0 +1,1256 @@
|
|
|
1
|
+
# Kanban Dashboard — API Reference
|
|
2
|
+
|
|
3
|
+
Base URL: `http://127.0.0.1:3000`
|
|
4
|
+
|
|
5
|
+
All endpoints return JSON. All timestamps are Unix milliseconds.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
- [Health & Config](#health--config)
|
|
12
|
+
- [Projects](#projects)
|
|
13
|
+
- [Tasks](#tasks)
|
|
14
|
+
- [Task Hierarchy](#task-hierarchy)
|
|
15
|
+
- [Next Sub-ticket](#next-sub-ticket)
|
|
16
|
+
- [Comments & Progress Updates](#comments--progress-updates)
|
|
17
|
+
- [Automation Tasks](#automation-tasks)
|
|
18
|
+
- [Automation Helpers](#automation-helpers)
|
|
19
|
+
- [AI: Task Merge](#ai-task-merge)
|
|
20
|
+
- [AI: Project Init](#ai-project-init)
|
|
21
|
+
- [AI: Evolve Hierarchy](#ai-evolve-hierarchy)
|
|
22
|
+
- [AI: Remove Concept](#ai-remove-concept)
|
|
23
|
+
- [Error Handling](#error-handling)
|
|
24
|
+
- [Object Schemas](#object-schemas)
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Health & Config
|
|
29
|
+
|
|
30
|
+
### `GET /api/health`
|
|
31
|
+
|
|
32
|
+
Basic liveness check.
|
|
33
|
+
|
|
34
|
+
**Response** `200`
|
|
35
|
+
```json
|
|
36
|
+
{ "ok": true }
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
### `GET /api/columns`
|
|
42
|
+
|
|
43
|
+
Returns the valid status columns for tasks and automation tasks.
|
|
44
|
+
|
|
45
|
+
**Response** `200`
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"taskColumns": [
|
|
49
|
+
{ "key": "ideas", "name": "Ideas" },
|
|
50
|
+
{ "key": "todo", "name": "To do" },
|
|
51
|
+
{ "key": "in_progress", "name": "In Progress" },
|
|
52
|
+
{ "key": "review", "name": "Review" },
|
|
53
|
+
{ "key": "testing", "name": "Testing" },
|
|
54
|
+
{ "key": "done", "name": "Done" }
|
|
55
|
+
],
|
|
56
|
+
"autoColumns": [
|
|
57
|
+
{ "key": "ideas", "name": "Ideas" },
|
|
58
|
+
{ "key": "active", "name": "Active" }
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
### `GET /api/ai/health`
|
|
66
|
+
|
|
67
|
+
Returns LLM configuration status. No API key required.
|
|
68
|
+
|
|
69
|
+
**Response** `200`
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"enabled": true,
|
|
73
|
+
"base_url": "https://openrouter.ai/api/v1",
|
|
74
|
+
"model": "google/gemini-3-pro-preview",
|
|
75
|
+
"api_key_required": false,
|
|
76
|
+
"rate_limit_per_min": 60
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Projects
|
|
83
|
+
|
|
84
|
+
### `GET /api/projects`
|
|
85
|
+
|
|
86
|
+
Lists all projects with task and automation counts.
|
|
87
|
+
|
|
88
|
+
**Response** `200`
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"projects": [
|
|
92
|
+
{
|
|
93
|
+
"id": "default",
|
|
94
|
+
"name": "Default",
|
|
95
|
+
"scope_text": "",
|
|
96
|
+
"created_at": 1770500000000,
|
|
97
|
+
"updated_at": 1770500000000,
|
|
98
|
+
"task_count": 42,
|
|
99
|
+
"automation_count": 2
|
|
100
|
+
}
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
### `POST /api/projects`
|
|
108
|
+
|
|
109
|
+
Creates a new project.
|
|
110
|
+
|
|
111
|
+
**Request**
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"name": "My Project",
|
|
115
|
+
"scope_text": "A web application for managing widgets."
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
| Field | Type | Required | Default |
|
|
120
|
+
|-------|------|----------|---------|
|
|
121
|
+
| `name` | string | yes | — |
|
|
122
|
+
| `scope_text` | string | no | `""` |
|
|
123
|
+
|
|
124
|
+
**Response** `201`
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"project": {
|
|
128
|
+
"id": "pH1ZSGuW5i",
|
|
129
|
+
"name": "My Project",
|
|
130
|
+
"scope_text": "A web application for managing widgets.",
|
|
131
|
+
"created_at": 1770572000000,
|
|
132
|
+
"updated_at": 1770572000000
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Errors**
|
|
138
|
+
- `400` — `name` is missing or empty
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
### `GET /api/projects/:id`
|
|
143
|
+
|
|
144
|
+
Returns a single project.
|
|
145
|
+
|
|
146
|
+
**Example** `GET /api/projects/pH1ZSGuW5i`
|
|
147
|
+
|
|
148
|
+
**Response** `200`
|
|
149
|
+
```json
|
|
150
|
+
{
|
|
151
|
+
"project": {
|
|
152
|
+
"id": "pH1ZSGuW5i",
|
|
153
|
+
"name": "My Project",
|
|
154
|
+
"scope_text": "A web application for managing widgets.",
|
|
155
|
+
"created_at": 1770572000000,
|
|
156
|
+
"updated_at": 1770572000000
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Errors**
|
|
162
|
+
- `404` — project not found
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
### `PATCH /api/projects/:id`
|
|
167
|
+
|
|
168
|
+
Updates a project's name and/or scope.
|
|
169
|
+
|
|
170
|
+
**Request**
|
|
171
|
+
```json
|
|
172
|
+
{
|
|
173
|
+
"name": "Renamed Project",
|
|
174
|
+
"scope_text": "Updated scope description."
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
All fields are optional. Only provided fields are updated.
|
|
179
|
+
|
|
180
|
+
**Response** `200` — same shape as GET
|
|
181
|
+
|
|
182
|
+
**Errors**
|
|
183
|
+
- `404` — project not found
|
|
184
|
+
- `400` — name is empty string
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
### `DELETE /api/projects/:id`
|
|
189
|
+
|
|
190
|
+
Deletes a project. All tasks in the project are reassigned to the `default` project first.
|
|
191
|
+
|
|
192
|
+
**Response** `200`
|
|
193
|
+
```json
|
|
194
|
+
{ "ok": true }
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**Errors**
|
|
198
|
+
- `400` — cannot delete the default project
|
|
199
|
+
- `404` — project not found
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Tasks
|
|
204
|
+
|
|
205
|
+
### `GET /api/tasks`
|
|
206
|
+
|
|
207
|
+
Lists tasks with optional filters.
|
|
208
|
+
|
|
209
|
+
**Query Parameters**
|
|
210
|
+
|
|
211
|
+
| Param | Type | Description |
|
|
212
|
+
|-------|------|-------------|
|
|
213
|
+
| `status` | string | Filter by status (e.g. `todo`, `in_progress`) |
|
|
214
|
+
| `project_id` | string | Filter by project |
|
|
215
|
+
| `parent_id` | string | Filter by parent. Use `null` or empty for root tasks |
|
|
216
|
+
| `include_deleted` | boolean | Include soft-deleted tasks. Default `false` |
|
|
217
|
+
|
|
218
|
+
**Example** `GET /api/tasks?project_id=pH1ZSGuW5i&status=todo`
|
|
219
|
+
|
|
220
|
+
**Response** `200`
|
|
221
|
+
```json
|
|
222
|
+
{
|
|
223
|
+
"tasks": [
|
|
224
|
+
{
|
|
225
|
+
"id": "bY0pcKdSUx",
|
|
226
|
+
"title": "Root Task",
|
|
227
|
+
"description": "A root-level task",
|
|
228
|
+
"status": "todo",
|
|
229
|
+
"detail_text": "",
|
|
230
|
+
"created_at": 1770572611089,
|
|
231
|
+
"updated_at": 1770572611089,
|
|
232
|
+
"project_id": "pH1ZSGuW5i",
|
|
233
|
+
"parent_id": null,
|
|
234
|
+
"deleted_at": null
|
|
235
|
+
}
|
|
236
|
+
]
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**Errors**
|
|
241
|
+
- `400` — invalid status or project_id
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
### `POST /api/tasks`
|
|
246
|
+
|
|
247
|
+
Creates a new task.
|
|
248
|
+
|
|
249
|
+
**Request**
|
|
250
|
+
```json
|
|
251
|
+
{
|
|
252
|
+
"title": "Implement login page",
|
|
253
|
+
"description": "Build the login form with email/password fields",
|
|
254
|
+
"status": "todo",
|
|
255
|
+
"detail_text": "Use Vuetify form components...",
|
|
256
|
+
"project_id": "pH1ZSGuW5i",
|
|
257
|
+
"parent_id": "bY0pcKdSUx"
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
| Field | Type | Required | Default |
|
|
262
|
+
|-------|------|----------|---------|
|
|
263
|
+
| `title` | string | yes | — |
|
|
264
|
+
| `description` | string | no | `""` |
|
|
265
|
+
| `status` | string | no | `"todo"` |
|
|
266
|
+
| `detail_text` | string | no | `""` |
|
|
267
|
+
| `project_id` | string | no | `"default"` |
|
|
268
|
+
| `parent_id` | string | no | `null` |
|
|
269
|
+
|
|
270
|
+
**Response** `201`
|
|
271
|
+
```json
|
|
272
|
+
{
|
|
273
|
+
"task": {
|
|
274
|
+
"id": "OnXAVEF7D1",
|
|
275
|
+
"title": "Implement login page",
|
|
276
|
+
"description": "Build the login form with email/password fields",
|
|
277
|
+
"status": "todo",
|
|
278
|
+
"detail_text": "Use Vuetify form components...",
|
|
279
|
+
"created_at": 1770572617938,
|
|
280
|
+
"updated_at": 1770572617938,
|
|
281
|
+
"project_id": "pH1ZSGuW5i",
|
|
282
|
+
"parent_id": "bY0pcKdSUx",
|
|
283
|
+
"deleted_at": null
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**Side effects**
|
|
289
|
+
- Parent task's `updated_at` is bumped when `parent_id` is set
|
|
290
|
+
|
|
291
|
+
**Errors**
|
|
292
|
+
- `400` — missing title, invalid status, project not found, parent not found or in different project
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
### `GET /api/tasks/:id`
|
|
297
|
+
|
|
298
|
+
Returns a task with its comments and progress updates.
|
|
299
|
+
|
|
300
|
+
**Example** `GET /api/tasks/bY0pcKdSUx`
|
|
301
|
+
|
|
302
|
+
**Response** `200`
|
|
303
|
+
```json
|
|
304
|
+
{
|
|
305
|
+
"task": { "...": "task object" },
|
|
306
|
+
"comments": [
|
|
307
|
+
{
|
|
308
|
+
"id": 4,
|
|
309
|
+
"entity_type": "task",
|
|
310
|
+
"entity_id": "bY0pcKdSUx",
|
|
311
|
+
"author": "Gabor",
|
|
312
|
+
"text": "This is a test comment",
|
|
313
|
+
"created_at": 1770572931850
|
|
314
|
+
}
|
|
315
|
+
],
|
|
316
|
+
"updates": [
|
|
317
|
+
{
|
|
318
|
+
"id": 299,
|
|
319
|
+
"entity_type": "task",
|
|
320
|
+
"entity_id": "bY0pcKdSUx",
|
|
321
|
+
"author": "Jarvis",
|
|
322
|
+
"text": "Progress: 50% complete",
|
|
323
|
+
"created_at": 1770572935085
|
|
324
|
+
}
|
|
325
|
+
]
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Updates are capped at 50 most recent, ordered newest first.
|
|
330
|
+
|
|
331
|
+
**Errors**
|
|
332
|
+
- `404` — task not found or soft-deleted
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
### `PATCH /api/tasks/:id`
|
|
337
|
+
|
|
338
|
+
Updates a task. Only provided fields are changed.
|
|
339
|
+
|
|
340
|
+
**Request**
|
|
341
|
+
```json
|
|
342
|
+
{
|
|
343
|
+
"title": "Updated title",
|
|
344
|
+
"status": "in_progress",
|
|
345
|
+
"parent_id": "bY0pcKdSUx",
|
|
346
|
+
"project_id": "pH1ZSGuW5i"
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
All fields are optional.
|
|
351
|
+
|
|
352
|
+
**Validation rules**
|
|
353
|
+
- `parent_id` cannot be the task itself (`400`)
|
|
354
|
+
- `parent_id` cannot create a cycle — i.e. cannot set parent to own descendant (`400`)
|
|
355
|
+
- `parent_id` must be in the same project (`400`)
|
|
356
|
+
- Changing `project_id` detaches the task from its parent (sets `parent_id = null`)
|
|
357
|
+
|
|
358
|
+
**Response** `200` — returns updated task object
|
|
359
|
+
|
|
360
|
+
**Errors**
|
|
361
|
+
- `404` — task not found
|
|
362
|
+
- `400` — invalid status, self-referencing parent, cycle detected, project mismatch
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
### `DELETE /api/tasks/:id`
|
|
367
|
+
|
|
368
|
+
Hard-deletes a task and its entire subtree (all descendants, comments, and updates).
|
|
369
|
+
|
|
370
|
+
**Example** `DELETE /api/tasks/tRYxSsybNq`
|
|
371
|
+
|
|
372
|
+
**Response** `200`
|
|
373
|
+
```json
|
|
374
|
+
{ "ok": true }
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
**Errors**
|
|
378
|
+
- `404` — task not found
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
## Task Hierarchy
|
|
383
|
+
|
|
384
|
+
### `GET /api/tasks/:id/ancestors`
|
|
385
|
+
|
|
386
|
+
Returns the ancestor path from root down to (optionally including) the task.
|
|
387
|
+
|
|
388
|
+
**Query Parameters**
|
|
389
|
+
|
|
390
|
+
| Param | Type | Default | Description |
|
|
391
|
+
|-------|------|---------|-------------|
|
|
392
|
+
| `include_self` | boolean | `false` | Include the task itself at the end of the path |
|
|
393
|
+
|
|
394
|
+
**Example** `GET /api/tasks/dzUFSKZQRr/ancestors?include_self=1`
|
|
395
|
+
|
|
396
|
+
**Response** `200`
|
|
397
|
+
```json
|
|
398
|
+
{
|
|
399
|
+
"path": [
|
|
400
|
+
{
|
|
401
|
+
"id": "bY0pcKdSUx",
|
|
402
|
+
"title": "Root Task",
|
|
403
|
+
"status": "in_progress",
|
|
404
|
+
"parent_id": null,
|
|
405
|
+
"depth": 2,
|
|
406
|
+
"...": "other task fields"
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
"id": "OnXAVEF7D1",
|
|
410
|
+
"title": "Child Task",
|
|
411
|
+
"parent_id": "bY0pcKdSUx",
|
|
412
|
+
"depth": 1,
|
|
413
|
+
"...": "..."
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
"id": "dzUFSKZQRr",
|
|
417
|
+
"title": "Grandchild Task",
|
|
418
|
+
"parent_id": "OnXAVEF7D1",
|
|
419
|
+
"depth": 0,
|
|
420
|
+
"...": "..."
|
|
421
|
+
}
|
|
422
|
+
]
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
Path is ordered root → leaf. `depth` counts distance from the target task (0 = self).
|
|
427
|
+
|
|
428
|
+
**Errors**
|
|
429
|
+
- `404` — task not found
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
### `GET /api/tasks/:id/descendants`
|
|
434
|
+
|
|
435
|
+
Returns all descendants of a task.
|
|
436
|
+
|
|
437
|
+
**Query Parameters**
|
|
438
|
+
|
|
439
|
+
| Param | Type | Default | Description |
|
|
440
|
+
|-------|------|---------|-------------|
|
|
441
|
+
| `mode` | string | `"flat"` | `"flat"` for a flat list, `"tree"` for nested structure |
|
|
442
|
+
| `include_self` | boolean | `false` | Include the root task itself |
|
|
443
|
+
|
|
444
|
+
**Example (flat)** `GET /api/tasks/bY0pcKdSUx/descendants?mode=flat`
|
|
445
|
+
|
|
446
|
+
**Response** `200`
|
|
447
|
+
```json
|
|
448
|
+
{
|
|
449
|
+
"descendants": [
|
|
450
|
+
{
|
|
451
|
+
"id": "OnXAVEF7D1",
|
|
452
|
+
"title": "Child Task",
|
|
453
|
+
"parent_id": "bY0pcKdSUx",
|
|
454
|
+
"depth": 1,
|
|
455
|
+
"...": "..."
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
"id": "dzUFSKZQRr",
|
|
459
|
+
"title": "Grandchild Task",
|
|
460
|
+
"parent_id": "OnXAVEF7D1",
|
|
461
|
+
"depth": 2,
|
|
462
|
+
"...": "..."
|
|
463
|
+
}
|
|
464
|
+
]
|
|
465
|
+
}
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
**Example (tree)** `GET /api/tasks/bY0pcKdSUx/descendants?mode=tree`
|
|
469
|
+
|
|
470
|
+
**Response** `200`
|
|
471
|
+
```json
|
|
472
|
+
{
|
|
473
|
+
"tree": {
|
|
474
|
+
"task": { "id": "bY0pcKdSUx", "title": "Root Task", "...": "..." },
|
|
475
|
+
"depth": 0,
|
|
476
|
+
"children": [
|
|
477
|
+
{
|
|
478
|
+
"task": { "id": "OnXAVEF7D1", "title": "Child Task", "...": "..." },
|
|
479
|
+
"depth": 1,
|
|
480
|
+
"children": [
|
|
481
|
+
{
|
|
482
|
+
"task": { "id": "dzUFSKZQRr", "title": "Grandchild Task", "...": "..." },
|
|
483
|
+
"depth": 2,
|
|
484
|
+
"children": []
|
|
485
|
+
}
|
|
486
|
+
]
|
|
487
|
+
}
|
|
488
|
+
]
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
**Errors**
|
|
494
|
+
- `404` — task not found
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
498
|
+
### `GET /api/tasks/:id/context`
|
|
499
|
+
|
|
500
|
+
Returns a full context bundle for a task: project info, ancestor path, children, and a rendered text summary suitable for LLM consumption.
|
|
501
|
+
|
|
502
|
+
**Example** `GET /api/tasks/OnXAVEF7D1/context`
|
|
503
|
+
|
|
504
|
+
**Response** `200`
|
|
505
|
+
```json
|
|
506
|
+
{
|
|
507
|
+
"project": { "id": "pH1ZSGuW5i", "name": "My Project", "...": "..." },
|
|
508
|
+
"path": [
|
|
509
|
+
{ "id": "bY0pcKdSUx", "title": "Root Task", "depth": 1, "...": "..." }
|
|
510
|
+
],
|
|
511
|
+
"task": { "id": "OnXAVEF7D1", "title": "Child Task", "...": "..." },
|
|
512
|
+
"children": [
|
|
513
|
+
{ "id": "dzUFSKZQRr", "title": "Grandchild Task", "...": "..." }
|
|
514
|
+
],
|
|
515
|
+
"agent_instructions": "Project: My Project (#pH1ZSGuW5i)\n\nProject scope:\n...\n\nTicket path (root -> selected):\n- [in_progress] Root Task (#bY0pcKdSUx)\n\nSelected ticket details:\nTitle: Child Task\n..."
|
|
516
|
+
}
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
**Errors**
|
|
520
|
+
- `404` — task not found
|
|
521
|
+
|
|
522
|
+
---
|
|
523
|
+
|
|
524
|
+
## Next Sub-ticket
|
|
525
|
+
|
|
526
|
+
### `POST /api/tasks/:id/next`
|
|
527
|
+
|
|
528
|
+
Picks the next best leaf sub-ticket to work on. Supports heuristic (local sort) or LLM-powered selection.
|
|
529
|
+
|
|
530
|
+
**Request**
|
|
531
|
+
```json
|
|
532
|
+
{
|
|
533
|
+
"strategy": "auto",
|
|
534
|
+
"exclude_status": ["done"],
|
|
535
|
+
"prefer_status": ["in_progress", "todo", "review", "testing", "ideas"],
|
|
536
|
+
"max_candidates": 40
|
|
537
|
+
}
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
| Field | Type | Required | Default |
|
|
541
|
+
|-------|------|----------|---------|
|
|
542
|
+
| `strategy` | string | no | `"auto"` — uses LLM if available, falls back to heuristic |
|
|
543
|
+
| `exclude_status` | string or string[] | no | `["done"]` |
|
|
544
|
+
| `prefer_status` | string or string[] | no | `["in_progress","todo","review","testing","ideas"]` |
|
|
545
|
+
| `max_candidates` | number | no | `40` |
|
|
546
|
+
|
|
547
|
+
**Strategy options**
|
|
548
|
+
- `"auto"` — tries LLM first, falls back to heuristic on failure
|
|
549
|
+
- `"llm"` — always uses LLM (fails if LLM unavailable)
|
|
550
|
+
- `"heuristic"` — never uses LLM; sorts by prefer_status order then oldest first
|
|
551
|
+
|
|
552
|
+
**Response** `200` (task found)
|
|
553
|
+
```json
|
|
554
|
+
{
|
|
555
|
+
"selected": {
|
|
556
|
+
"id": "dzUFSKZQRr",
|
|
557
|
+
"title": "Grandchild Task",
|
|
558
|
+
"status": "todo",
|
|
559
|
+
"...": "..."
|
|
560
|
+
},
|
|
561
|
+
"strategy": "llm",
|
|
562
|
+
"rationale": "The database schema is the foundational dependency...",
|
|
563
|
+
"llm_run_id": "abc123",
|
|
564
|
+
"candidate_count": 5,
|
|
565
|
+
"context": {
|
|
566
|
+
"project": { "...": "..." },
|
|
567
|
+
"path": [ "..." ],
|
|
568
|
+
"task": { "...": "..." },
|
|
569
|
+
"children": [ "..." ],
|
|
570
|
+
"agent_instructions": "..."
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
**Response** `200` (no candidates)
|
|
576
|
+
```json
|
|
577
|
+
{
|
|
578
|
+
"selected": null,
|
|
579
|
+
"strategy": "none",
|
|
580
|
+
"rationale": "No leaf sub-tickets found...",
|
|
581
|
+
"candidate_count": 0
|
|
582
|
+
}
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
**Errors**
|
|
586
|
+
- `404` — task not found
|
|
587
|
+
|
|
588
|
+
---
|
|
589
|
+
|
|
590
|
+
## Comments & Progress Updates
|
|
591
|
+
|
|
592
|
+
### `POST /api/tasks/:id/comments`
|
|
593
|
+
|
|
594
|
+
Adds a comment to a task.
|
|
595
|
+
|
|
596
|
+
**Request**
|
|
597
|
+
```json
|
|
598
|
+
{
|
|
599
|
+
"text": "Need to clarify requirements with stakeholder",
|
|
600
|
+
"author": "Gabor"
|
|
601
|
+
}
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
| Field | Type | Required | Default |
|
|
605
|
+
|-------|------|----------|---------|
|
|
606
|
+
| `text` | string | yes | — |
|
|
607
|
+
| `author` | string | no | `"Gabor"` |
|
|
608
|
+
|
|
609
|
+
**Response** `201`
|
|
610
|
+
```json
|
|
611
|
+
{
|
|
612
|
+
"comment": {
|
|
613
|
+
"id": 4,
|
|
614
|
+
"entity_type": "task",
|
|
615
|
+
"entity_id": "bY0pcKdSUx",
|
|
616
|
+
"author": "Gabor",
|
|
617
|
+
"text": "Need to clarify requirements with stakeholder",
|
|
618
|
+
"created_at": 1770572931850
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
**Side effects** — bumps the task's `updated_at`
|
|
624
|
+
|
|
625
|
+
**Errors**
|
|
626
|
+
- `404` — task not found
|
|
627
|
+
- `400` — `text` is missing
|
|
628
|
+
|
|
629
|
+
---
|
|
630
|
+
|
|
631
|
+
### `POST /api/tasks/:id/updates`
|
|
632
|
+
|
|
633
|
+
Adds a progress update to a task.
|
|
634
|
+
|
|
635
|
+
**Request**
|
|
636
|
+
```json
|
|
637
|
+
{
|
|
638
|
+
"text": "Completed the database schema migration",
|
|
639
|
+
"author": "Jarvis"
|
|
640
|
+
}
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
| Field | Type | Required | Default |
|
|
644
|
+
|-------|------|----------|---------|
|
|
645
|
+
| `text` | string | yes | — |
|
|
646
|
+
| `author` | string | no | `"Jarvis"` |
|
|
647
|
+
|
|
648
|
+
**Response** `201`
|
|
649
|
+
```json
|
|
650
|
+
{
|
|
651
|
+
"update": {
|
|
652
|
+
"id": 299,
|
|
653
|
+
"entity_type": "task",
|
|
654
|
+
"entity_id": "bY0pcKdSUx",
|
|
655
|
+
"author": "Jarvis",
|
|
656
|
+
"text": "Completed the database schema migration",
|
|
657
|
+
"created_at": 1770572935085
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
**Side effects** — bumps the task's `updated_at`
|
|
663
|
+
|
|
664
|
+
**Errors**
|
|
665
|
+
- `404` — task not found
|
|
666
|
+
- `400` — `text` is missing
|
|
667
|
+
|
|
668
|
+
---
|
|
669
|
+
|
|
670
|
+
## Automation Tasks
|
|
671
|
+
|
|
672
|
+
Automation tasks come in two types: `recurring` (cron-based) and `scheduled` (one-shot at a specific time).
|
|
673
|
+
|
|
674
|
+
### `GET /api/automation/:type`
|
|
675
|
+
|
|
676
|
+
Lists automation tasks of a given type.
|
|
677
|
+
|
|
678
|
+
**URL parameters** — `:type` is `recurring` or `scheduled`
|
|
679
|
+
|
|
680
|
+
**Query Parameters**
|
|
681
|
+
|
|
682
|
+
| Param | Type | Description |
|
|
683
|
+
|-------|------|-------------|
|
|
684
|
+
| `status` | string | Filter by status (`ideas` or `active`) |
|
|
685
|
+
| `project_id` | string | Filter by project |
|
|
686
|
+
|
|
687
|
+
**Example** `GET /api/automation/recurring?status=active`
|
|
688
|
+
|
|
689
|
+
**Response** `200`
|
|
690
|
+
```json
|
|
691
|
+
{
|
|
692
|
+
"tasks": [
|
|
693
|
+
{
|
|
694
|
+
"id": "44d4003vU2",
|
|
695
|
+
"type": "recurring",
|
|
696
|
+
"title": "Weekly Review",
|
|
697
|
+
"description": "Review all tasks weekly",
|
|
698
|
+
"status": "active",
|
|
699
|
+
"detail_text": "",
|
|
700
|
+
"project_id": "pH1ZSGuW5i",
|
|
701
|
+
"schedule_kind": "cron",
|
|
702
|
+
"expr": "0 9 * * 1",
|
|
703
|
+
"tz": "America/New_York",
|
|
704
|
+
"at_iso": null,
|
|
705
|
+
"cron_job_id": null,
|
|
706
|
+
"cron_enabled": 1,
|
|
707
|
+
"last_synced_at": null,
|
|
708
|
+
"last_sync_error": null,
|
|
709
|
+
"created_at": 1770572993713,
|
|
710
|
+
"updated_at": 1770573019024
|
|
711
|
+
}
|
|
712
|
+
]
|
|
713
|
+
}
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
---
|
|
717
|
+
|
|
718
|
+
### `POST /api/automation/:type`
|
|
719
|
+
|
|
720
|
+
Creates a new automation task.
|
|
721
|
+
|
|
722
|
+
**URL parameters** — `:type` is `recurring` or `scheduled`
|
|
723
|
+
|
|
724
|
+
**Request (recurring/cron)**
|
|
725
|
+
```json
|
|
726
|
+
{
|
|
727
|
+
"title": "Weekly Review",
|
|
728
|
+
"description": "Review all tasks weekly",
|
|
729
|
+
"schedule_kind": "cron",
|
|
730
|
+
"expr": "0 9 * * 1",
|
|
731
|
+
"tz": "America/New_York",
|
|
732
|
+
"project_id": "pH1ZSGuW5i"
|
|
733
|
+
}
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
**Request (scheduled/at)**
|
|
737
|
+
```json
|
|
738
|
+
{
|
|
739
|
+
"title": "Deploy Release",
|
|
740
|
+
"description": "Deploy v2.0 release",
|
|
741
|
+
"schedule_kind": "at",
|
|
742
|
+
"at_iso": "2026-03-01T10:00:00Z",
|
|
743
|
+
"project_id": "pH1ZSGuW5i"
|
|
744
|
+
}
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
| Field | Type | Required | Default | Notes |
|
|
748
|
+
|-------|------|----------|---------|-------|
|
|
749
|
+
| `title` | string | yes | — | |
|
|
750
|
+
| `description` | string | no | `""` | |
|
|
751
|
+
| `status` | string | no | `"ideas"` | Must be `ideas` or `active` |
|
|
752
|
+
| `detail_text` | string | no | `""` | |
|
|
753
|
+
| `project_id` | string | no | `"default"` | |
|
|
754
|
+
| `schedule_kind` | string | yes | — | `"cron"` or `"at"` |
|
|
755
|
+
| `expr` | string | if cron | — | Cron expression (e.g. `0 9 * * 1`) |
|
|
756
|
+
| `tz` | string | if cron | — | Timezone (e.g. `America/New_York`) |
|
|
757
|
+
| `at_iso` | string | if at | — | ISO 8601 datetime |
|
|
758
|
+
|
|
759
|
+
**Constraints**
|
|
760
|
+
- Recurring tasks must use `schedule_kind: "cron"` (cannot use `"at"`)
|
|
761
|
+
|
|
762
|
+
**Response** `201` — returns the automation task object
|
|
763
|
+
|
|
764
|
+
**Errors**
|
|
765
|
+
- `400` — missing required fields, invalid schedule_kind, recurring with `at` kind
|
|
766
|
+
|
|
767
|
+
---
|
|
768
|
+
|
|
769
|
+
### `GET /api/automation/:type/:id`
|
|
770
|
+
|
|
771
|
+
Returns an automation task with its comments and updates.
|
|
772
|
+
|
|
773
|
+
**Example** `GET /api/automation/recurring/44d4003vU2`
|
|
774
|
+
|
|
775
|
+
**Response** `200`
|
|
776
|
+
```json
|
|
777
|
+
{
|
|
778
|
+
"task": { "...": "automation task object" },
|
|
779
|
+
"comments": [ "..." ],
|
|
780
|
+
"updates": [ "..." ]
|
|
781
|
+
}
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
**Errors**
|
|
785
|
+
- `404` — task not found
|
|
786
|
+
- `400` — invalid type
|
|
787
|
+
|
|
788
|
+
---
|
|
789
|
+
|
|
790
|
+
### `PATCH /api/automation/:type/:id`
|
|
791
|
+
|
|
792
|
+
Updates an automation task. Only provided fields are changed.
|
|
793
|
+
|
|
794
|
+
**Request**
|
|
795
|
+
```json
|
|
796
|
+
{
|
|
797
|
+
"title": "Updated Weekly Review",
|
|
798
|
+
"status": "active",
|
|
799
|
+
"expr": "0 10 * * 1"
|
|
800
|
+
}
|
|
801
|
+
```
|
|
802
|
+
|
|
803
|
+
All fields are optional. Schedule fields (`schedule_kind`, `expr`, `tz`, `at_iso`) are re-validated together when any of them change.
|
|
804
|
+
|
|
805
|
+
**Special behavior**
|
|
806
|
+
- Setting `status: "ideas"` automatically sets `cron_enabled: 0`
|
|
807
|
+
- Setting `status: "active"` automatically sets `cron_enabled: 1`
|
|
808
|
+
|
|
809
|
+
**Additional fields** (for sync agent use)
|
|
810
|
+
|
|
811
|
+
| Field | Type | Description |
|
|
812
|
+
|-------|------|-------------|
|
|
813
|
+
| `cron_job_id` | string | External cron service job ID |
|
|
814
|
+
| `cron_enabled` | boolean | Whether cron is enabled |
|
|
815
|
+
| `last_synced_at` | number | Last sync timestamp (ms) |
|
|
816
|
+
| `last_sync_error` | string | Last sync error message |
|
|
817
|
+
|
|
818
|
+
**Response** `200` — returns updated automation task object
|
|
819
|
+
|
|
820
|
+
**Errors**
|
|
821
|
+
- `404` — task not found
|
|
822
|
+
- `400` — invalid type, status, or schedule
|
|
823
|
+
|
|
824
|
+
---
|
|
825
|
+
|
|
826
|
+
### `DELETE /api/automation/:type/:id`
|
|
827
|
+
|
|
828
|
+
Deletes an automation task and its comments/updates.
|
|
829
|
+
|
|
830
|
+
**Response** `200`
|
|
831
|
+
```json
|
|
832
|
+
{ "ok": true }
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
**Errors**
|
|
836
|
+
- `404` — task not found
|
|
837
|
+
- `400` — invalid type
|
|
838
|
+
|
|
839
|
+
---
|
|
840
|
+
|
|
841
|
+
### `POST /api/automation/:type/:id/comments`
|
|
842
|
+
|
|
843
|
+
Adds a comment to an automation task. Same interface as task comments.
|
|
844
|
+
|
|
845
|
+
**Request**
|
|
846
|
+
```json
|
|
847
|
+
{
|
|
848
|
+
"text": "Adjusted schedule to run at 10am",
|
|
849
|
+
"author": "Gabor"
|
|
850
|
+
}
|
|
851
|
+
```
|
|
852
|
+
|
|
853
|
+
**Response** `201` — comment object with `entity_type` set to `"recurring"` or `"scheduled"`
|
|
854
|
+
|
|
855
|
+
---
|
|
856
|
+
|
|
857
|
+
### `POST /api/automation/:type/:id/updates`
|
|
858
|
+
|
|
859
|
+
Adds a progress update to an automation task. Same interface as task updates.
|
|
860
|
+
|
|
861
|
+
**Request**
|
|
862
|
+
```json
|
|
863
|
+
{
|
|
864
|
+
"text": "Synced with cron-job.org successfully",
|
|
865
|
+
"author": "Jarvis"
|
|
866
|
+
}
|
|
867
|
+
```
|
|
868
|
+
|
|
869
|
+
**Response** `201` — update object with `entity_type` set to `"recurring"` or `"scheduled"`
|
|
870
|
+
|
|
871
|
+
---
|
|
872
|
+
|
|
873
|
+
## Automation Helpers
|
|
874
|
+
|
|
875
|
+
These endpoints are designed for the external sync agent.
|
|
876
|
+
|
|
877
|
+
### `GET /api/automation-active`
|
|
878
|
+
|
|
879
|
+
Returns all automation tasks with `status = 'active'` (both recurring and scheduled).
|
|
880
|
+
|
|
881
|
+
**Response** `200`
|
|
882
|
+
```json
|
|
883
|
+
{
|
|
884
|
+
"tasks": [ "...automation task objects..." ]
|
|
885
|
+
}
|
|
886
|
+
```
|
|
887
|
+
|
|
888
|
+
---
|
|
889
|
+
|
|
890
|
+
### `GET /api/automation-sync-snapshot`
|
|
891
|
+
|
|
892
|
+
Returns all automation tasks (regardless of status) for full sync.
|
|
893
|
+
|
|
894
|
+
**Response** `200`
|
|
895
|
+
```json
|
|
896
|
+
{
|
|
897
|
+
"tasks": [ "...automation task objects..." ]
|
|
898
|
+
}
|
|
899
|
+
```
|
|
900
|
+
|
|
901
|
+
---
|
|
902
|
+
|
|
903
|
+
## AI: Task Merge
|
|
904
|
+
|
|
905
|
+
### `POST /api/ai/tasks/merge`
|
|
906
|
+
|
|
907
|
+
Creates a new task from a natural-language description. The LLM enhances the title/description and optionally breaks it down into sub-tasks.
|
|
908
|
+
|
|
909
|
+
**Request**
|
|
910
|
+
```json
|
|
911
|
+
{
|
|
912
|
+
"text": "Implement user authentication with login, registration, and password reset",
|
|
913
|
+
"project_id": "pH1ZSGuW5i",
|
|
914
|
+
"breakdown": true,
|
|
915
|
+
"max_depth": 2,
|
|
916
|
+
"status": "todo",
|
|
917
|
+
"parent_id": "bY0pcKdSUx",
|
|
918
|
+
"apply": true
|
|
919
|
+
}
|
|
920
|
+
```
|
|
921
|
+
|
|
922
|
+
| Field | Type | Required | Default | Notes |
|
|
923
|
+
|-------|------|----------|---------|-------|
|
|
924
|
+
| `text` | string | yes | — | Natural-language task description |
|
|
925
|
+
| `project_id` | string | no | `"default"` | |
|
|
926
|
+
| `breakdown` | boolean | no | `false` | Create sub-tasks |
|
|
927
|
+
| `max_depth` | number | no | `3` | Max nesting depth (1–6) |
|
|
928
|
+
| `status` | string | no | `"todo"` | Root task status |
|
|
929
|
+
| `parent_id` | string | no | `null` | Attach under existing task |
|
|
930
|
+
| `apply` | boolean | no | `true` | `false` for dry-run |
|
|
931
|
+
|
|
932
|
+
**Response (apply=true)** `200`
|
|
933
|
+
```json
|
|
934
|
+
{
|
|
935
|
+
"plan_id": "QyOvX8gckSoR",
|
|
936
|
+
"llm_run_id": "abc123def456",
|
|
937
|
+
"applied": true,
|
|
938
|
+
"rationale": "Created task with 6 sub-tasks covering backend and frontend...",
|
|
939
|
+
"root_task": {
|
|
940
|
+
"id": "LkpwlcsGpj",
|
|
941
|
+
"title": "Implement User Authentication System",
|
|
942
|
+
"description": "Full authentication system with login, registration...",
|
|
943
|
+
"status": "todo",
|
|
944
|
+
"parent_id": null,
|
|
945
|
+
"project_id": "pH1ZSGuW5i",
|
|
946
|
+
"...": "..."
|
|
947
|
+
},
|
|
948
|
+
"created_tasks": [
|
|
949
|
+
{ "id": "LkpwlcsGpj", "title": "Implement User Authentication System", "parent_id": null, "...": "..." },
|
|
950
|
+
{ "id": "6eQIP0ar3U", "title": "Backend: User Database Schema", "parent_id": "LkpwlcsGpj", "...": "..." },
|
|
951
|
+
{ "id": "xUGDlxxdnP", "title": "Backend: Auth API Endpoints", "parent_id": "LkpwlcsGpj", "...": "..." }
|
|
952
|
+
]
|
|
953
|
+
}
|
|
954
|
+
```
|
|
955
|
+
|
|
956
|
+
**Response (apply=false, dry-run)** `200`
|
|
957
|
+
```json
|
|
958
|
+
{
|
|
959
|
+
"plan_id": "vdZScM0uu4It",
|
|
960
|
+
"llm_run_id": "abc123def456",
|
|
961
|
+
"applied": false,
|
|
962
|
+
"plan": {
|
|
963
|
+
"actions": [
|
|
964
|
+
{
|
|
965
|
+
"type": "create_task",
|
|
966
|
+
"temp_id": "t0",
|
|
967
|
+
"title": "Implement Dark Mode Support",
|
|
968
|
+
"description": "Add a global dark mode toggle...",
|
|
969
|
+
"detail_text": "",
|
|
970
|
+
"status": "todo",
|
|
971
|
+
"parent_id": null,
|
|
972
|
+
"parent_temp_id": null
|
|
973
|
+
},
|
|
974
|
+
{
|
|
975
|
+
"type": "create_task",
|
|
976
|
+
"temp_id": "t1",
|
|
977
|
+
"title": "Theme Configuration Store",
|
|
978
|
+
"parent_temp_id": "t0",
|
|
979
|
+
"...": "..."
|
|
980
|
+
}
|
|
981
|
+
],
|
|
982
|
+
"root_temp_id": "t0",
|
|
983
|
+
"rationale": "Breaking down into theme store, component updates, and toggle UI..."
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
```
|
|
987
|
+
|
|
988
|
+
**Errors**
|
|
989
|
+
- `400` — missing `text`, invalid status/project/parent, LLM not enabled
|
|
990
|
+
- `502` — LLM response parsing failure
|
|
991
|
+
|
|
992
|
+
---
|
|
993
|
+
|
|
994
|
+
## AI: Project Init
|
|
995
|
+
|
|
996
|
+
### `POST /api/ai/projects/:id/init`
|
|
997
|
+
|
|
998
|
+
Scans a local repository and generates a project scope description. Optionally creates seed tasks.
|
|
999
|
+
|
|
1000
|
+
**Request**
|
|
1001
|
+
```json
|
|
1002
|
+
{
|
|
1003
|
+
"path": "c:/xampp/htdocs/KanbanDashboard",
|
|
1004
|
+
"create_seed_tasks": true,
|
|
1005
|
+
"max_depth": 3,
|
|
1006
|
+
"apply": true
|
|
1007
|
+
}
|
|
1008
|
+
```
|
|
1009
|
+
|
|
1010
|
+
| Field | Type | Required | Default | Notes |
|
|
1011
|
+
|-------|------|----------|---------|-------|
|
|
1012
|
+
| `path` | string | yes | — | Local filesystem path to scan |
|
|
1013
|
+
| `create_seed_tasks` | boolean | no | `false` | Generate initial tasks |
|
|
1014
|
+
| `max_depth` | number | no | `3` | Max task nesting (1–6) |
|
|
1015
|
+
| `apply` | boolean | no | `true` | `false` for dry-run |
|
|
1016
|
+
|
|
1017
|
+
**Path restrictions** — controlled by environment variables:
|
|
1018
|
+
- `AI_INIT_ALLOWED_ROOTS` — comma-separated list of allowed root paths
|
|
1019
|
+
- `AI_INIT_ALLOW_ANY=1` — allow any path (for development)
|
|
1020
|
+
|
|
1021
|
+
**Response (apply=true)** `200`
|
|
1022
|
+
```json
|
|
1023
|
+
{
|
|
1024
|
+
"plan_id": "abc123",
|
|
1025
|
+
"llm_run_id": "def456",
|
|
1026
|
+
"applied": true,
|
|
1027
|
+
"project": {
|
|
1028
|
+
"id": "pH1ZSGuW5i",
|
|
1029
|
+
"name": "My Project",
|
|
1030
|
+
"scope_text": "# Jarvis Kanban Dashboard\n\nAn intelligent task management system...",
|
|
1031
|
+
"...": "..."
|
|
1032
|
+
},
|
|
1033
|
+
"scope_text": "# Jarvis Kanban Dashboard\n\nAn intelligent task management system...",
|
|
1034
|
+
"created_tasks": [
|
|
1035
|
+
{ "id": "J8ijTp_Mr_", "title": "Implement Cron Sync Agent", "parent_id": null, "...": "..." },
|
|
1036
|
+
{ "id": "WUNcgBsi5r", "title": "Add Frontend Tests", "parent_id": null, "...": "..." }
|
|
1037
|
+
]
|
|
1038
|
+
}
|
|
1039
|
+
```
|
|
1040
|
+
|
|
1041
|
+
The project's `scope_text` is updated in the database when `apply=true`.
|
|
1042
|
+
|
|
1043
|
+
**Errors**
|
|
1044
|
+
- `404` — project not found
|
|
1045
|
+
- `400` — path not allowed, LLM not enabled
|
|
1046
|
+
- `502` — LLM response parsing failure
|
|
1047
|
+
|
|
1048
|
+
---
|
|
1049
|
+
|
|
1050
|
+
## AI: Evolve Hierarchy
|
|
1051
|
+
|
|
1052
|
+
### `POST /api/ai/projects/:id/evolve`
|
|
1053
|
+
|
|
1054
|
+
Proposes and optionally creates new tasks to advance a project toward a goal.
|
|
1055
|
+
|
|
1056
|
+
**Request**
|
|
1057
|
+
```json
|
|
1058
|
+
{
|
|
1059
|
+
"goal": "Add comprehensive error handling and logging across all API endpoints",
|
|
1060
|
+
"max_depth": 3,
|
|
1061
|
+
"max_new_tasks": 15,
|
|
1062
|
+
"apply": true
|
|
1063
|
+
}
|
|
1064
|
+
```
|
|
1065
|
+
|
|
1066
|
+
| Field | Type | Required | Default | Notes |
|
|
1067
|
+
|-------|------|----------|---------|-------|
|
|
1068
|
+
| `goal` | string | no | `""` | Direction for evolution |
|
|
1069
|
+
| `max_depth` | number | no | `3` | Max nesting (1–6) |
|
|
1070
|
+
| `max_new_tasks` | number | no | `15` | Max tasks to create (1–50) |
|
|
1071
|
+
| `apply` | boolean | no | `true` | `false` for dry-run |
|
|
1072
|
+
|
|
1073
|
+
**Response (apply=true)** `200`
|
|
1074
|
+
```json
|
|
1075
|
+
{
|
|
1076
|
+
"plan_id": "j527T-MwDM2a",
|
|
1077
|
+
"llm_run_id": "abc123",
|
|
1078
|
+
"applied": true,
|
|
1079
|
+
"rationale": "Created error handling epic with 5 sub-tasks...",
|
|
1080
|
+
"created_tasks": [
|
|
1081
|
+
{ "id": "3ACdJSHHJx", "title": "Implement Comprehensive Error Handling", "parent_id": null, "...": "..." },
|
|
1082
|
+
{ "id": "ePdlgfl6Ex", "title": "Backend: Integrate Structured Logger", "parent_id": "3ACdJSHHJx", "...": "..." }
|
|
1083
|
+
]
|
|
1084
|
+
}
|
|
1085
|
+
```
|
|
1086
|
+
|
|
1087
|
+
New tasks default to `status: "ideas"`.
|
|
1088
|
+
|
|
1089
|
+
**Response (apply=false)** `200`
|
|
1090
|
+
```json
|
|
1091
|
+
{
|
|
1092
|
+
"plan_id": "qr-yO9eaQhGT",
|
|
1093
|
+
"llm_run_id": "abc123",
|
|
1094
|
+
"applied": false,
|
|
1095
|
+
"plan": {
|
|
1096
|
+
"actions": [ "...create_task actions..." ],
|
|
1097
|
+
"rationale": "..."
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
```
|
|
1101
|
+
|
|
1102
|
+
**Errors**
|
|
1103
|
+
- `404` — project not found
|
|
1104
|
+
- `400` — LLM not enabled
|
|
1105
|
+
- `502` — LLM response parsing failure
|
|
1106
|
+
|
|
1107
|
+
---
|
|
1108
|
+
|
|
1109
|
+
## AI: Remove Concept
|
|
1110
|
+
|
|
1111
|
+
### `POST /api/ai/projects/:id/remove-concept`
|
|
1112
|
+
|
|
1113
|
+
Uses the LLM to identify tasks related to a concept and either soft-deletes them or moves them to the Ideas column.
|
|
1114
|
+
|
|
1115
|
+
**Request**
|
|
1116
|
+
```json
|
|
1117
|
+
{
|
|
1118
|
+
"concept": "CI/CD pipeline",
|
|
1119
|
+
"mode": "soft_delete",
|
|
1120
|
+
"apply": true
|
|
1121
|
+
}
|
|
1122
|
+
```
|
|
1123
|
+
|
|
1124
|
+
| Field | Type | Required | Default | Notes |
|
|
1125
|
+
|-------|------|----------|---------|-------|
|
|
1126
|
+
| `concept` | string | yes | — | The concept to remove |
|
|
1127
|
+
| `mode` | string | no | `"soft_delete"` | `"soft_delete"` or `"move_to_ideas"` |
|
|
1128
|
+
| `apply` | boolean | no | `true` | `false` for dry-run |
|
|
1129
|
+
|
|
1130
|
+
**Response (apply=true)** `200`
|
|
1131
|
+
```json
|
|
1132
|
+
{
|
|
1133
|
+
"plan_id": "cLO1xMRFvlKn",
|
|
1134
|
+
"llm_run_id": "c_9np7nnEVBC",
|
|
1135
|
+
"applied": true,
|
|
1136
|
+
"rationale": "Removing the CI/CD task as requested...",
|
|
1137
|
+
"affected_ids": ["8yNV7C0S4K"],
|
|
1138
|
+
"affected_count": 1
|
|
1139
|
+
}
|
|
1140
|
+
```
|
|
1141
|
+
|
|
1142
|
+
**Mode behavior**
|
|
1143
|
+
- `soft_delete` — sets `deleted_at` on matched tasks; they no longer appear in listings
|
|
1144
|
+
- `move_to_ideas` — sets `status = 'ideas'` on matched tasks
|
|
1145
|
+
|
|
1146
|
+
**Errors**
|
|
1147
|
+
- `404` — project not found
|
|
1148
|
+
- `400` — missing concept, LLM not enabled
|
|
1149
|
+
- `502` — LLM response parsing failure
|
|
1150
|
+
|
|
1151
|
+
---
|
|
1152
|
+
|
|
1153
|
+
## Error Handling
|
|
1154
|
+
|
|
1155
|
+
All errors return JSON:
|
|
1156
|
+
|
|
1157
|
+
```json
|
|
1158
|
+
{ "error": "description of the error" }
|
|
1159
|
+
```
|
|
1160
|
+
|
|
1161
|
+
**Status codes**
|
|
1162
|
+
|
|
1163
|
+
| Code | Meaning |
|
|
1164
|
+
|------|---------|
|
|
1165
|
+
| `400` | Bad request — validation error, missing required field |
|
|
1166
|
+
| `401` | Unauthorized — invalid or missing `X-API-Key` (AI endpoints only, when configured) |
|
|
1167
|
+
| `404` | Not found — resource doesn't exist or is soft-deleted |
|
|
1168
|
+
| `429` | Rate limited — AI endpoint rate limit exceeded |
|
|
1169
|
+
| `502` | Bad gateway — LLM returned unparseable or invalid response |
|
|
1170
|
+
|
|
1171
|
+
**API route guard** — any `GET /api/*` route that doesn't match a defined endpoint returns `404` JSON (not the SPA HTML fallback). Non-API routes serve the frontend.
|
|
1172
|
+
|
|
1173
|
+
---
|
|
1174
|
+
|
|
1175
|
+
## Object Schemas
|
|
1176
|
+
|
|
1177
|
+
### Task
|
|
1178
|
+
|
|
1179
|
+
```typescript
|
|
1180
|
+
{
|
|
1181
|
+
id: string, // nanoid
|
|
1182
|
+
title: string,
|
|
1183
|
+
description: string,
|
|
1184
|
+
status: string, // "ideas" | "todo" | "in_progress" | "review" | "testing" | "done"
|
|
1185
|
+
detail_text: string,
|
|
1186
|
+
project_id: string,
|
|
1187
|
+
parent_id: string | null,
|
|
1188
|
+
deleted_at: number | null, // soft-delete timestamp (ms) or null
|
|
1189
|
+
created_at: number, // Unix ms
|
|
1190
|
+
updated_at: number // Unix ms
|
|
1191
|
+
}
|
|
1192
|
+
```
|
|
1193
|
+
|
|
1194
|
+
### Automation Task
|
|
1195
|
+
|
|
1196
|
+
```typescript
|
|
1197
|
+
{
|
|
1198
|
+
id: string,
|
|
1199
|
+
type: "recurring" | "scheduled",
|
|
1200
|
+
title: string,
|
|
1201
|
+
description: string,
|
|
1202
|
+
status: string, // "ideas" | "active"
|
|
1203
|
+
detail_text: string,
|
|
1204
|
+
project_id: string,
|
|
1205
|
+
schedule_kind: "cron" | "at",
|
|
1206
|
+
expr: string | null, // cron expression
|
|
1207
|
+
tz: string | null, // timezone
|
|
1208
|
+
at_iso: string | null, // ISO 8601 datetime
|
|
1209
|
+
cron_job_id: string | null, // external cron service ID
|
|
1210
|
+
cron_enabled: 0 | 1,
|
|
1211
|
+
last_synced_at: number | null,
|
|
1212
|
+
last_sync_error: string | null,
|
|
1213
|
+
created_at: number,
|
|
1214
|
+
updated_at: number
|
|
1215
|
+
}
|
|
1216
|
+
```
|
|
1217
|
+
|
|
1218
|
+
### Project
|
|
1219
|
+
|
|
1220
|
+
```typescript
|
|
1221
|
+
{
|
|
1222
|
+
id: string,
|
|
1223
|
+
name: string,
|
|
1224
|
+
scope_text: string,
|
|
1225
|
+
created_at: number,
|
|
1226
|
+
updated_at: number,
|
|
1227
|
+
task_count?: number, // only in GET /api/projects list
|
|
1228
|
+
automation_count?: number // only in GET /api/projects list
|
|
1229
|
+
}
|
|
1230
|
+
```
|
|
1231
|
+
|
|
1232
|
+
### Comment
|
|
1233
|
+
|
|
1234
|
+
```typescript
|
|
1235
|
+
{
|
|
1236
|
+
id: number,
|
|
1237
|
+
entity_type: "task" | "recurring" | "scheduled",
|
|
1238
|
+
entity_id: string,
|
|
1239
|
+
author: string,
|
|
1240
|
+
text: string,
|
|
1241
|
+
created_at: number
|
|
1242
|
+
}
|
|
1243
|
+
```
|
|
1244
|
+
|
|
1245
|
+
### Progress Update
|
|
1246
|
+
|
|
1247
|
+
```typescript
|
|
1248
|
+
{
|
|
1249
|
+
id: number,
|
|
1250
|
+
entity_type: "task" | "recurring" | "scheduled",
|
|
1251
|
+
entity_id: string,
|
|
1252
|
+
author: string,
|
|
1253
|
+
text: string,
|
|
1254
|
+
created_at: number
|
|
1255
|
+
}
|
|
1256
|
+
```
|