DWSD.md

Board DSL — Columns

Columns are the stages a work item flows through. This page covers a column’s fields and modifiers (wip, aging, max-returns, status-category tint, tags chips) and the 5-color status-tint palette. See the reference index for the board header and the other constructs.

Column fields (each entry of columns)

A column entry is either a bare string (a name-only column — - ToDo) or an object with a name plus modifiers.

FieldValues / shapeDefaultDiagnostic on misuse
namestring (required in the object form)—board.invalid-column (entry skipped when missing/empty)
wipa number → max only; OR [min, max] → a range(none)board.invalid-wip (warning; omitted)
agingstring (e.g. 3d)(none)(none — non-string ignored)
max-returns (alias max_returns)number (→ AST returns)(none)(none — non-number ignored)
checkstring (DoD check text)(none)(none — non-string ignored)
status-categorysingle value, closed set to-do | in-progress | done | waiting | assess (drives the header tint — see below)(none)board.invalid-status-category (warning; value dropped, no tint)
tagsstring list (descriptive category chips, rendered visibly with … overflow — see below)(none)tolerant
agreementsstring OR string list — column working agreements (wikilink entry = linked entity; plain string = inline agreement)(none)tolerant
interactionsstring OR string list — column meeting / interaction pointers(none)tolerant
groupstring OR string list (outer→inner) — a group back-reference(none)(none — non-string dropped)
splita split block (see Splits)(none)board.invalid-split

Column wip: is max-only for a single number (wip: 3 → { wipMax: 3 }), and a range for a pair (wip: [2, 4] → { wipMin: 2, wipMax: 4 }). (Lanes differ — see Lanes.)

status-category: is a single value (not an array) from the closed set to-do | in-progress | done | waiting | assess (kebab spelling, consistent with max-returns:). It drives the column header tint from a fixed 5-color palette — the concept Jira calls a status category, but not Jira-branded and with no Jira dependency. A value outside the closed set is dropped with board.invalid-status-category and the column gets no tint. The same key is available at lane, group, and split-section scope (it is not a board-level key — a board-level status-category: is silently ignored).

assess (yellow tint) is the umbrella category for work that is not directly value-adding but necessary — quality / prioritization gating. Downstream: Review, Test, QA, Verify. Upstream: Select, Prioritize, Triage. It was added in Plan 21-10 (2026-06-21 EDH-walk follow-up), generalizing a leftover render-layer review fallback into a first-class authorable category. At the render layer the name-match heuristic maps the bare column / #tag names review / test / qa / verify / prioritize / select / triage → the assess tint (so a bare column named Review still tints yellow under the coherent assess slug). blocked is not a separate category — it folds into waiting (red).

tags: is a list of descriptive category chips, rendered visibly — each chip is shown in the column header, with a … ellipsis when the chips overflow the available width. It is the cross-DSL tags: convention (same shape the topology DSL uses). tags: carries no tint; the tint is the separate status-category: concern. Use status-category: to color the header and tags: to attach descriptive labels — the two are independent.

The reserved FL/ToC lane conventions external / drum / buffer / hypercare are descriptive tags: (a visible chip, no tint). The tint palette is the five status-category: values (to-do / in-progress / done / waiting / assess).

Status tint

A column’s header tint is driven by its status-category: value. When a column has no explicit status-category: but its name case-insensitively matches a known category (To Do / Doing / Done / Waiting, or one of the assess name-match aliases Review / Test / QA / Verify / Prioritize / Select / Triage, or Blocked → the waiting red), the renderer derives the tint from the name — as if status-category: <name> had been written. This is a render-layer heuristic: a bare - ToDo column carries no AST tint field (no tags); the tint is computed downstream by the renderer (deriveStatusSlug), not stored on the parsed column. An explicit status-category: always wins.

The 5-color status palette (the jira-default theme). Each status-category: slug maps to a fixed background + text color:

slugbackgroundtextmeaning
to-do#dfe1e6 grey#42526enot started
in-progress#deebff blue#0747a6active
assess#fff0b3 yellow#7f5f01non-value-add gating (Review / Test / QA / Select / Triage)
waiting#ffbdad red#bf2600stuck / blocked
done#abf5d1 green#006644complete

The palette above is a property of the jira-default theme (see Themes), not of the DSL — a theme added later is free to paint the same five status categories differently, or not at all.

Example

A focused board exercising the column modifiers — a bare status-named column (tint derived at render time), an explicit wip: range + aging: + status-category: + descriptive tags:, and a max-returns: count on an assess column:

title: Delivery
columns:
  - ToDo
  - name: Build
    wip: [2, 4]
    aging: 3d
    status-category: in-progress
    tags: [frontend, api]
  - name: Review
    max-returns: 2
    status-category: assess
  - Done

Like what you see? → Start — build your own org folder in ~2 min

