@basementuniverse/kanbn 1.1.0 → 2.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/README.md +2 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/coverage-summary.json +31 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +146 -0
- package/coverage/kanbn/index.html +116 -0
- package/coverage/kanbn/index.js.html +217 -0
- package/coverage/kanbn/src/board.js.html +646 -0
- package/coverage/kanbn/src/controller/add.js.html +1729 -0
- package/coverage/kanbn/src/controller/archive.js.html +277 -0
- package/coverage/kanbn/src/controller/board.js.html +217 -0
- package/coverage/kanbn/src/controller/burndown.js.html +607 -0
- package/coverage/kanbn/src/controller/comment.js.html +397 -0
- package/coverage/kanbn/src/controller/edit.js.html +2920 -0
- package/coverage/kanbn/src/controller/find.js.html +1597 -0
- package/coverage/kanbn/src/controller/gantt.js.html +1342 -0
- package/coverage/kanbn/src/controller/help.js.html +115 -0
- package/coverage/kanbn/src/controller/history.js.html +400 -0
- package/coverage/kanbn/src/controller/index.html +431 -0
- package/coverage/kanbn/src/controller/init.js.html +511 -0
- package/coverage/kanbn/src/controller/move.js.html +514 -0
- package/coverage/kanbn/src/controller/remove-all.js.html +226 -0
- package/coverage/kanbn/src/controller/remove.js.html +307 -0
- package/coverage/kanbn/src/controller/rename.js.html +397 -0
- package/coverage/kanbn/src/controller/restore.js.html +268 -0
- package/coverage/kanbn/src/controller/sort.js.html +1318 -0
- package/coverage/kanbn/src/controller/sprint.js.html +361 -0
- package/coverage/kanbn/src/controller/status.js.html +310 -0
- package/coverage/kanbn/src/controller/task.js.html +244 -0
- package/coverage/kanbn/src/controller/validate.js.html +367 -0
- package/coverage/kanbn/src/controller/version.js.html +100 -0
- package/coverage/kanbn/src/index.html +191 -0
- package/coverage/kanbn/src/main.js.html +9787 -0
- package/coverage/kanbn/src/parse-index.js.html +1063 -0
- package/coverage/kanbn/src/parse-markdown.js.html +202 -0
- package/coverage/kanbn/src/parse-task.js.html +2191 -0
- package/coverage/kanbn/src/utility.js.html +616 -0
- package/coverage/lcov.info +11837 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/coverage/tmp/coverage-214292-1787777191526-0.json +1 -0
- package/coverage/tmp/coverage-214293-1787777184569-0.json +1 -0
- package/docs/advanced-configuration.md +2 -0
- package/docs/commands/add.txt +10 -0
- package/docs/commands/board.txt +3 -1
- package/docs/commands/burndown.txt +2 -4
- package/docs/commands/edit.txt +22 -0
- package/docs/commands/find.txt +45 -1
- package/docs/commands/help.txt +1 -0
- package/docs/commands/move.txt +1 -1
- package/docs/commands/sort.txt +13 -2
- package/docs/commands/validate.txt +12 -0
- package/docs/filtering-and-sorting.md +218 -0
- package/docs/index-structure.md +68 -19
- package/docs/index.md +26 -2
- package/docs/migration-2.0.md +92 -0
- package/docs/quick-start.md +37 -1
- package/docs/task-structure.md +12 -3
- package/docs/views.md +229 -0
- package/example/README.md +70 -0
- package/example/advanced/.kanbn/index.md +26 -0
- package/example/advanced/.kanbn/tasks/add-rate-limiting.md +18 -0
- package/example/advanced/.kanbn/tasks/add-sso-support.md +15 -0
- package/example/advanced/.kanbn/tasks/migrate-to-new-cdn.md +14 -0
- package/example/advanced/.kanbn/tasks/refresh-marketing-site.md +14 -0
- package/example/advanced/.kanbn/tasks/rotate-api-keys.md +15 -0
- package/example/advanced/.kanbn/tasks/split-billing-service.md +17 -0
- package/example/advanced/.kanbn/tasks/upgrade-node-runtime.md +19 -0
- package/example/advanced/kanbn.yml +59 -0
- package/example/views/.kanbn/index.md +140 -0
- package/example/views/.kanbn/tasks/add-audit-log-export.md +18 -0
- package/example/views/.kanbn/tasks/add-dark-mode-toggle.md +16 -0
- package/example/views/.kanbn/tasks/build-webhook-retry-queue.md +15 -0
- package/example/views/.kanbn/tasks/fix-avatar-upload-crash.md +13 -0
- package/example/views/.kanbn/tasks/fix-expired-session-redirect.md +15 -0
- package/example/views/.kanbn/tasks/investigate-offline-mode.md +12 -0
- package/example/views/.kanbn/tasks/rewrite-search-indexer.md +12 -0
- package/example/views/.kanbn/tasks/tidy-up-settings-copy.md +12 -0
- package/package.json +4 -3
- package/routes/edit.json +2 -1
- package/routes/validate.json +4 -2
- package/skills/kanbn-plan/references/index-structure.md +1 -0
- package/skills/kanbn-plan/references/task-structure.md +2 -0
- package/src/board.js +1 -0
- package/src/controller/board.js +6 -0
- package/src/controller/edit.js +65 -12
- package/src/controller/gantt.js +46 -1
- package/src/controller/status.js +12 -0
- package/src/controller/task.js +1 -1
- package/src/controller/validate.js +78 -15
- package/src/main.js +324 -152
- package/src/parse-index.js +3 -0
- package/src/parse-markdown.js +3 -1
- package/src/parse-task.js +28 -1
- package/src/utility.js +26 -1
- /package/example/{.kanbn → basic/.kanbn}/index.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/add-basic-activity-feed.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/add-passwordless-login-option.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/add-usage-alert-email-thresholds.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/build-email-template-system.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/build-invoice-download-endpoint.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/build-tenant-settings-page.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/create-organization-switcher.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/create-sandbox-environment-provisioner.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/create-self-serve-cancellation-flow.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/define-product-pricing-strategy.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/design-onboarding-checklist.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/design-team-invite-expiry-flow.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/implement-data-retention-policy-jobs.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/implement-feature-flags-foundation.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/implement-project-creation-wizard.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/implement-stripe-webhook-signature-check.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/implement-team-permissions-ui.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/implement-user-signup-and-login.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/integrate-crm-lead-sync.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/legal-review-terms-and-privacy.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/migrate-legacy-events-to-new-schema.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/optimize-dashboard-first-load.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/prototype-report-export-scheduler.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/publish-internal-qa-checklist.md +0 -0
- /package/example/{.kanbn → basic/.kanbn}/tasks/setup-ci-pipeline.md +0 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Filtering and Sorting
|
|
2
|
+
|
|
3
|
+
Kanbn uses one shared filtering model and one shared sorting model. They are used by:
|
|
4
|
+
|
|
5
|
+
| Feature | Filters | Sorters |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| `kanbn find` | yes (CLI options) | no |
|
|
8
|
+
| `kanbn sort` | no | yes (CLI options) |
|
|
9
|
+
| `columnSorting` project option | no | yes |
|
|
10
|
+
| [Views](views.md) (root, column and lane filters) | yes | yes (per view column) |
|
|
11
|
+
|
|
12
|
+
`kanbn status`, `kanbn burndown`, `kanbn gantt` and `kanbn history` have their own simpler `--column` / `--assigned` / `--date` / `--sprint` options and don't use this model.
|
|
13
|
+
|
|
14
|
+
## Filters
|
|
15
|
+
|
|
16
|
+
A filter set is a map of field names to filter values. **A task must match every filter in the set** (filters are combined with AND). An empty filter set matches all tasks.
|
|
17
|
+
|
|
18
|
+
On the command line each `kanbn find` option is one filter. In the index options a filter set is a YAML object:
|
|
19
|
+
|
|
20
|
+
```yaml
|
|
21
|
+
filters:
|
|
22
|
+
column: 'In Progress'
|
|
23
|
+
tag: Bug
|
|
24
|
+
workload:
|
|
25
|
+
- 3
|
|
26
|
+
- 8
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Filter fields
|
|
30
|
+
|
|
31
|
+
| Field | `kanbn find` option | Type | Matched against |
|
|
32
|
+
| --- | --- | --- | --- |
|
|
33
|
+
| `id` | `--id` | string | The task id (the task filename without `.md`) |
|
|
34
|
+
| `name` | `--name`, `-n` | string | The task name (level-1 heading) |
|
|
35
|
+
| `description` | `--description`, `-d` | string | The task description |
|
|
36
|
+
| `column` | `--column`, `-c` | string | The name of the column the task is currently in |
|
|
37
|
+
| `created` | `--created` | date | `created` metadata |
|
|
38
|
+
| `updated` | `--updated` | date | `updated` metadata |
|
|
39
|
+
| `started` | `--started` | date | `started` metadata |
|
|
40
|
+
| `completed` | `--completed` | date | `completed` metadata |
|
|
41
|
+
| `due` | `--due`, `-e` | date | `due` metadata |
|
|
42
|
+
| `plannedStart` | `--plannedStart` | date | `plannedStart` metadata |
|
|
43
|
+
| `plannedFinish` | `--plannedFinish` | date | `plannedFinish` metadata |
|
|
44
|
+
| `assigned` | `--assigned` | string | `assigned` metadata (empty string if unset) |
|
|
45
|
+
| `workload` | `--workload` | number | The task's [calculated workload](index-structure.md#taskworkloadtags) |
|
|
46
|
+
| `progress` | `--progress` | number | The task's [calculated progress](task-structure.md#progress) |
|
|
47
|
+
| `sub-task` | `--sub-task`, `-s` | string | All sub-tasks, one per line, as `[ ] text` or `[x] text` |
|
|
48
|
+
| `count-sub-tasks` | `--count-sub-tasks` | number | Number of sub-tasks |
|
|
49
|
+
| `tag` | `--tag`, `-t` | string | All tags, one per line |
|
|
50
|
+
| `count-tags` | `--count-tags` | number | Number of tags |
|
|
51
|
+
| `relation` | `--relation`, `-r` | string | All relations, one per line, as `type task-id` |
|
|
52
|
+
| `count-relations` | `--count-relations` | number | Number of relations |
|
|
53
|
+
| `comment` | `--comment` | string | All comments, one per line, as `author text` |
|
|
54
|
+
| `count-comments` | `--count-comments` | number | Number of comments |
|
|
55
|
+
| *custom field name* | `--<custom field name>` | declared type | The custom field value in the task metadata |
|
|
56
|
+
|
|
57
|
+
Custom fields must be declared in the [`customFields`](index-structure.md#customfields) project option before they can be filtered on.
|
|
58
|
+
|
|
59
|
+
A task that doesn't have the metadata field being filtered on never matches a date filter or a custom field filter. Missing `assigned` is treated as an empty string, missing `tags`/sub-tasks/relations/comments are treated as empty.
|
|
60
|
+
|
|
61
|
+
*Note: `hiddenColumns` only affects the board. `kanbn find` still returns tasks in hidden columns unless you filter them out with `column`.*
|
|
62
|
+
|
|
63
|
+
### String filters
|
|
64
|
+
|
|
65
|
+
String filter values are **case-insensitive regular expressions**, matched anywhere in the value (not anchored). Passing an array (or repeating a CLI option) joins the values with `|`, so an array means "match any of these":
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
kanbn find --column Todo --column "In Progress"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
```yaml
|
|
72
|
+
filters:
|
|
73
|
+
column:
|
|
74
|
+
- Todo
|
|
75
|
+
- 'In Progress'
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Multi-value fields (`tag`, `sub-task`, `relation`, `comment`) are flattened into a single newline-separated string before matching. The regex is **not** built with the multiline flag, so `^` and `$` anchor to the start and end of that whole string, not to each line. To match a single value exactly, anchor on the line breaks instead:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Matches "Bug", but also "Debug" and "Bugfix"
|
|
82
|
+
kanbn find --tag Bug
|
|
83
|
+
|
|
84
|
+
# Matches only the exact tag "Bug"
|
|
85
|
+
kanbn find --tag '(^|\n)Bug($|\n)'
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Date filters
|
|
89
|
+
|
|
90
|
+
A single date matches any task whose date falls on **the same calendar day** — the time part is ignored:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
kanbn find --due "20 July 2026"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Two or more dates match any task whose date falls **between the earliest and latest** of them (inclusive, times included):
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
kanbn find --due "1 July 2026" --due "31 July 2026"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
On the command line dates are parsed with [chrono](https://github.com/wanasit/chrono), so almost any format works, including relative dates like `"yesterday"` or `"next friday"`. In YAML, write dates as plain YAML timestamps:
|
|
103
|
+
|
|
104
|
+
```yaml
|
|
105
|
+
filters:
|
|
106
|
+
due:
|
|
107
|
+
- 2026-07-01
|
|
108
|
+
- 2026-07-31
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Number filters
|
|
112
|
+
|
|
113
|
+
A single number matches that number exactly. Two or more numbers match anything between the lowest and highest (inclusive):
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
kanbn find --workload 5 # exactly 5
|
|
117
|
+
kanbn find --workload 3 --workload 8 # between 3 and 8
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Boolean filters
|
|
121
|
+
|
|
122
|
+
Boolean filters only apply to custom fields with type `boolean`, and are matched by exact equality. On the command line, `--<name>` matches `true` and `--no-<name>` matches `false`:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
kanbn find --needsDesign # tasks where needsDesign is true
|
|
126
|
+
kanbn find --no-needsDesign # tasks where needsDesign is false
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Sorters
|
|
130
|
+
|
|
131
|
+
A sorter list is an ordered array. Tasks are compared using the first sorter; ties are broken using the next one, and so on. Each sorter is an object:
|
|
132
|
+
|
|
133
|
+
```yaml
|
|
134
|
+
sorters:
|
|
135
|
+
- field: workload
|
|
136
|
+
order: descending
|
|
137
|
+
- field: name
|
|
138
|
+
filter: ''
|
|
139
|
+
order: ascending
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
| Property | Required | Description |
|
|
143
|
+
| --- | --- | --- |
|
|
144
|
+
| `field` | yes | The task field to sort by |
|
|
145
|
+
| `order` | no | `ascending` (default) or `descending` |
|
|
146
|
+
| `filter` | no | A regex used to transform values before comparing them (see below) |
|
|
147
|
+
|
|
148
|
+
Strings are compared with `localeCompare` (accent-sensitive, case-insensitive); dates and numbers are compared numerically.
|
|
149
|
+
|
|
150
|
+
### Sort filters
|
|
151
|
+
|
|
152
|
+
The `filter` property is **not** a search filter — it extracts part of each value before comparing. The regex is applied globally and case-insensitively, and:
|
|
153
|
+
|
|
154
|
+
- if it has named capturing groups, the contents of all named groups are concatenated;
|
|
155
|
+
- otherwise, if it has numbered capturing groups, the contents of the first group are used;
|
|
156
|
+
- otherwise, the whole match is used;
|
|
157
|
+
- if there are multiple matches, their results are concatenated.
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# Sort by the number in task names like "Task 12", not by the whole name
|
|
161
|
+
kanbn sort "Todo" --name "Task (\d+)"
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Sortable fields
|
|
165
|
+
|
|
166
|
+
`kanbn sort` and `columnSorting` can sort by any of these. Note that the `field` value written in YAML is **not** always the same as the command line option:
|
|
167
|
+
|
|
168
|
+
| `field` value | `kanbn sort` option |
|
|
169
|
+
| --- | --- |
|
|
170
|
+
| `id` | `--id` |
|
|
171
|
+
| `name` | `--name`, `-n` |
|
|
172
|
+
| `description` | `--description`, `-d` |
|
|
173
|
+
| `created` | `--created` |
|
|
174
|
+
| `updated` | `--updated` |
|
|
175
|
+
| `started` | `--started` |
|
|
176
|
+
| `completed` | `--completed` |
|
|
177
|
+
| `due` | `--due`, `-e` |
|
|
178
|
+
| `plannedStart` | `--plannedStart` |
|
|
179
|
+
| `plannedFinish` | `--plannedFinish` |
|
|
180
|
+
| `assigned` | `--assigned` |
|
|
181
|
+
| `workload` | `--workload`, `-w` |
|
|
182
|
+
| `progress` | `--progress` |
|
|
183
|
+
| `subTasks` | `--sub-task`, `-s` |
|
|
184
|
+
| `countSubTasks` | `--count-sub-tasks` |
|
|
185
|
+
| `tags` | `--tag`, `-t` |
|
|
186
|
+
| `countTags` | `--count-tags` |
|
|
187
|
+
| `relations` | `--relation`, `-r` |
|
|
188
|
+
| `countRelations` | `--count-relations` |
|
|
189
|
+
| `comments` | `--comment` |
|
|
190
|
+
| `countComments` | `--count-comments` |
|
|
191
|
+
| *custom field name* | `--<custom field name>` |
|
|
192
|
+
|
|
193
|
+
[View](views.md) column `sorters` accept all of the same fields, plus `column` (the index column the task is currently in), which is useful in a view whose columns don't map onto index columns.
|
|
194
|
+
|
|
195
|
+
A view sorter only changes the order within that view. To order a column permanently, use `columnSorting` — that ordering is written to the index itself, and view columns with no `sorters` of their own inherit it.
|
|
196
|
+
|
|
197
|
+
## Persistent column sorting
|
|
198
|
+
|
|
199
|
+
`columnSorting` keeps a column sorted in the index file itself, so the order survives `kanbn add`, `kanbn move` and `kanbn validate --save`:
|
|
200
|
+
|
|
201
|
+
```yaml
|
|
202
|
+
columnSorting:
|
|
203
|
+
Backlog:
|
|
204
|
+
- field: workload
|
|
205
|
+
order: descending
|
|
206
|
+
- field: name
|
|
207
|
+
order: ascending
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
You can also write this from the command line:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
kanbn sort "Backlog" --workload -z --name -a --save
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Running `kanbn sort "Backlog"` **without** `--save` removes any saved sorting settings for that column after applying the sort once.
|
|
217
|
+
|
|
218
|
+
See `kanbn find --help` and `kanbn sort --help` for the full list of command line options, and [Views](views.md) for filters and sorters inside board views.
|
package/docs/index-structure.md
CHANGED
|
@@ -67,23 +67,23 @@ taskTemplate: ""
|
|
|
67
67
|
dateFormat: ""
|
|
68
68
|
views:
|
|
69
69
|
- name: My view 1
|
|
70
|
+
filters:
|
|
71
|
+
tag: Bug
|
|
70
72
|
columns:
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
sorters:
|
|
79
|
-
- field: name
|
|
80
|
-
filter: ""
|
|
81
|
-
order: ascending
|
|
82
|
-
lanes:
|
|
83
|
-
- name: "Lane 1"
|
|
84
|
-
filter:
|
|
73
|
+
- name: Column 1
|
|
74
|
+
filters:
|
|
75
|
+
name: test
|
|
76
|
+
workload:
|
|
77
|
+
- 1
|
|
78
|
+
- 5
|
|
79
|
+
sorters:
|
|
85
80
|
- field: name
|
|
86
81
|
filter: ""
|
|
82
|
+
order: ascending
|
|
83
|
+
lanes:
|
|
84
|
+
- name: Lane 1
|
|
85
|
+
filters:
|
|
86
|
+
assigned: username
|
|
87
87
|
customFields:
|
|
88
88
|
- name: 'myCustomField'
|
|
89
89
|
type: 'date'
|
|
@@ -95,13 +95,40 @@ customFields:
|
|
|
95
95
|
|
|
96
96
|
A list of column names. These columns will be hidden from the kanbn board.
|
|
97
97
|
|
|
98
|
+
This only affects the default board layout. Tasks in hidden columns are still tracked, still show up in `kanbn find` and `kanbn status`, and are still shown by any [view](views.md) that defines its own `columns`.
|
|
99
|
+
|
|
98
100
|
### `startedColumns`
|
|
99
101
|
|
|
100
102
|
A list of column names. When a task is created in or dragged into one of these columns, the task's `started` date will be set to the current time, unless the task already has a 'started' date.
|
|
101
103
|
|
|
102
104
|
### `completedColumns`
|
|
103
105
|
|
|
104
|
-
A list of column names. When a task is created in or dragged into one of these columns, the task's `completed` date will be set to the current time
|
|
106
|
+
A list of column names. When a task is created in or dragged into one of these columns, the task's `completed` date will be set to the current time, unless the task already has a `completed` date.
|
|
107
|
+
|
|
108
|
+
Note that these columns control when the date is *written*. They don't decide whether a task counts as complete - that comes from the date itself. See [Task state](#task-state) below.
|
|
109
|
+
|
|
110
|
+
### `startedField`
|
|
111
|
+
|
|
112
|
+
The name of the metadata field that holds a task's started date. Defaults to `started`.
|
|
113
|
+
|
|
114
|
+
### `completedField`
|
|
115
|
+
|
|
116
|
+
The name of the metadata field that holds a task's completed date. Defaults to `completed`.
|
|
117
|
+
|
|
118
|
+
Pointing these at custom date fields lets a board track its own started/completed state without touching the shared `started` and `completed` fields:
|
|
119
|
+
|
|
120
|
+
```yaml
|
|
121
|
+
completedField: designSignedOffAt
|
|
122
|
+
completedColumns:
|
|
123
|
+
- Signed Off
|
|
124
|
+
customFields:
|
|
125
|
+
- name: designSignedOffAt
|
|
126
|
+
type: date
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### `verbose`
|
|
130
|
+
|
|
131
|
+
Set to `false` to suppress hints and notices printed alongside normal output, such as the reminder shown when tasks have dates that don't match their column. Defaults to `true`. Hints are never shown when using `--json`.
|
|
105
132
|
|
|
106
133
|
### `sprints`
|
|
107
134
|
|
|
@@ -123,7 +150,9 @@ An associative array of column names and sorters. Each column can have an array
|
|
|
123
150
|
|
|
124
151
|
The `filter` property can be used to transform values before sorting.
|
|
125
152
|
|
|
126
|
-
|
|
153
|
+
Columns listed here are re-sorted every time Kanbn writes the index, so the order survives `kanbn add`, `kanbn move` and `kanbn validate --save`.
|
|
154
|
+
|
|
155
|
+
See [Filtering and Sorting](filtering-and-sorting.md#sorters), or run `kanbn sort --help`.
|
|
127
156
|
|
|
128
157
|
### `taskTemplate`
|
|
129
158
|
|
|
@@ -137,6 +166,7 @@ updated
|
|
|
137
166
|
started
|
|
138
167
|
completed
|
|
139
168
|
due
|
|
169
|
+
assigned
|
|
140
170
|
tags
|
|
141
171
|
subTasks
|
|
142
172
|
relations
|
|
@@ -149,6 +179,8 @@ progress
|
|
|
149
179
|
{...customFields}
|
|
150
180
|
```
|
|
151
181
|
|
|
182
|
+
*Note: referencing a variable that isn't in the list above (or a custom field that isn't declared in `customFields`) will print "Unable to build task template" instead of rendering the board.*
|
|
183
|
+
|
|
152
184
|
The default task template is `^+^_${overdue ? '^R' : ''}${name}^: ${created ? ('\\n^-^/' + created) : ''}`.
|
|
153
185
|
|
|
154
186
|
This string can contain markup sequences. See [terminal-kit](https://github.com/cronvel/terminal-kit/blob/21607fb51749853dd9193c6aaf205b14c63b2768/doc/markup.md#markup) for markup reference.
|
|
@@ -161,11 +193,13 @@ The date format to use for dates on the kanbn board and burndown chart views. Se
|
|
|
161
193
|
|
|
162
194
|
### `views`
|
|
163
195
|
|
|
164
|
-
An array of views that can be used to customize how the kanbn board is displayed.
|
|
196
|
+
An array of views that can be used to customize how the kanbn board is displayed. Select a view with `kanbn board --view "name"`.
|
|
197
|
+
|
|
198
|
+
Each view has a required `name`, an optional root `filters` object, an optional array of `columns` and an optional array of `lanes`. Each column has a required `name` and optional `filters` and `sorters`. Each lane has a required `name` and optional `filters`.
|
|
165
199
|
|
|
166
|
-
|
|
200
|
+
If `columns` is omitted, the index columns are used (minus `hiddenColumns`). If `lanes` is omitted, a single lane containing all matching tasks is used.
|
|
167
201
|
|
|
168
|
-
|
|
202
|
+
See [Views](views.md) for a full description and worked examples, and [Filtering and Sorting](filtering-and-sorting.md) for the filter and sorter formats.
|
|
169
203
|
|
|
170
204
|
### `customFields`
|
|
171
205
|
|
|
@@ -204,3 +238,18 @@ Here's an example of how this could be used:
|
|
|
204
238
|
- Testing
|
|
205
239
|
```
|
|
206
240
|
* When a task is moved into the `Testing` column and the task doesn't already have a `testedAt` value in its metadata, this value will be automatically populated with the current date/time.
|
|
241
|
+
|
|
242
|
+
## Task state
|
|
243
|
+
|
|
244
|
+
Whether a task has started or been completed is decided by its metadata dates, and nothing else:
|
|
245
|
+
|
|
246
|
+
* a task has started if its `started` field is set (or whichever field `startedField` names);
|
|
247
|
+
* a task is complete if its `completed` field is set (or whichever field `completedField` names).
|
|
248
|
+
|
|
249
|
+
The column a task sits in doesn't make it started or complete. Columns listed in `startedColumns` and `completedColumns` cause those dates to be *written* when a task is moved through the CLI or the VSCode extension, but the dates are what everything else reads: `kanbn status`, `kanbn find`, progress, burndown charts and gantt charts.
|
|
250
|
+
|
|
251
|
+
This matters when a task is moved **outside** of kanbn - by editing the index file by hand, or through a git merge. No date is written in that case, so the task keeps whatever state its metadata already described. `kanbn validate` reports tasks whose dates and columns disagree, and `kanbn validate --fix` fills in the missing dates, taking them from the task's history where possible.
|
|
252
|
+
|
|
253
|
+
To clear a date - for example to reopen a task that was completed - use `kanbn edit "task-id" --unset completed`.
|
|
254
|
+
|
|
255
|
+
_Note: before version 2.0.0, a task sitting in a completed column counted as complete even with no `completed` date. See [Migrating to 2.0.0](migration-2.0.md)._
|
package/docs/index.md
CHANGED
|
@@ -7,6 +7,30 @@ To get started quickly, check out the [Quick Start](quick-start.md) guide.
|
|
|
7
7
|
## Contents
|
|
8
8
|
|
|
9
9
|
- [Quick Start](quick-start.md)
|
|
10
|
-
- [Index Structure](index-structure.md)
|
|
11
|
-
- [Task Structure](task-structure.md)
|
|
10
|
+
- [Index Structure](index-structure.md) — the board file and all project options
|
|
11
|
+
- [Task Structure](task-structure.md) — task files, metadata, sub-tasks, relations, comments and history
|
|
12
|
+
- [Views](views.md) — custom board layouts, columns and lanes
|
|
13
|
+
- [Filtering and Sorting](filtering-and-sorting.md) — the filter and sorter model shared by `find`, `sort` and views
|
|
12
14
|
- [Advanced Configuration](advanced-configuration.md)
|
|
15
|
+
- [Migrating to 2.0.0](migration-2.0.md) — separate config files and custom folder locations
|
|
16
|
+
|
|
17
|
+
## Examples
|
|
18
|
+
|
|
19
|
+
The [`example`](../example) directory contains ready-to-run boards:
|
|
20
|
+
|
|
21
|
+
| Example | Demonstrates |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| [`example/basic`](../example/basic) | A typical board: columns, tags, workload, sprints |
|
|
24
|
+
| [`example/views`](../example/views) | Views, lanes, filters and sorters |
|
|
25
|
+
| [`example/advanced`](../example/advanced) | A `kanbn.yml` config file, custom fields, column sorting and a custom task template |
|
|
26
|
+
|
|
27
|
+
Run any Kanbn command from inside one of those directories to try it out.
|
|
28
|
+
|
|
29
|
+
## Command help
|
|
30
|
+
|
|
31
|
+
Every command has built-in help:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
kanbn help <command>
|
|
35
|
+
kanbn <command> --help
|
|
36
|
+
```
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Migrating to 2.0.0
|
|
2
|
+
|
|
3
|
+
Version 2.0.0 changes how kanbn decides whether a task has started or been completed. Everything else about the file format is unchanged: your `index.md` and task files are read and written exactly as before, and no migration step is required to open an existing board.
|
|
4
|
+
|
|
5
|
+
## What changed
|
|
6
|
+
|
|
7
|
+
**Before**, a task counted as complete if *either* it had a `completed` date *or* it was sitting in a column listed in `completedColumns`. The same applied to `started` and `startedColumns` when drawing burndown charts.
|
|
8
|
+
|
|
9
|
+
**Now**, only the dates count. A task has started if its `started` date is set, and it is complete if its `completed` date is set.
|
|
10
|
+
|
|
11
|
+
Columns still cause those dates to be written. Moving a task into a completed column through `kanbn move`, `kanbn edit -c`, or the VSCode extension sets its `completed` date exactly as it did before. What's changed is that the column no longer *stands in for* the date.
|
|
12
|
+
|
|
13
|
+
## Why
|
|
14
|
+
|
|
15
|
+
Inferring state from columns produced results that contradicted themselves and couldn't be corrected:
|
|
16
|
+
|
|
17
|
+
* `kanbn status --due` could report a task as `completed: true` with `completedDate: null` - complete, but with no record of when.
|
|
18
|
+
* Burndown charts substituted a task's **created** date when it had no started date, inventing timings unrelated to when the work happened.
|
|
19
|
+
* State could only ever move forwards. Once a `completed` date was written, moving the task back out of the column didn't clear it, and there was no command that could.
|
|
20
|
+
* A task could be complete on one board and not another purely because of what its columns were called - which becomes a real problem now that a task can appear on several boards.
|
|
21
|
+
|
|
22
|
+
## What you might notice
|
|
23
|
+
|
|
24
|
+
* **Tasks moved by hand.** If you moved a task between columns by editing `index.md` directly, or a git merge moved it, no date was written. Those tasks will now show as not started or not complete.
|
|
25
|
+
* **Burndown charts will look different** for any board where dates and columns disagreed.
|
|
26
|
+
* **Generated boards.** Tasks written by a tool or an AI assistant may sit in `Done` without a `completed` date.
|
|
27
|
+
|
|
28
|
+
Boards that have only ever been driven through the CLI or the VSCode extension already have the right dates and won't change.
|
|
29
|
+
|
|
30
|
+
## Fixing up an existing board
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
kanbn validate
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
reports every task whose dates and column disagree, in both directions:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
2 tasks have dates that don't match their column:
|
|
40
|
+
bravo: task is in column "In Progress" but has no started date
|
|
41
|
+
alpha: task is in column "Done" but has no completed date
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
kanbn validate --fix
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
fills in the missing dates. Each date is taken from the task's own history, where the move into that column is recorded, so the backfilled dates reflect when the move actually happened:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
Filled in 2 missing dates:
|
|
52
|
+
bravo: started set to 2026-08-14T09:12:04.000Z (from history)
|
|
53
|
+
alpha: completed set to 2026-08-19T16:40:11.000Z (from history)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
If a task has no history recording the move, the date falls back to the task's `updated` date, then its `created` date. The source is always reported so you can see which dates were guessed.
|
|
57
|
+
|
|
58
|
+
Tasks that have a `completed` date while sitting **outside** a completed column are reported but never changed - the date records something that really happened, and removing it automatically would lose it.
|
|
59
|
+
|
|
60
|
+
`kanbn board` and `kanbn status` print a one-line reminder when a board has drifted. Set `verbose: false` in your project options to suppress it.
|
|
61
|
+
|
|
62
|
+
## Clearing a date
|
|
63
|
+
|
|
64
|
+
There is now a way to remove a date, which is what makes the dates trustworthy as the single source of truth:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
kanbn edit "my-task" --unset completed
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
This reopens a completed task. It works for `started`, `completed`, `due`, `plannedStart`, `plannedFinish`, `assigned`, `progress`, `tags`, and any custom field. If the same command also moves the task into a completed column, the unset is applied last, so it wins.
|
|
71
|
+
|
|
72
|
+
## Per-board state fields
|
|
73
|
+
|
|
74
|
+
Two new project options, `startedField` and `completedField`, name the metadata fields a board reads and writes. They default to `started` and `completed`.
|
|
75
|
+
|
|
76
|
+
Pointing them at custom date fields lets one task carry separate state for separate workflows:
|
|
77
|
+
|
|
78
|
+
```yaml
|
|
79
|
+
completedField: designSignedOffAt
|
|
80
|
+
completedColumns:
|
|
81
|
+
- Signed Off
|
|
82
|
+
customFields:
|
|
83
|
+
- name: designSignedOffAt
|
|
84
|
+
type: date
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
A board configured this way writes and reads `designSignedOffAt` and leaves the shared `completed` field alone.
|
|
88
|
+
|
|
89
|
+
## Other changes in 2.0.0
|
|
90
|
+
|
|
91
|
+
* **Task ids ending in a single capital letter are now fully lowercased.** `kanbn add -n "Task A"` previously produced the id `task-A`; it now produces `task-a`. Non-ASCII capitals are lowercased too. Existing task files are not renamed.
|
|
92
|
+
* **Unknown history event types and keys are preserved** rather than rejected, so a task file written by a newer version of kanbn stays readable.
|
package/docs/quick-start.md
CHANGED
|
@@ -59,4 +59,40 @@ This will add a "Large" tag to the task and modify the task's updated date. If y
|
|
|
59
59
|
|
|
60
60
|
Run `kanbn edit --help` for more information on editing tasks.
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
## Find tasks
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
kanbn find --tag "Large" --column "Todo"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Filters are combined with AND, string filters are case-insensitive regular expressions, and dates and numbers can be given twice to search a range. See [filtering and sorting](filtering-and-sorting.md) for the full model.
|
|
69
|
+
|
|
70
|
+
## Customise the board
|
|
71
|
+
|
|
72
|
+
Define a view in your project options to re-arrange, filter or group the board without moving any tasks:
|
|
73
|
+
|
|
74
|
+
```yaml
|
|
75
|
+
views:
|
|
76
|
+
- name: 'by-assignee'
|
|
77
|
+
lanes:
|
|
78
|
+
- name: 'Me'
|
|
79
|
+
filters:
|
|
80
|
+
assigned: '^my-username$'
|
|
81
|
+
- name: 'Everyone else'
|
|
82
|
+
filters:
|
|
83
|
+
assigned: '^(?!my-username$).*'
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
kanbn board -v by-assignee
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
See [views](views.md) for columns, lanes, filters and sorters.
|
|
91
|
+
|
|
92
|
+
## Next steps
|
|
93
|
+
|
|
94
|
+
- [Index structure](index-structure.md) — project settings, tags and workload calculations
|
|
95
|
+
- [Task structure](task-structure.md) — task metadata, sub-tasks, relations and comments
|
|
96
|
+
- [Views](views.md) and [filtering and sorting](filtering-and-sorting.md)
|
|
97
|
+
- [Advanced configuration](advanced-configuration.md) — separate config files and custom paths
|
|
98
|
+
- The [`example`](../example) directory contains three ready-to-run boards you can experiment with
|
package/docs/task-structure.md
CHANGED
|
@@ -64,7 +64,7 @@ There should be a single level-1 heading at the top of the markdown body contain
|
|
|
64
64
|
|
|
65
65
|
The task description should appear below the title. The description can be of any length and can contain markdown.
|
|
66
66
|
|
|
67
|
-
The following level-2 headings are reserved for special purposes
|
|
67
|
+
The following level-2 headings are reserved for special purposes (`## Metadata`, `## Sub-tasks`, `## Relations`, `## Comments` and `## History`). Any other level-2 heading is treated as part of the description.
|
|
68
68
|
|
|
69
69
|
## Metadata
|
|
70
70
|
|
|
@@ -106,6 +106,8 @@ The name of the user this task is assigned to.
|
|
|
106
106
|
|
|
107
107
|
The amount of progress for this task. This should be between 0 (not started) and 1 (complete).
|
|
108
108
|
|
|
109
|
+
Progress is not derived from sub-tasks. If the task has no `progress` value it counts as 0, and a task that is considered complete always counts as 1 regardless of this value. A task is considered complete if it has a `completed` date or is in one of the [`completedColumns`](index-structure.md#completedcolumns).
|
|
110
|
+
|
|
109
111
|
### `started`
|
|
110
112
|
|
|
111
113
|
The date and time that the task was started.
|
|
@@ -126,6 +128,14 @@ An optional date and time used as a preferred start point for gantt scheduling.
|
|
|
126
128
|
|
|
127
129
|
An optional date and time used as a preferred finish point for gantt scheduling.
|
|
128
130
|
|
|
131
|
+
### Custom fields
|
|
132
|
+
|
|
133
|
+
Any other metadata field is preserved but otherwise ignored, unless it is declared in the [`customFields`](index-structure.md#customfields) project option. Declared custom fields can be set with `kanbn add` and `kanbn edit`, searched with `kanbn find`, sorted with `kanbn sort`, filtered in [views](views.md), and interpolated into the board's [`taskTemplate`](index-structure.md#tasktemplate).
|
|
134
|
+
|
|
135
|
+
### Workload
|
|
136
|
+
|
|
137
|
+
A task's workload is not stored in the file - it is calculated from the task's `tags`. It is the sum of the values of its [workload tags](index-structure.md#taskworkloadtags), or `defaultTaskWorkload` if it has none.
|
|
138
|
+
|
|
129
139
|
## Sub-tasks
|
|
130
140
|
|
|
131
141
|
This should be a list of strings. Each string can optionally start with `[ ]` (incomplete) or `[x]` (completed).
|
|
@@ -134,8 +144,7 @@ This should be a list of strings. Each string can optionally start with `[ ]` (i
|
|
|
134
144
|
|
|
135
145
|
This should be a list of links to other task files. The link text can optionally begin with a relation type.
|
|
136
146
|
|
|
137
|
-
The `depends-on` relation type is reserved for gantt scheduling. It means the current task should not start until the
|
|
138
|
-
linked task has finished.
|
|
147
|
+
The `depends-on` relation type is reserved for gantt scheduling. It means the current task should not start until the linked task has finished.
|
|
139
148
|
|
|
140
149
|
## Comments
|
|
141
150
|
|