@basementuniverse/kanbn 2.0.0 → 2.1.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 -1
- package/docs/advanced-configuration.md +23 -0
- package/docs/commands/add.txt +9 -0
- package/docs/commands/archive.txt +5 -0
- package/docs/commands/board.txt +5 -0
- package/docs/commands/boards.txt +34 -0
- package/docs/commands/burndown.txt +6 -0
- package/docs/commands/comment.txt +5 -0
- package/docs/commands/edit.txt +5 -0
- package/docs/commands/find.txt +11 -0
- package/docs/commands/gantt.txt +5 -0
- package/docs/commands/help.txt +1 -0
- package/docs/commands/history.txt +5 -0
- package/docs/commands/init.txt +13 -0
- package/docs/commands/move.txt +9 -0
- package/docs/commands/remove.txt +12 -1
- package/docs/commands/rename.txt +5 -0
- package/docs/commands/restore.txt +6 -0
- package/docs/commands/sort.txt +5 -0
- package/docs/commands/sprint.txt +9 -0
- package/docs/commands/status.txt +10 -1
- package/docs/commands/task.txt +5 -0
- package/docs/commands/validate.txt +15 -0
- package/docs/index-structure.md +26 -0
- package/docs/index.md +3 -1
- package/docs/multiple-boards.md +258 -0
- package/docs/quick-start.md +21 -1
- package/docs/task-structure.md +22 -1
- package/example/README.md +23 -0
- package/example/boards/.kanbn/design.md +31 -0
- package/example/boards/.kanbn/index.md +44 -0
- package/example/boards/.kanbn/tasks/add-usage-alert-emails.md +19 -0
- package/example/boards/.kanbn/tasks/build-tenant-settings-page.md +43 -0
- package/example/boards/.kanbn/tasks/create-organization-switcher.md +44 -0
- package/example/boards/.kanbn/tasks/design-onboarding-checklist.md +22 -0
- package/example/boards/.kanbn/tasks/refresh-marketing-site.md +28 -0
- package/example/boards/.kanbn/tasks/ship-billing-portal.md +29 -0
- package/package.json +9 -7
- package/routes/add.json +35 -11
- package/routes/archive.json +10 -2
- package/routes/board.json +11 -3
- package/routes/boards.json +30 -0
- package/routes/burndown.json +23 -7
- package/routes/comment.json +14 -4
- package/routes/edit.json +32 -10
- package/routes/find.json +37 -12
- package/routes/gantt.json +20 -6
- package/routes/history.json +39 -25
- package/routes/init.json +3 -1
- package/routes/move.json +22 -6
- package/routes/remove.json +15 -4
- package/routes/rename.json +11 -3
- package/routes/restore.json +8 -2
- package/routes/sort.json +35 -11
- package/routes/sprint.json +14 -4
- package/routes/status.json +23 -7
- package/routes/task.json +10 -2
- package/routes/validate.json +18 -5
- package/skills/kanbn-plan/SKILL.md +10 -1
- package/skills/kanbn-replan/SKILL.md +6 -1
- package/src/board.js +1 -1
- package/src/controller/add.js +52 -46
- package/src/controller/archive.js +8 -4
- package/src/controller/board.js +8 -9
- package/src/controller/boards.js +140 -0
- package/src/controller/burndown.js +9 -5
- package/src/controller/comment.js +9 -5
- package/src/controller/edit.js +9 -5
- package/src/controller/find.js +12 -9
- package/src/controller/gantt.js +8 -4
- package/src/controller/history.js +8 -4
- package/src/controller/init.js +39 -4
- package/src/controller/move.js +69 -15
- package/src/controller/remove.js +34 -11
- package/src/controller/rename.js +8 -4
- package/src/controller/restore.js +23 -8
- package/src/controller/sort.js +19 -3
- package/src/controller/sprint.js +31 -7
- package/src/controller/status.js +8 -4
- package/src/controller/task.js +22 -9
- package/src/controller/validate.js +60 -7
- package/src/git-user-name.js +19 -0
- package/src/main.d.ts +184 -6
- package/src/main.js +1333 -63
- package/src/parse-index.js +14 -0
- package/src/parse-task.js +16 -0
- package/src/utility.js +140 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# Multiple Boards
|
|
2
|
+
|
|
3
|
+
A Kanbn workspace can hold more than one board. Every board is a markdown file directly inside the kanbn folder, in exactly the same format as `index.md`, and they all share one `tasks/` folder — so a single task can appear on several boards, in a different column on each.
|
|
4
|
+
|
|
5
|
+
Multi-board support is opt-in. A workspace that never creates a second board behaves, and produces files, exactly as it always has.
|
|
6
|
+
|
|
7
|
+
## Views or boards?
|
|
8
|
+
|
|
9
|
+
> **A view is a lens; a board is a place.** A view re-arranges, filters and groups the tasks that are already on a board — it is read-only, and nothing you do to a view changes where a task lives. A board is somewhere tasks actually live: a task is added to it, moved between its columns, and removed from it. If you want to *look at* the same work differently, use a view. If you want to *track* the same work in a different workflow, use a board.
|
|
10
|
+
|
|
11
|
+
See [Views](views.md) for the read-only option.
|
|
12
|
+
|
|
13
|
+
## The main board
|
|
14
|
+
|
|
15
|
+
`.kanbn/index.md` is the **main board**. Its slug is `index`, and `main` and `default` always resolve to it. If you have customised `indexFile` in your config file, the main board's slug is that filename without its extension, and `main` / `default` still resolve to it.
|
|
16
|
+
|
|
17
|
+
The main board is the default target of every command, so nothing changes for existing workspaces or scripts.
|
|
18
|
+
|
|
19
|
+
## Creating a board
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
kanbn init -b design -n "Design Pipeline" -d "Design work across the product" -c Ideas -c Designing -c "Signed Off"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
That writes `.kanbn/design.md`:
|
|
26
|
+
|
|
27
|
+
```markdown
|
|
28
|
+
# Design Pipeline
|
|
29
|
+
|
|
30
|
+
Design work across the product
|
|
31
|
+
|
|
32
|
+
## Ideas
|
|
33
|
+
|
|
34
|
+
## Designing
|
|
35
|
+
|
|
36
|
+
## Signed Off
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Board slugs are generated the same way task ids are, so they must be lowercase and hyphenated. A few slugs are reserved and rejected: `index`, `main`, `default`, and the names of your task and archive folders.
|
|
40
|
+
|
|
41
|
+
Running `kanbn init -b design` again updates the board's name, description and columns, in the same way `kanbn init` does for the main board.
|
|
42
|
+
|
|
43
|
+
A new board only picks up the default `startedColumns: [In Progress]` and `completedColumns: [Done]` if it actually has columns by those names — a board with its own workflow does not silently claim that "In Progress" started work and "Done" finished it.
|
|
44
|
+
|
|
45
|
+
## Listing boards
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
kanbn boards
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
2 boards:
|
|
53
|
+
|
|
54
|
+
index (main board)
|
|
55
|
+
Main Project
|
|
56
|
+
4 columns, 12 tasks, 25% complete, last modified 2026-08-27T11:49:17.314Z
|
|
57
|
+
|
|
58
|
+
design
|
|
59
|
+
Design Pipeline
|
|
60
|
+
Design work across the product
|
|
61
|
+
3 columns, 4 tasks, 50% complete, last modified 2026-08-27T11:50:34.602Z
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`kanbn boards --tasks` shows the cross-board picture — every task that appears on more than one board, and the column it occupies on each. Add `--all` to include tasks that are only on one board.
|
|
65
|
+
|
|
66
|
+
`kanbn boards --rename design ux --name "UX Pipeline"` renames a board, and `kanbn boards --delete design` deletes one. Deleting a board never deletes task files, but tasks that no other board references become untracked; if that would happen, they are listed and `-f` is required to go ahead.
|
|
67
|
+
|
|
68
|
+
Both listings support `--json`.
|
|
69
|
+
|
|
70
|
+
## Targeting a board
|
|
71
|
+
|
|
72
|
+
Every board-scoped command takes `-b` / `--board`:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
kanbn board -b design
|
|
76
|
+
kanbn status -b design
|
|
77
|
+
kanbn task build-tenant-settings-page -b design
|
|
78
|
+
kanbn find -b design --tag Bug
|
|
79
|
+
kanbn validate -b design
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The target board is resolved in this order:
|
|
83
|
+
|
|
84
|
+
1. `--board` / `-b`
|
|
85
|
+
2. the `KANBN_BOARD` environment variable
|
|
86
|
+
3. the `defaultBoard` option in your config file
|
|
87
|
+
4. the main board
|
|
88
|
+
|
|
89
|
+
There is deliberately no stateful "current board" — everything stays visible in your shell and in git-tracked markdown.
|
|
90
|
+
|
|
91
|
+
## Tracked, untracked, and tracked elsewhere
|
|
92
|
+
|
|
93
|
+
"Tracked" is workspace-scoped: a task is tracked if **any** board references it.
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
kanbn status -b design --untracked
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
reports two separate things:
|
|
100
|
+
|
|
101
|
+
- `untrackedTasks` — task files that are on no board at all;
|
|
102
|
+
- `tasksOnOtherBoards` — tasks that other boards track but this one doesn't, naming the board and column each one sits in. This is the useful half: it is the "what could I pull onto this board" list.
|
|
103
|
+
|
|
104
|
+
Once a workspace has more than one board, `kanbn status` also reports a `board` field naming the board it applied to. A single-board workspace produces exactly the output it always has.
|
|
105
|
+
|
|
106
|
+
`kanbn task <task-id>` lists the boards a task appears on, and the column it occupies on each, whenever there is more than one.
|
|
107
|
+
|
|
108
|
+
`kanbn find --all-boards` searches every board, annotating each result with the board and column it occupies. Without the flag, `find` is scoped to the target board as it always has been.
|
|
109
|
+
|
|
110
|
+
## Working with tasks across boards
|
|
111
|
+
|
|
112
|
+
Every board-scoped command takes `-b`, so a task can be created, moved, commented on and removed on whichever board you mean:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
kanbn add -n "Task" -b design -c Ideas
|
|
116
|
+
kanbn move build-settings-page -b design -c Designing
|
|
117
|
+
kanbn remove build-settings-page -b design
|
|
118
|
+
kanbn edit build-settings-page -b design --tag Bug
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`kanbn add -b` is repeatable, so one task can land on several boards at once. Each `-b` pairs with the `-c` in the same position; boards with no `-c` of their own use the first one given, and a board that hasn't got that column falls back to its first column with a notice:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
kanbn add -n "Task" -b index -b design -b ops -c Todo -c Designing
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
With a *single* board an unknown column is still an error — the fallback only applies when several boards are named at once, where a column can legitimately exist on one and not another.
|
|
128
|
+
|
|
129
|
+
### Adding, moving and removing membership
|
|
130
|
+
|
|
131
|
+
- `kanbn move <task> -b design -c Designing` moves the task on the design board. If it isn't on that board yet, it is **added**, with a notice. `--no-add` turns that back into an error.
|
|
132
|
+
The main board never adds implicitly: moving an untracked task there is an error either way.
|
|
133
|
+
- `kanbn remove <task> -b design --index` removes the task from the design board only. Boards own membership, so the task file and every other board are untouched.
|
|
134
|
+
- Without `--index`, `remove` deletes the task file as well, and that is refused while another board still references it. `--all-boards` removes the task from every board and then deletes the file.
|
|
135
|
+
- `kanbn rename <task>` rewrites the id on **every** board that references it, because the id is the file name.
|
|
136
|
+
|
|
137
|
+
Membership changes are recorded in the task's history as `added` and `removed` events, so a board's history includes the task arriving and leaving. See [Task Structure](task-structure.md#history).
|
|
138
|
+
|
|
139
|
+
### Archiving and restoring
|
|
140
|
+
|
|
141
|
+
Archiving removes a task from every board and remembers where it was on each:
|
|
142
|
+
|
|
143
|
+
```yaml
|
|
144
|
+
column: In Progress # the main board, as it always has been
|
|
145
|
+
columns: # only written when the task was on more than one board
|
|
146
|
+
design: Designing
|
|
147
|
+
ops: Backlog
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
`kanbn restore <task>` puts it back on every board it was on, in the column it occupied on each. A board that has since been deleted, or a column that has since gone, is reported and skipped rather than failing the restore. `kanbn restore <task> -b design` restores to that board only.
|
|
151
|
+
|
|
152
|
+
## Options and configuration
|
|
153
|
+
|
|
154
|
+
Options resolve in layers when a board is loaded:
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
defaults < kanbn.yml / kanbn.json < boards.<slug> in config < board file front matter
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Array options — `startedColumns`, `completedColumns`, `hiddenColumns`, `sprints`, `views` — **override** rather than merge. Element-wise merging of an ordered array has no predictable semantics.
|
|
161
|
+
|
|
162
|
+
Some options describe the workspace rather than a single board:
|
|
163
|
+
|
|
164
|
+
| Option | Scope |
|
|
165
|
+
| --- | --- |
|
|
166
|
+
| `hiddenColumns`, `startedColumns`, `completedColumns`, `startedField`, `completedField`, `columnSorting`, `views`, `taskTemplate`, `verbose` | Board |
|
|
167
|
+
| `sprints` | Workspace, overridable per board |
|
|
168
|
+
| `customFields` | Workspace — task files are shared, so a field defined on one board must parse on all |
|
|
169
|
+
| `defaultTaskWorkload`, `taskWorkloadTags` | Workspace — workload is a property of the task, not the board |
|
|
170
|
+
| `dateFormat` | Workspace only — dates should read identically everywhere |
|
|
171
|
+
| `mainFolder`, `indexFile`, `taskFolder`, `archiveFolder`, `defaultBoard`, `boards` | Workspace only — layout, meaningless in a board file |
|
|
172
|
+
|
|
173
|
+
A workspace-scoped option in a *secondary* board's front matter is ignored, because one shared task file has to parse identically for every board that references it.
|
|
174
|
+
|
|
175
|
+
Where options are written:
|
|
176
|
+
|
|
177
|
+
- **Main board** — unchanged. If a config file exists, options go there; otherwise they go into `index.md`'s front matter.
|
|
178
|
+
- **Secondary boards** — board-scoped options are always written to that board file's front matter. A board-local operation never writes to the workspace config file.
|
|
179
|
+
|
|
180
|
+
If you have no config file, the workspace options live in the main board's front matter, so loading any secondary board also reads `index.md`. That costs one extra file read per process, not per board.
|
|
181
|
+
|
|
182
|
+
**Only workspace-scoped options are inherited from `index.md`'s front matter.** With no config file that file is doing double duty — it holds the workspace options *and* the main board's own board-scoped ones — so `startedColumns`, `completedColumns`, `hiddenColumns`, `views`, custom field column linkages and the rest stay with the main board. A secondary board that happens to share a column name with it does not silently pick up its behaviour; if you want those columns to mean the same thing on another board, declare them in that board's front matter.
|
|
183
|
+
|
|
184
|
+
A `kanbn.yml` / `kanbn.json` config file is different: it is workspace-level by construction, so a board-scoped option declared there is a deliberate statement about every board, and is inherited.
|
|
185
|
+
|
|
186
|
+
### Per-board state fields
|
|
187
|
+
|
|
188
|
+
Because `started` and `completed` live on the shared task file, a board that needs its own notion of started or completed can point at different metadata fields:
|
|
189
|
+
|
|
190
|
+
```markdown
|
|
191
|
+
---
|
|
192
|
+
startedField: designStartedAt
|
|
193
|
+
completedField: designSignedOffAt
|
|
194
|
+
startedColumns:
|
|
195
|
+
- Designing
|
|
196
|
+
completedColumns:
|
|
197
|
+
- Signed Off
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
# Design Pipeline
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Declare `designStartedAt` and `designSignedOffAt` once as workspace-scoped `customFields` of type `date`. The design board then stamps and reads its own fields, and the main board's `completed` can never leak into it. See [Index Structure](index-structure.md) for `customFields`.
|
|
204
|
+
|
|
205
|
+
### Per-board sprints
|
|
206
|
+
|
|
207
|
+
Sprints are workspace-level by default: a board reads the workspace list unless it declares its own `sprints` in its front matter, in which case that list **replaces** the workspace one entirely.
|
|
208
|
+
|
|
209
|
+
`kanbn sprint -b design` appends to the workspace list, and says so, unless the design board has its own list — in which case it appends there, auto-named `Design Pipeline Sprint 2`. A board-local list is never created implicitly: forking is permanent and invisible in the CLI, so it stays a deliberate front-matter edit.
|
|
210
|
+
|
|
211
|
+
The cost of forking is worth stating plainly: a board with its own list can no longer see workspace sprints at all, so `kanbn status -b design -s "Foundation Sprint"` will fail to find it.
|
|
212
|
+
|
|
213
|
+
`--sprint` can't be combined with `--all-boards`, because sprint numbers and names are relative to one board's list.
|
|
214
|
+
|
|
215
|
+
`kanbn burndown -b <slug>` on a board that declares no `startedColumns` errors rather than drawing an empty chart — a board with no notion of work in progress has nothing to burn down. Gantt charts don't use sprints at all, so they are unaffected.
|
|
216
|
+
|
|
217
|
+
Note that a task on two boards contributes its workload to both boards' charts. That is correct for per-board reporting; it is only double counting if you add the charts together.
|
|
218
|
+
|
|
219
|
+
### History and charts are board-scoped
|
|
220
|
+
|
|
221
|
+
`kanbn history -b design` shows the events that happened on the design board, plus the ones that aren't board-scoped at all. Burndown datapoints are placed and annotated the same way, so activity on one board never puts markers on another board's chart.
|
|
222
|
+
|
|
223
|
+
`progress` and `archived` events are never filtered: progress is a property of the task, and archiving removes a task from every board.
|
|
224
|
+
|
|
225
|
+
### Validation
|
|
226
|
+
|
|
227
|
+
`kanbn validate` reports multi-board problems as warnings once a workspace has more than one board:
|
|
228
|
+
|
|
229
|
+
- a workspace-scoped option in a secondary board's front matter, which is ignored;
|
|
230
|
+
- several boards stamping the same shared `completedField`, where whichever board is touched first silently owns that date for every board;
|
|
231
|
+
- sprints out of chronological order, which the "current sprint" logic assumes;
|
|
232
|
+
- a task on no board at all, or referenced by a board with no file behind it;
|
|
233
|
+
- a task in two columns on the same board;
|
|
234
|
+
- history events naming a board that has been deleted;
|
|
235
|
+
- markdown files beside the boards that don't parse as one, and files excluded by `boards.exclude`.
|
|
236
|
+
|
|
237
|
+
`kanbn validate --all-boards` validates every board and its tasks, rather than just the target board.
|
|
238
|
+
|
|
239
|
+
### Board discovery
|
|
240
|
+
|
|
241
|
+
Boards are discovered by globbing `*.md` directly inside the kanbn folder, so `tasks/` and `archive/` are excluded by construction. A file counts as a board if it parses as an index — that is, if it has an H1. Files that don't parse are ignored during ordinary commands and reported by `kanbn validate`.
|
|
242
|
+
|
|
243
|
+
Where discovery isn't enough, the `boards` config key takes over:
|
|
244
|
+
|
|
245
|
+
```yaml
|
|
246
|
+
boards:
|
|
247
|
+
exclude:
|
|
248
|
+
- notes.md # not a board, just a scratch file
|
|
249
|
+
order: # display order for `kanbn boards`
|
|
250
|
+
- index
|
|
251
|
+
- design
|
|
252
|
+
- ops
|
|
253
|
+
design: # options applied to the design board
|
|
254
|
+
hiddenColumns:
|
|
255
|
+
- Ideas
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
`exclude` and `order` are reserved; every other key is a board slug whose value is that board's options.
|
package/docs/quick-start.md
CHANGED
|
@@ -89,10 +89,30 @@ kanbn board -v by-assignee
|
|
|
89
89
|
|
|
90
90
|
See [views](views.md) for columns, lanes, filters and sorters.
|
|
91
91
|
|
|
92
|
+
## Multiple boards
|
|
93
|
+
|
|
94
|
+
A workspace can hold more than one board, all sharing the same pool of tasks:
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
kanbn init -b design -n "Design Pipeline" -c Ideas -c Designing -c "Signed Off"
|
|
98
|
+
kanbn boards
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Every board-scoped command takes `-b`, so a task can sit in `In Progress` on the main board and `Designing` on the design board at the same time:
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
kanbn move my-new-task -b design -c Designing
|
|
105
|
+
kanbn board -b design
|
|
106
|
+
kanbn boards --tasks
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
See [multiple boards](multiple-boards.md) for membership, per-board options and per-board sprints.
|
|
110
|
+
|
|
92
111
|
## Next steps
|
|
93
112
|
|
|
94
113
|
- [Index structure](index-structure.md) — project settings, tags and workload calculations
|
|
114
|
+
- [Multiple boards](multiple-boards.md) — several boards over one shared pool of tasks
|
|
95
115
|
- [Task structure](task-structure.md) — task metadata, sub-tasks, relations and comments
|
|
96
116
|
- [Views](views.md) and [filtering and sorting](filtering-and-sorting.md)
|
|
97
117
|
- [Advanced configuration](advanced-configuration.md) — separate config files and custom paths
|
|
98
|
-
- The [`example`](../example) directory contains
|
|
118
|
+
- The [`example`](../example) directory contains four ready-to-run workspaces you can experiment with
|
package/docs/task-structure.md
CHANGED
|
@@ -106,7 +106,7 @@ 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
|
|
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 its [`completedField`](index-structure.md#completedfield) — `completed` by default — has a date. The column a task sits in doesn't make it complete; see [Index Structure](index-structure.md#completedcolumns).
|
|
110
110
|
|
|
111
111
|
### `started`
|
|
112
112
|
|
|
@@ -157,6 +157,8 @@ An optional array of structured lifecycle events used for richer timeline report
|
|
|
157
157
|
Supported event types:
|
|
158
158
|
|
|
159
159
|
- `created`: requires `date` and `column`
|
|
160
|
+
- `added`: requires `date` and `column` — the task joined a board
|
|
161
|
+
- `removed`: requires `date` — the task left a board
|
|
160
162
|
- `moved`: requires `date`, `fromColumn`, `toColumn`
|
|
161
163
|
- `progress`: requires `date`, `fromProgress`, `toProgress`
|
|
162
164
|
- `archived`: requires `date`, `fromColumn`
|
|
@@ -167,3 +169,22 @@ Notes:
|
|
|
167
169
|
- History entries are stored in the reserved `## History` section as list items.
|
|
168
170
|
- `date` should be an ISO timestamp.
|
|
169
171
|
- Additional fields (for example `author`) are preserved if present.
|
|
172
|
+
- An event type this version of Kanbn doesn't recognise is preserved and skipped rather than rejected, so a task file written by a newer version stays readable.
|
|
173
|
+
|
|
174
|
+
### Board attribution
|
|
175
|
+
|
|
176
|
+
In a workspace with [multiple boards](multiple-boards.md), an event carries an optional `board` key naming the board it happened on:
|
|
177
|
+
|
|
178
|
+
```markdown
|
|
179
|
+
## History
|
|
180
|
+
|
|
181
|
+
- type: moved
|
|
182
|
+
date: 2026-07-14T09:12:00.000Z
|
|
183
|
+
fromColumn: Ideas
|
|
184
|
+
toColumn: Designing
|
|
185
|
+
board: design
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Events on the **main board carry no `board` key**, so a single-board workspace writes exactly the history it always has, and every existing task file stays valid.
|
|
189
|
+
|
|
190
|
+
`archived` and `progress` events are never board-scoped: archiving removes a task from every board, and progress is a property of the task rather than of a board.
|
package/example/README.md
CHANGED
|
@@ -48,6 +48,29 @@ kanbn board -v everything
|
|
|
48
48
|
kanbn board -v triage --json
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
+
## [`boards`](boards)
|
|
52
|
+
|
|
53
|
+
Several boards over one shared pool of tasks. See [Multiple Boards](../docs/multiple-boards.md).
|
|
54
|
+
|
|
55
|
+
- an engineering board in [`index.md`](boards/.kanbn/index.md) and a design board in
|
|
56
|
+
[`design.md`](boards/.kanbn/design.md), sharing one `tasks/` folder
|
|
57
|
+
- three tasks that sit in **different columns on each board** - including one that design has started
|
|
58
|
+
and engineering hasn't
|
|
59
|
+
- `startedField` / `completedField` on the design board, so design progress is tracked in its own
|
|
60
|
+
metadata fields rather than in the shared `started` / `completed` dates
|
|
61
|
+
- board-scoped options in each board's front matter, and workspace-scoped `customFields` in the main
|
|
62
|
+
board's - where they are inherited by both
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
kanbn boards
|
|
66
|
+
kanbn boards --tasks
|
|
67
|
+
kanbn board -b design
|
|
68
|
+
kanbn status -b design --untracked
|
|
69
|
+
kanbn task build-tenant-settings-page
|
|
70
|
+
kanbn find --all-boards
|
|
71
|
+
kanbn validate --all-boards
|
|
72
|
+
```
|
|
73
|
+
|
|
51
74
|
## [`advanced`](advanced)
|
|
52
75
|
|
|
53
76
|
Project configuration beyond the defaults. See
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
# Board-scoped: this board has its own workflow, and its own idea of started and completed
|
|
3
|
+
startedColumns:
|
|
4
|
+
- Designing
|
|
5
|
+
completedColumns:
|
|
6
|
+
- 'Signed Off'
|
|
7
|
+
|
|
8
|
+
# ...and its own state fields, so design progress is tracked separately from engineering progress on
|
|
9
|
+
# the same shared task files. Without these, moving a task to "Signed Off" here would set the
|
|
10
|
+
# shared `completed` date and mark it done on the engineering board too
|
|
11
|
+
startedField: designStartedAt
|
|
12
|
+
completedField: designSignedOffAt
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Design Pipeline
|
|
16
|
+
|
|
17
|
+
Design work across the product, tracked separately from engineering delivery. Tasks here are the
|
|
18
|
+
same task files the engineering board uses - a task can sit in a different column on each.
|
|
19
|
+
|
|
20
|
+
## Ideas
|
|
21
|
+
|
|
22
|
+
- [design-onboarding-checklist](tasks/design-onboarding-checklist.md)
|
|
23
|
+
|
|
24
|
+
## Designing
|
|
25
|
+
|
|
26
|
+
- [build-tenant-settings-page](tasks/build-tenant-settings-page.md)
|
|
27
|
+
- [refresh-marketing-site](tasks/refresh-marketing-site.md)
|
|
28
|
+
|
|
29
|
+
## Signed Off
|
|
30
|
+
|
|
31
|
+
- [create-organization-switcher](tasks/create-organization-switcher.md)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
# Board-scoped: these belong to the main board alone, and are NOT inherited by design.md
|
|
3
|
+
startedColumns:
|
|
4
|
+
- 'In Progress'
|
|
5
|
+
completedColumns:
|
|
6
|
+
- Done
|
|
7
|
+
|
|
8
|
+
# Workspace-scoped: with no config file these live here, and every board inherits them. A custom
|
|
9
|
+
# field has to be declared once for the whole workspace, because one task file has to parse
|
|
10
|
+
# identically for every board that references it
|
|
11
|
+
customFields:
|
|
12
|
+
- name: designStartedAt
|
|
13
|
+
type: date
|
|
14
|
+
- name: designSignedOffAt
|
|
15
|
+
type: date
|
|
16
|
+
taskWorkloadTags:
|
|
17
|
+
Tiny: 1
|
|
18
|
+
Small: 2
|
|
19
|
+
Medium: 3
|
|
20
|
+
Large: 5
|
|
21
|
+
Huge: 8
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
# Example SaaS Project
|
|
25
|
+
|
|
26
|
+
The engineering board. Design work on the same tasks is tracked separately on the `design` board -
|
|
27
|
+
run `kanbn boards` to see both, and `kanbn boards --tasks` to see which tasks span them.
|
|
28
|
+
|
|
29
|
+
## Backlog
|
|
30
|
+
|
|
31
|
+
- [refresh-marketing-site](tasks/refresh-marketing-site.md)
|
|
32
|
+
- [add-usage-alert-emails](tasks/add-usage-alert-emails.md)
|
|
33
|
+
|
|
34
|
+
## Todo
|
|
35
|
+
|
|
36
|
+
- [create-organization-switcher](tasks/create-organization-switcher.md)
|
|
37
|
+
|
|
38
|
+
## In Progress
|
|
39
|
+
|
|
40
|
+
- [build-tenant-settings-page](tasks/build-tenant-settings-page.md)
|
|
41
|
+
|
|
42
|
+
## Done
|
|
43
|
+
|
|
44
|
+
- [ship-billing-portal](tasks/ship-billing-portal.md)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
created: 2026-07-09T15:00:00.000Z
|
|
3
|
+
tags:
|
|
4
|
+
- Medium
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Add Usage Alert Emails
|
|
8
|
+
|
|
9
|
+
Warn an organisation by email when it crosses 80% and 100% of its plan's usage allowance.
|
|
10
|
+
|
|
11
|
+
Engineering-only work, so it never reaches the design board.
|
|
12
|
+
|
|
13
|
+
## History
|
|
14
|
+
|
|
15
|
+
- type: created
|
|
16
|
+
date: 2026-07-09T15:00:00.000Z
|
|
17
|
+
column: Backlog
|
|
18
|
+
fromProgress: 0
|
|
19
|
+
toProgress: 0
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
created: 2026-07-02T09:15:00.000Z
|
|
3
|
+
updated: 2026-07-14T11:30:00.000Z
|
|
4
|
+
started: 2026-07-10T09:00:00.000Z
|
|
5
|
+
designStartedAt: 2026-07-06T10:00:00.000Z
|
|
6
|
+
assigned: priya
|
|
7
|
+
tags:
|
|
8
|
+
- Medium
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Build Tenant Settings Page
|
|
12
|
+
|
|
13
|
+
A single place for an organisation's owner to manage name, logo, timezone and default roles.
|
|
14
|
+
|
|
15
|
+
This task is on both boards: `In Progress` on the engineering board and `Designing` on the design
|
|
16
|
+
board. Its `started` date is the engineering start; `designStartedAt` is when design picked it up.
|
|
17
|
+
|
|
18
|
+
## Sub-tasks
|
|
19
|
+
|
|
20
|
+
- [x] Settings form layout
|
|
21
|
+
- [ ] Logo upload and cropping
|
|
22
|
+
- [ ] Role defaults
|
|
23
|
+
|
|
24
|
+
## History
|
|
25
|
+
|
|
26
|
+
- type: created
|
|
27
|
+
date: 2026-07-02T09:15:00.000Z
|
|
28
|
+
column: Backlog
|
|
29
|
+
fromProgress: 0
|
|
30
|
+
toProgress: 0
|
|
31
|
+
- type: added
|
|
32
|
+
date: 2026-07-06T10:00:00.000Z
|
|
33
|
+
column: Ideas
|
|
34
|
+
board: design
|
|
35
|
+
- type: moved
|
|
36
|
+
date: 2026-07-06T10:00:00.000Z
|
|
37
|
+
fromColumn: Ideas
|
|
38
|
+
toColumn: Designing
|
|
39
|
+
board: design
|
|
40
|
+
- type: moved
|
|
41
|
+
date: 2026-07-10T09:00:00.000Z
|
|
42
|
+
fromColumn: Backlog
|
|
43
|
+
toColumn: 'In Progress'
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
created: 2026-07-03T14:00:00.000Z
|
|
3
|
+
updated: 2026-07-12T16:45:00.000Z
|
|
4
|
+
designStartedAt: 2026-07-05T09:30:00.000Z
|
|
5
|
+
designSignedOffAt: 2026-07-12T16:45:00.000Z
|
|
6
|
+
assigned: sam
|
|
7
|
+
tags:
|
|
8
|
+
- Small
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Create Organization Switcher
|
|
12
|
+
|
|
13
|
+
A dropdown for moving between the organisations a user belongs to, without signing out.
|
|
14
|
+
|
|
15
|
+
Design has finished with this one - it sits in `Signed Off` on the design board - but engineering
|
|
16
|
+
hasn't started it, so it's still in `Todo` on the main board. Because the design board reads
|
|
17
|
+
`designSignedOffAt` rather than the shared `completed` field, finishing it here doesn't mark it done
|
|
18
|
+
for engineering.
|
|
19
|
+
|
|
20
|
+
## Sub-tasks
|
|
21
|
+
|
|
22
|
+
- [ ] Switcher component
|
|
23
|
+
- [ ] Persist last-used organisation
|
|
24
|
+
|
|
25
|
+
## History
|
|
26
|
+
|
|
27
|
+
- type: created
|
|
28
|
+
date: 2026-07-03T14:00:00.000Z
|
|
29
|
+
column: Backlog
|
|
30
|
+
fromProgress: 0
|
|
31
|
+
toProgress: 0
|
|
32
|
+
- type: added
|
|
33
|
+
date: 2026-07-05T09:30:00.000Z
|
|
34
|
+
column: Designing
|
|
35
|
+
board: design
|
|
36
|
+
- type: moved
|
|
37
|
+
date: 2026-07-08T10:00:00.000Z
|
|
38
|
+
fromColumn: Backlog
|
|
39
|
+
toColumn: Todo
|
|
40
|
+
- type: moved
|
|
41
|
+
date: 2026-07-12T16:45:00.000Z
|
|
42
|
+
fromColumn: Designing
|
|
43
|
+
toColumn: 'Signed Off'
|
|
44
|
+
board: design
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
created: 2026-07-11T13:20:00.000Z
|
|
3
|
+
assigned: priya
|
|
4
|
+
tags:
|
|
5
|
+
- Small
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Design Onboarding Checklist
|
|
9
|
+
|
|
10
|
+
An in-product checklist walking a new organisation through its first week.
|
|
11
|
+
|
|
12
|
+
This one is only on the design board - engineering hasn't picked it up, so it isn't on the main
|
|
13
|
+
board at all. `kanbn status --untracked` would not list it: it is tracked, just not here.
|
|
14
|
+
|
|
15
|
+
## History
|
|
16
|
+
|
|
17
|
+
- type: created
|
|
18
|
+
date: 2026-07-11T13:20:00.000Z
|
|
19
|
+
column: Ideas
|
|
20
|
+
board: design
|
|
21
|
+
fromProgress: 0
|
|
22
|
+
toProgress: 0
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
created: 2026-07-05T08:00:00.000Z
|
|
3
|
+
updated: 2026-07-13T09:00:00.000Z
|
|
4
|
+
designStartedAt: 2026-07-13T09:00:00.000Z
|
|
5
|
+
assigned: priya
|
|
6
|
+
tags:
|
|
7
|
+
- Large
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Refresh Marketing Site
|
|
11
|
+
|
|
12
|
+
New landing page, pricing page and case studies, ahead of the autumn launch.
|
|
13
|
+
|
|
14
|
+
Design has started, engineering hasn't - `Designing` on the design board, `Backlog` on the main one.
|
|
15
|
+
This is the shape that makes per-board state fields worth having: the task genuinely is in flight on
|
|
16
|
+
one board and untouched on the other.
|
|
17
|
+
|
|
18
|
+
## History
|
|
19
|
+
|
|
20
|
+
- type: created
|
|
21
|
+
date: 2026-07-05T08:00:00.000Z
|
|
22
|
+
column: Backlog
|
|
23
|
+
fromProgress: 0
|
|
24
|
+
toProgress: 0
|
|
25
|
+
- type: added
|
|
26
|
+
date: 2026-07-13T09:00:00.000Z
|
|
27
|
+
column: Designing
|
|
28
|
+
board: design
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
created: 2026-06-24T10:00:00.000Z
|
|
3
|
+
updated: 2026-07-07T17:10:00.000Z
|
|
4
|
+
started: 2026-06-26T09:00:00.000Z
|
|
5
|
+
completed: 2026-07-07T17:10:00.000Z
|
|
6
|
+
assigned: sam
|
|
7
|
+
tags:
|
|
8
|
+
- Large
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Ship Billing Portal
|
|
12
|
+
|
|
13
|
+
Self-serve plan changes, payment method updates and invoice history.
|
|
14
|
+
|
|
15
|
+
## History
|
|
16
|
+
|
|
17
|
+
- type: created
|
|
18
|
+
date: 2026-06-24T10:00:00.000Z
|
|
19
|
+
column: Backlog
|
|
20
|
+
fromProgress: 0
|
|
21
|
+
toProgress: 0
|
|
22
|
+
- type: moved
|
|
23
|
+
date: 2026-06-26T09:00:00.000Z
|
|
24
|
+
fromColumn: Backlog
|
|
25
|
+
toColumn: 'In Progress'
|
|
26
|
+
- type: moved
|
|
27
|
+
date: 2026-07-07T17:10:00.000Z
|
|
28
|
+
fromColumn: 'In Progress'
|
|
29
|
+
toColumn: Done
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@basementuniverse/kanbn",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "A CLI Kanban application",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"url": "git+https://github.com/basementuniverse/kanbn.git"
|
|
19
19
|
},
|
|
20
20
|
"engines": {
|
|
21
|
-
"node": ">=
|
|
21
|
+
"node": ">=16.13.0"
|
|
22
22
|
},
|
|
23
23
|
"keywords": [
|
|
24
24
|
"kanbn",
|
|
@@ -38,7 +38,6 @@
|
|
|
38
38
|
"dotenv": "^8.2.0",
|
|
39
39
|
"front-matter": "^4.0.2",
|
|
40
40
|
"fuzzy": "^0.1.3",
|
|
41
|
-
"git-user-name": "^2.0.0",
|
|
42
41
|
"glob-promise": "^3.4.0",
|
|
43
42
|
"humanize-duration": "^3.25.0",
|
|
44
43
|
"inquirer": "^7.3.3",
|
|
@@ -47,11 +46,11 @@
|
|
|
47
46
|
"inquirer-recursive": "github:basementuniverse/inquirer-recursive",
|
|
48
47
|
"inquirer-select-line": "github:basementuniverse/inquirer-select-line",
|
|
49
48
|
"jsonschema": "^1.4.0",
|
|
50
|
-
"marked": "^
|
|
51
|
-
"marked-terminal": "^
|
|
52
|
-
"minimist": "^1.2.
|
|
49
|
+
"marked": "^4.3.0",
|
|
50
|
+
"marked-terminal": "^5.2.0",
|
|
51
|
+
"minimist": "^1.2.8",
|
|
53
52
|
"rimraf": "^3.0.2",
|
|
54
|
-
"terminal-kit": "^1.
|
|
53
|
+
"terminal-kit": "^3.1.4",
|
|
55
54
|
"yamljs": "^0.3.0"
|
|
56
55
|
},
|
|
57
56
|
"devDependencies": {
|
|
@@ -66,5 +65,8 @@
|
|
|
66
65
|
"qunit": "^2.13.0",
|
|
67
66
|
"strip-ansi": "^6.0.0",
|
|
68
67
|
"typescript": "^4.9.3"
|
|
68
|
+
},
|
|
69
|
+
"overrides": {
|
|
70
|
+
"tmp": "^0.2.7"
|
|
69
71
|
}
|
|
70
72
|
}
|