columns.md
# Board DSL — Columns
Columns are the stages a work item flows through. This page covers a column's
fields and modifiers (`wip`, `aging`, `max-returns`, `status-category` tint,
`tags` chips) and the 5-color status-tint palette. See the
[reference index](./index.md) for the board header and the other constructs.
## Column fields (each entry of `columns`)
A column entry is either a **bare string** (a name-only column — `- ToDo`) or an
**object** with a `name` plus modifiers.
| Field | Values / shape | Default | Diagnostic on misuse |
|-------|----------------|---------|----------------------|
| `name` | string (**required** in the object form) | — | `board.invalid-column` (entry skipped when missing/empty) |
| `wip` | a number → max only; OR `[min, max]` → a range | (none) | `board.invalid-wip` (warning; omitted) |
| `aging` | string (e.g. `3d`) | (none) | (none — non-string ignored) |
| `max-returns` (alias `max_returns`) | number (→ AST `returns`) | (none) | (none — non-number ignored) |
| `check` | string (DoD check text) | (none) | (none — non-string ignored) |
| `status-category` | **single value**, closed set `to-do` \| `in-progress` \| `done` \| `waiting` \| `assess` (drives the header tint — see below) | (none) | `board.invalid-status-category` (warning; value dropped, no tint) |
| `tags` | string list (descriptive category chips, rendered visibly with `…` overflow — see below) | (none) | tolerant |
| `agreements` | string OR string list — column working agreements (wikilink entry = linked entity; plain string = inline agreement) | (none) | tolerant |
| `interactions` | string OR string list — column meeting / interaction pointers | (none) | tolerant |
| `group` | string OR string list (outer→inner) — a group back-reference | (none) | (none — non-string dropped) |
| `split` | a split block (see [Splits](./splits.md)) | (none) | `board.invalid-split` |
**Column `wip:` is max-only for a single number** (`wip: 3` → `{ wipMax: 3 }`),
and a range for a pair (`wip: [2, 4]` → `{ wipMin: 2, wipMax: 4 }`). (Lanes
differ — see [Lanes](./lanes.md).)
**`status-category:`** is a **single value** (not an array) from the closed set
`to-do | in-progress | done | waiting | assess` (kebab spelling, consistent with
`max-returns:`). It drives the **column header tint** from a fixed 5-color
palette — the concept Jira calls a status _category_, but **not Jira-branded and
with no Jira dependency**. A value outside the closed set is dropped with
`board.invalid-status-category` and the column gets no tint. The same key is
available at lane, group, and split-section scope (it is **not** a board-level
key — a board-level `status-category:` is silently ignored).
**`assess`** (yellow tint) is the umbrella category for work that is **not
directly value-adding but necessary** — quality / prioritization gating.
Downstream: **Review, Test, QA, Verify**. Upstream: **Select, Prioritize,
Triage**. It was added in Plan 21-10 (2026-06-21 EDH-walk follow-up),
generalizing a leftover render-layer `review` fallback into a first-class
authorable category. At the **render layer** the name-match heuristic maps the
bare column / `#tag` names `review` / `test` / `qa` / `verify` / `prioritize` /
`select` / `triage` → the `assess` tint (so a bare column named `Review` still
tints yellow under the coherent `assess` slug). `blocked` is **not** a separate
category — it folds into `waiting` (red).
**`tags:`** is a **list of descriptive category chips**, rendered **visibly** —
each chip is shown in the column header, with a `…` ellipsis when the chips
overflow the available width. It is the cross-DSL `tags:` convention (same shape
the topology DSL uses). `tags:` carries **no** tint; the tint is the separate
`status-category:` concern. Use `status-category:` to color the header and
`tags:` to attach descriptive labels — the two are independent.
The reserved FL/ToC lane conventions `external` / `drum` / `buffer` /
`hypercare` are **descriptive `tags:`** (a visible chip, no tint). The tint
palette is the five `status-category:` values (`to-do` / `in-progress` / `done` /
`waiting` / `assess`).
![Column with modifiers](../../images/column.png)
![WIP limit — number vs range](../../images/wip-limit.png)
![Descriptive tags chips](../../images/tags.png)
## Status tint
A column's header tint is driven by its **`status-category:`** value. When a
column has **no explicit `status-category:`** but its `name` case-insensitively
matches a known category (`To Do` / `Doing` / `Done` / `Waiting`, or one of the
`assess` name-match aliases `Review` / `Test` / `QA` / `Verify` / `Prioritize` /
`Select` / `Triage`, or `Blocked` → the `waiting` red), the renderer derives the
tint from the name — _as if_ `status-category: <name>` had been written. This is a **render-layer heuristic**: a bare `- ToDo` column carries
**no AST tint field** (no `tags`); the tint is computed downstream by the
renderer (`deriveStatusSlug`), not stored on the parsed column. An explicit
`status-category:` always wins.
**The 5-color status palette** (the `jira-default` theme). Each
`status-category:` slug maps to a fixed background + text color:
| slug | background | text | meaning |
|------|------------|------|---------|
| `to-do` | `#dfe1e6` grey | `#42526e` | not started |
| `in-progress` | `#deebff` blue | `#0747a6` | active |
| `assess` | `#fff0b3` yellow | `#7f5f01` | non-value-add gating (Review / Test / QA / Select / Triage) |
| `waiting` | `#ffbdad` red | `#bf2600` | stuck / blocked |
| `done` | `#abf5d1` green | `#006644` | complete |
> The palette above is a property of the `jira-default` theme (see
> [Themes](./index.md#themes)), not of the DSL — a theme added later is free to
> paint the same five status categories differently, or not at all.
## Example
A focused board exercising the column modifiers — a bare status-named column (tint
derived at render time), an explicit `wip:` range + `aging:` + `status-category:` +
descriptive `tags:`, and a `max-returns:` count on an `assess` column:
```dwsd-board
title: Delivery
columns:
- ToDo
- name: Build
wip: [2, 4]
aging: 3d
status-category: in-progress
tags: [frontend, api]
- name: Review
max-returns: 2
status-category: assess
- Done
```