@nowline/cli 0.2.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.
Files changed (139) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +372 -0
  3. package/dist/cli/args.d.ts +54 -0
  4. package/dist/cli/args.d.ts.map +1 -0
  5. package/dist/cli/args.js +165 -0
  6. package/dist/cli/args.js.map +1 -0
  7. package/dist/cli/formats.d.ts +61 -0
  8. package/dist/cli/formats.d.ts.map +1 -0
  9. package/dist/cli/formats.js +153 -0
  10. package/dist/cli/formats.js.map +1 -0
  11. package/dist/cli/help.d.ts +3 -0
  12. package/dist/cli/help.d.ts.map +1 -0
  13. package/dist/cli/help.js +90 -0
  14. package/dist/cli/help.js.map +1 -0
  15. package/dist/cli/output-path.d.ts +57 -0
  16. package/dist/cli/output-path.d.ts.map +1 -0
  17. package/dist/cli/output-path.js +70 -0
  18. package/dist/cli/output-path.js.map +1 -0
  19. package/dist/commands/init.d.ts +20 -0
  20. package/dist/commands/init.d.ts.map +1 -0
  21. package/dist/commands/init.js +80 -0
  22. package/dist/commands/init.js.map +1 -0
  23. package/dist/commands/render.d.ts +15 -0
  24. package/dist/commands/render.d.ts.map +1 -0
  25. package/dist/commands/render.js +435 -0
  26. package/dist/commands/render.js.map +1 -0
  27. package/dist/commands/serve.d.ts +16 -0
  28. package/dist/commands/serve.d.ts.map +1 -0
  29. package/dist/commands/serve.js +287 -0
  30. package/dist/commands/serve.js.map +1 -0
  31. package/dist/convert/parse-json.d.ts +7 -0
  32. package/dist/convert/parse-json.d.ts.map +1 -0
  33. package/dist/convert/parse-json.js +34 -0
  34. package/dist/convert/parse-json.js.map +1 -0
  35. package/dist/convert/printer.d.ts +6 -0
  36. package/dist/convert/printer.d.ts.map +1 -0
  37. package/dist/convert/printer.js +334 -0
  38. package/dist/convert/printer.js.map +1 -0
  39. package/dist/convert/schema.d.ts +33 -0
  40. package/dist/convert/schema.d.ts.map +1 -0
  41. package/dist/convert/schema.js +77 -0
  42. package/dist/convert/schema.js.map +1 -0
  43. package/dist/core/parse.d.ts +24 -0
  44. package/dist/core/parse.d.ts.map +1 -0
  45. package/dist/core/parse.js +58 -0
  46. package/dist/core/parse.js.map +1 -0
  47. package/dist/diagnostics/adapt.d.ts +46 -0
  48. package/dist/diagnostics/adapt.d.ts.map +1 -0
  49. package/dist/diagnostics/adapt.js +109 -0
  50. package/dist/diagnostics/adapt.js.map +1 -0
  51. package/dist/diagnostics/format.d.ts +18 -0
  52. package/dist/diagnostics/format.d.ts.map +1 -0
  53. package/dist/diagnostics/format.js +41 -0
  54. package/dist/diagnostics/format.js.map +1 -0
  55. package/dist/diagnostics/index.d.ts +5 -0
  56. package/dist/diagnostics/index.d.ts.map +1 -0
  57. package/dist/diagnostics/index.js +5 -0
  58. package/dist/diagnostics/index.js.map +1 -0
  59. package/dist/diagnostics/json.d.ts +8 -0
  60. package/dist/diagnostics/json.d.ts.map +1 -0
  61. package/dist/diagnostics/json.js +24 -0
  62. package/dist/diagnostics/json.js.map +1 -0
  63. package/dist/diagnostics/model.d.ts +44 -0
  64. package/dist/diagnostics/model.d.ts.map +1 -0
  65. package/dist/diagnostics/model.js +2 -0
  66. package/dist/diagnostics/model.js.map +1 -0
  67. package/dist/diagnostics/text.d.ts +6 -0
  68. package/dist/diagnostics/text.d.ts.map +1 -0
  69. package/dist/diagnostics/text.js +43 -0
  70. package/dist/diagnostics/text.js.map +1 -0
  71. package/dist/generated/templates.d.ts +4 -0
  72. package/dist/generated/templates.d.ts.map +1 -0
  73. package/dist/generated/templates.js +9 -0
  74. package/dist/generated/templates.js.map +1 -0
  75. package/dist/generated/version.d.ts +11 -0
  76. package/dist/generated/version.d.ts.map +1 -0
  77. package/dist/generated/version.js +8 -0
  78. package/dist/generated/version.js.map +1 -0
  79. package/dist/i18n/locale.d.ts +56 -0
  80. package/dist/i18n/locale.d.ts.map +1 -0
  81. package/dist/i18n/locale.js +107 -0
  82. package/dist/i18n/locale.js.map +1 -0
  83. package/dist/index.d.ts +3 -0
  84. package/dist/index.d.ts.map +1 -0
  85. package/dist/index.js +60 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/io/config.d.ts +2 -0
  88. package/dist/io/config.d.ts.map +1 -0
  89. package/dist/io/config.js +5 -0
  90. package/dist/io/config.js.map +1 -0
  91. package/dist/io/exit-codes.d.ts +12 -0
  92. package/dist/io/exit-codes.d.ts.map +1 -0
  93. package/dist/io/exit-codes.js +15 -0
  94. package/dist/io/exit-codes.js.map +1 -0
  95. package/dist/io/read.d.ts +13 -0
  96. package/dist/io/read.d.ts.map +1 -0
  97. package/dist/io/read.js +53 -0
  98. package/dist/io/read.js.map +1 -0
  99. package/dist/io/write.d.ts +32 -0
  100. package/dist/io/write.d.ts.map +1 -0
  101. package/dist/io/write.js +61 -0
  102. package/dist/io/write.js.map +1 -0
  103. package/dist/version.d.ts +13 -0
  104. package/dist/version.d.ts.map +1 -0
  105. package/dist/version.js +20 -0
  106. package/dist/version.js.map +1 -0
  107. package/man/fr/nowline.1 +424 -0
  108. package/man/fr/nowline.5 +1864 -0
  109. package/man/nowline.1 +517 -0
  110. package/man/nowline.5 +1784 -0
  111. package/package.json +66 -0
  112. package/scripts/bundle-templates.mjs +105 -0
  113. package/scripts/compile.mjs +131 -0
  114. package/src/cli/args.ts +252 -0
  115. package/src/cli/formats.ts +207 -0
  116. package/src/cli/help.ts +92 -0
  117. package/src/cli/output-path.ts +98 -0
  118. package/src/commands/init.ts +99 -0
  119. package/src/commands/render.ts +566 -0
  120. package/src/commands/serve.ts +322 -0
  121. package/src/convert/parse-json.ts +57 -0
  122. package/src/convert/printer.ts +376 -0
  123. package/src/convert/schema.ts +105 -0
  124. package/src/core/parse.ts +93 -0
  125. package/src/diagnostics/adapt.ts +148 -0
  126. package/src/diagnostics/format.ts +70 -0
  127. package/src/diagnostics/index.ts +4 -0
  128. package/src/diagnostics/json.ts +30 -0
  129. package/src/diagnostics/model.ts +48 -0
  130. package/src/diagnostics/text.ts +62 -0
  131. package/src/generated/templates.ts +12 -0
  132. package/src/generated/version.ts +18 -0
  133. package/src/i18n/locale.ts +133 -0
  134. package/src/index.ts +60 -0
  135. package/src/io/config.ts +11 -0
  136. package/src/io/exit-codes.ts +18 -0
  137. package/src/io/read.ts +70 -0
  138. package/src/io/write.ts +94 -0
  139. package/src/version.ts +21 -0
package/man/nowline.5 ADDED
@@ -0,0 +1,1784 @@
1
+ .Dd $Mdocdate$
2
+ .Dt NOWLINE 5
3
+ .Os
4
+ .Sh NAME
5
+ .Nm nowline
6
+ .Nd Nowline DSL roadmap file format
7
+ .Sh DESCRIPTION
8
+ A
9
+ .Pa .nowline
10
+ file is an indentation-significant outline that defines a roadmap.
11
+ The file itself is the product; every other artefact (SVG, PNG, PDF,
12
+ HTML, Markdown+Mermaid, XLSX, MS Project XML) is a view of it produced
13
+ by
14
+ .Xr nowline 1 .
15
+ .Pp
16
+ This page documents the file format.
17
+ For the rendering pipeline and visual contracts, see
18
+ .Pa specs/rendering.md
19
+ in the source repository.
20
+ For the CLI surface, see
21
+ .Xr nowline 1 .
22
+ .Pp
23
+ The canonical, prose source for everything below is
24
+ .Pa specs/dsl.md
25
+ in the source repository; this page is a hand-authored reference
26
+ distilled from it.
27
+ .Sh FILE STRUCTURE
28
+ A
29
+ .Pa .nowline
30
+ file has up to four sections in strict order:
31
+ .Bl -enum -offset indent
32
+ .It
33
+ .Sy nowline
34
+ directive (optional, recommended). Must be the first non-comment,
35
+ non-blank line if present.
36
+ .It
37
+ .Sy include
38
+ declarations (optional). Pull in other
39
+ .Pa .nowline
40
+ files.
41
+ .It
42
+ .Sy config
43
+ section (optional). Rendering configuration: styles, defaults,
44
+ scale, calendar, symbols.
45
+ .It
46
+ .Sy roadmap
47
+ section (required). Content: persons, teams, anchors, labels, sizes,
48
+ statuses, swimlanes, items, milestones, footnotes.
49
+ .El
50
+ .Pp
51
+ .Sy config
52
+ and
53
+ .Sy roadmap
54
+ are section markers, not indent-containers.
55
+ Keywords inside each section appear at the top level (not indented
56
+ under the marker).
57
+ Indentation is used where nesting is real: style properties under a
58
+ .Sy style
59
+ block, items under a
60
+ .Sy swimlane ,
61
+ team members under a
62
+ .Sy team .
63
+ .Pp
64
+ Indentation is significant.
65
+ Two-space indent is canonical; one tab is also accepted.
66
+ Spaces and tabs must not be mixed inside a single file \(em the
67
+ parser rejects mixed indentation with an error identifying the first
68
+ offending line.
69
+ .Pp
70
+ Strings are double-quoted
71
+ .Pq Qq Auth refactor ,
72
+ not bare or single-quoted.
73
+ Properties are
74
+ .Sy key:value
75
+ pairs on the same line as the entity; values containing spaces must
76
+ be double-quoted.
77
+ Property keys never use
78
+ .Sq = .
79
+ .Pp
80
+ Built-in keywords and property names are kebab-case
81
+ .Pq Sy capacity-icon , Sy days-per-week , Sy in-progress .
82
+ Author-chosen identifiers may use any combination of letters,
83
+ digits, underscores, and dashes
84
+ .Pq Sy auth-refactor , Sy authRefactor , Sy auth_refactor ;
85
+ they must start with a letter or underscore.
86
+ .Pp
87
+ Comments use
88
+ .Sq //
89
+ for single-line and
90
+ .Sq /* */
91
+ for multi-line.
92
+ A trailing
93
+ .Sq \e
94
+ continues a line; indentation on the continuation line is cosmetic.
95
+ Use
96
+ .Sq \e\e
97
+ for a literal backslash.
98
+ .Sh DIRECTIVE
99
+ The
100
+ .Sy nowline
101
+ directive declares which DSL major version a file targets:
102
+ .Bd -literal -offset indent
103
+ nowline v1
104
+ .Ed
105
+ .Pp
106
+ The version is integer-only
107
+ .Pq Sy v1 , Sy v2 , Sy v3 , ...
108
+ and is independent of the npm package version.
109
+ Within a DSL major, the parser must accept every valid file written
110
+ for that major; new syntax may be added between package minor/patch
111
+ releases, but no breaking change to an existing valid
112
+ .Sy nowline v1
113
+ file ships without bumping the directive to
114
+ .Sy v2 .
115
+ When the parser encounters a version newer than it supports, it
116
+ emits an error identifying the required version.
117
+ When the directive is omitted, the parser assumes the latest
118
+ version it supports.
119
+ .Pp
120
+ The directive line accepts optional file-level properties after the
121
+ version.
122
+ The only directive property today is
123
+ .Sy locale: ,
124
+ a BCP-47 tag controlling localized rendering and validator
125
+ messages:
126
+ .Bd -literal -offset indent
127
+ nowline v1 locale:fr-CA
128
+ .Ed
129
+ .Pp
130
+ Unknown directive keys are an error so typos surface immediately.
131
+ See
132
+ .Pa specs/localization.md
133
+ for the locale model and precedence chain.
134
+ .Pp
135
+ The
136
+ .Sy nowline
137
+ directive is the only construct that does not follow the universal
138
+ declaration pattern
139
+ .Pq see Sx GRAMMAR :
140
+ no identifier, no title, just the keyword and version.
141
+ .Sh INCLUDES
142
+ .Sy include
143
+ pulls another
144
+ .Pa .nowline
145
+ file into the current file:
146
+ .Bd -literal -offset indent
147
+ include "shared/teams.nowline"
148
+ include "brand-styles.nowline" roadmap:ignore
149
+ include "partner.nowline" config:isolate roadmap:isolate
150
+ .Ed
151
+ .Pp
152
+ Two optional properties \(em
153
+ .Sy config:
154
+ and
155
+ .Sy roadmap:
156
+ \(em control how the included file's content is handled.
157
+ They operate on two independent categories:
158
+ .Bl -tag -width "Roadmap (content)"
159
+ .It Sy Config
160
+ The included file's
161
+ .Sy scale ,
162
+ .Sy style ,
163
+ .Sy symbol ,
164
+ .Sy default ,
165
+ and
166
+ .Sy calendar
167
+ declarations.
168
+ .It Sy Roadmap
169
+ The included file's
170
+ .Sy roadmap
171
+ declaration plus all its content (persons, teams, anchors, labels,
172
+ sizes, statuses, swimlanes, items, milestones, footnotes).
173
+ .El
174
+ .Pp
175
+ .Sy config:
176
+ modes:
177
+ .Bl -tag -width "isolate"
178
+ .It Sy merge Pq default
179
+ Child config items are merged into the parent.
180
+ On collision, the
181
+ .Em parent wins
182
+ and the parser emits a warning identifying the shadowed definition
183
+ and source file.
184
+ .It Sy ignore
185
+ Child config is dropped entirely.
186
+ If child roadmap content is merged, it resolves styles from the
187
+ parent's post-merge config.
188
+ .It Sy isolate
189
+ Child config is only available within the child file; parent config
190
+ is only available in the parent.
191
+ Neither side bleeds into the other.
192
+ .El
193
+ .Pp
194
+ .Sy roadmap:
195
+ modes:
196
+ .Bl -tag -width "isolate"
197
+ .It Sy merge Pq default
198
+ Child content entities are merged into the parent.
199
+ On collision,
200
+ .Em parent wins
201
+ and a warning is emitted.
202
+ A swimlane collision drops the swimlane's contained items as well.
203
+ Merged content resolves styles from the post-merge config.
204
+ .It Sy ignore
205
+ Child content is dropped.
206
+ Use for shared style libraries
207
+ .Pq Sy include "brand.nowline" roadmap:ignore .
208
+ Shared label, status, and size vocabulary uses
209
+ .Sy roadmap:merge ,
210
+ not
211
+ .Sy roadmap:ignore .
212
+ .It Sy isolate
213
+ Child content stays scoped to the child file and uses only the
214
+ child's config.
215
+ The child must contain a
216
+ .Sy roadmap
217
+ declaration (needed for the region label).
218
+ The isolated content renders as a visually distinct region with its
219
+ own border.
220
+ .El
221
+ .Pp
222
+ Includes are processed depth-first, in file order.
223
+ When the processor encounters an
224
+ .Sy include ,
225
+ it processes that child (and its includes recursively) before
226
+ continuing with the next declaration.
227
+ Config is merged before roadmap content at each level.
228
+ .Pp
229
+ Diamond includes (A includes B and C, both include D) are valid;
230
+ D is processed once on first encounter.
231
+ Duplicate includes of the same file in a single file are an error.
232
+ Circular includes are an error.
233
+ .Pp
234
+ Includes are resolved relative to the including file's directory.
235
+ Paths use forward slashes on all platforms.
236
+ Includes must appear before
237
+ .Sy config
238
+ and
239
+ .Sy roadmap
240
+ \(em they are the first declarations in a file (after the optional
241
+ .Sy nowline
242
+ directive).
243
+ .Pp
244
+ For any include whose
245
+ .Sy roadmap:
246
+ mode is not
247
+ .Sy ignore ,
248
+ if the child file declares a
249
+ .Sy roadmap ,
250
+ the parent and child must agree on
251
+ .Sy start: \(em
252
+ both absent, or both present with identical values.
253
+ A mismatch is an error reported on the parent's
254
+ .Sy include
255
+ line; this is an explicit exception to the
256
+ .Qq parent wins
257
+ merge behaviour because
258
+ .Sy start:
259
+ defines the shared timeline baseline.
260
+ .Sh CONFIG SECTION
261
+ The optional
262
+ .Sy config
263
+ section marker appears before
264
+ .Sy roadmap .
265
+ Config keywords sit at the top level (not indented under the
266
+ marker) and define rendering vocabulary, defaults, axis settings,
267
+ day arithmetic, and custom symbols.
268
+ .Pp
269
+ Five config keywords:
270
+ .Sy scale ,
271
+ .Sy style ,
272
+ .Sy symbol ,
273
+ .Sy default ,
274
+ .Sy calendar .
275
+ Every config entry is optional; if
276
+ .Sy config
277
+ is omitted, all built-in defaults apply.
278
+ .Ss style \(em named visual definition
279
+ A
280
+ .Sy style
281
+ declares a named visual treatment.
282
+ Properties are indented beneath:
283
+ .Bd -literal -offset indent
284
+ style enterprise "Enterprise readiness"
285
+ bg: blue
286
+ fg: navy
287
+ text: white
288
+ border: solid
289
+ icon: shield
290
+
291
+ style risky
292
+ border: dashed
293
+ fg: orange
294
+ .Ed
295
+ .Pp
296
+ Styles follow the universal
297
+ .Sy [id] ["title"]
298
+ pattern.
299
+ Properties are listed under
300
+ .Sx STYLE PROPERTIES
301
+ below.
302
+ .Ss symbol \(em custom named symbol
303
+ A
304
+ .Sy symbol
305
+ declares a custom symbol for use by
306
+ .Sy icon:
307
+ and
308
+ .Sy capacity-icon:
309
+ style properties.
310
+ Authors use the inline Unicode-literal form
311
+ .Pq Sy capacity-icon:"\(rs"
312
+ for one-off symbols; named
313
+ .Sy symbol
314
+ declarations are for reusable ones.
315
+ .Bd -literal -offset indent
316
+ symbol budget "Budget" unicode:"\(em" ascii:"$"
317
+ symbol fte unicode:"\eu{1F464}" ascii:"@"
318
+ symbol star unicode:"\(em"
319
+ .Ed
320
+ .Pp
321
+ Required:
322
+ .Sy unicode:"<string>"
323
+ \(em the Unicode character (literal or
324
+ .Sy \eu{...}
325
+ escape, may be a multi-codepoint grapheme cluster).
326
+ .Pp
327
+ Optional:
328
+ .Sy ascii:"<string>"
329
+ \(em short ASCII fallback for terminals lacking the glyph,
330
+ \(<= 3 ASCII characters; defaults to
331
+ .Sq \&?
332
+ when omitted.
333
+ .Pp
334
+ A
335
+ .Sy symbol
336
+ id must not shadow a built-in icon name
337
+ .Pq Sy none , Sy multiplier , Sy person , Sy people , Sy points , Sy time , Sy shield , Sy warning , Sy lock .
338
+ .Ss default \(em default property values per entity type
339
+ .Sy default <entity> <properties>
340
+ sets default property values for a given entity type.
341
+ One declaration per entity type per file:
342
+ .Bd -literal -offset indent
343
+ default item status:planned shadow:subtle
344
+ default label style:subtle corner-radius:full
345
+ default swimlane padding:sm spacing:none
346
+ default roadmap padding:md header-height:md font:sans
347
+ default milestone weight:bold
348
+ default footnote style:subtle shadow:subtle
349
+ default anchor style:subtle
350
+ default parallel bracket:none
351
+ default group padding:xs spacing:xs
352
+ .Ed
353
+ .Pp
354
+ Supported entity types:
355
+ .Sy item , label , swimlane , roadmap , parallel , group , milestone , footnote , anchor .
356
+ When an entity omits a property, the matching default applies;
357
+ explicit values on the entity always override defaults.
358
+ .Pp
359
+ Identity-defining, sizing, sequencing, reference, and prose
360
+ properties cannot be defaulted because they must be explicit per
361
+ entity.
362
+ Banned, by entity type:
363
+ .Bl -tag -width "default footnote"
364
+ .It Sy default item
365
+ .Sy size , duration , after , before , remaining , link , description , owner .
366
+ .It Sy default milestone
367
+ .Sy date , after , link , description .
368
+ .It Sy default anchor
369
+ .Sy date , link , description .
370
+ .It Sy default footnote
371
+ .Sy on , link , description .
372
+ .El
373
+ .Pp
374
+ Raw style properties
375
+ .Pq Sy bg , Sy fg , Sy text , Sy border , Sy shadow , ...
376
+ are allowed on
377
+ .Sy default
378
+ because
379
+ .Sy default
380
+ lives in
381
+ .Sy config ,
382
+ the presentation section.
383
+ The ban on raw style properties applies to roadmap-section
384
+ entities, not to
385
+ .Sy default
386
+ lines.
387
+ .Pp
388
+ .Sy capacity
389
+ is allowed on
390
+ .Sy default item
391
+ but
392
+ .Em not
393
+ on
394
+ .Sy default swimlane
395
+ \(em each lane's budget is intentionally explicit at its declaration
396
+ site.
397
+ .Sy utilization-warn-at: ,
398
+ .Sy utilization-over-at: ,
399
+ and
400
+ .Sy capacity-icon:
401
+ are allowed on both
402
+ .Sy default swimlane
403
+ and
404
+ .Sy default item
405
+ per the usual presentation-property rule.
406
+ .Ss scale \(em axis display
407
+ .Sy scale
408
+ configures the timeline axis.
409
+ Column width is set by
410
+ .Sy scale:<duration>
411
+ on the
412
+ .Sy roadmap
413
+ declaration; this block configures display:
414
+ .Bd -literal -offset indent
415
+ scale
416
+ name: sprints
417
+ label-every: 2
418
+ label: "Sprint {n}"
419
+ .Ed
420
+ .Bl -tag -width "label-every"
421
+ .It Sy name
422
+ Display label for the scale unit (e.g.
423
+ .Qq sprint ) .
424
+ Defaults to an auto-generated name based on the roadmap's
425
+ .Sy scale:
426
+ duration.
427
+ .It Sy label-every
428
+ Show an axis label every Nth column.
429
+ Defaults to the renderer's choice.
430
+ .It Sy label
431
+ Axis label format.
432
+ .Sq {n}
433
+ is the column index.
434
+ .El
435
+ .Pp
436
+ The
437
+ .Sy scale
438
+ config block is optional.
439
+ A file can declare
440
+ .Sy scale:2w
441
+ on its
442
+ .Sy roadmap
443
+ with no
444
+ .Sy scale
445
+ block and the renderer picks all display defaults.
446
+ .Ss calendar \(em day arithmetic
447
+ The
448
+ .Sy calendar:
449
+ property on
450
+ .Sy roadmap
451
+ selects day-arithmetic mode:
452
+ .Bl -tag -width "calendar:business"
453
+ .It Sy calendar:business Pq default
454
+ Engineering working-day arithmetic.
455
+ .Sy days-per-week:5 ,
456
+ .Sy days-per-month:22 ,
457
+ .Sy days-per-quarter:65 ,
458
+ .Sy days-per-year:260 .
459
+ .It Sy calendar:full
460
+ Calendar-day arithmetic with weekends.
461
+ .Sy days-per-week:7 ,
462
+ .Sy days-per-month:30 ,
463
+ .Sy days-per-quarter:90 ,
464
+ .Sy days-per-year:365 .
465
+ .It Sy calendar:custom
466
+ Author-supplied values via the
467
+ .Sy calendar
468
+ config block.
469
+ .El
470
+ .Pp
471
+ A
472
+ .Sy calendar
473
+ config block is only meaningful when
474
+ .Sy roadmap
475
+ declares
476
+ .Sy calendar:custom .
477
+ When custom, all four
478
+ .Sy days-per-*
479
+ fields are required:
480
+ .Bd -literal -offset indent
481
+ config
482
+
483
+ calendar
484
+ days-per-week: 6
485
+ days-per-month: 26
486
+ days-per-quarter: 78
487
+ days-per-year: 312
488
+
489
+ roadmap rotating-shift "Rotating Shift" calendar:custom
490
+ .Ed
491
+ .Pp
492
+ All four entries must be positive integers.
493
+ There is no partial form.
494
+ .Pp
495
+ Each
496
+ .Sy days-per-*
497
+ field is independently defined: a duration like
498
+ .Sy 1y
499
+ resolves to
500
+ .Sy days-per-year
501
+ directly, not by multiplying through months or weeks.
502
+ This is why business mode's
503
+ .Sy 1y
504
+ is
505
+ .Sy 260d ,
506
+ not
507
+ .Sy 12 \(mu 22d = 264d .
508
+ .Sh ROADMAP SECTION
509
+ The
510
+ .Sy roadmap
511
+ section marker is required and appears exactly once per file.
512
+ Roadmap keywords sit at the top level (not indented under the
513
+ marker) and form the content of the file.
514
+ .Pp
515
+ The
516
+ .Sy roadmap
517
+ declaration line itself accepts:
518
+ .Bd -literal -offset indent
519
+ roadmap platform-2026 "Platform 2026" \e
520
+ author:"Acme" \e
521
+ start:2026-01-06 \e
522
+ scale:2w \e
523
+ calendar:business \e
524
+ logo:"./brand/acme.svg" \e
525
+ logo-size:md
526
+ .Ed
527
+ .Bl -tag -width "calendar:"
528
+ .It Sy author:
529
+ Free-form string.
530
+ .It Sy start:
531
+ ISO date
532
+ .Pq Pa YYYY-MM-DD ,
533
+ the timeline baseline.
534
+ Required if any
535
+ .Sy anchor
536
+ or any dated
537
+ .Sy milestone
538
+ exists.
539
+ Every anchor date and dated milestone date must be on or after
540
+ .Sy start: .
541
+ .It Sy scale:
542
+ Raw duration literal for column width
543
+ .Pq Sy 2w , Sy 1q ;
544
+ defaults to
545
+ .Sy 1w .
546
+ .It Sy calendar:
547
+ .Sy business | full | custom .
548
+ Defaults to
549
+ .Sy business .
550
+ .It Sy logo:
551
+ Path to a logo file
552
+ .Pq Sy .svg , Sy .png , Sy .jpg / Sy .jpeg , Sy .webp ,
553
+ resolved relative to the
554
+ .Pa .nowline
555
+ file's directory.
556
+ Forward slashes on all platforms; only local paths are accepted.
557
+ Asset resolution happens at render time, not parse time \(em a file
558
+ referencing a missing logo is still a valid document.
559
+ .It Sy logo-size:
560
+ Size preset
561
+ .Pq Sy xs | sm | md | lg | xl ,
562
+ default
563
+ .Sy md .
564
+ .El
565
+ .Pp
566
+ Twelve roadmap-section keywords:
567
+ .Sy swimlane , item , parallel , group ,
568
+ .Sy person , team , anchor , label , size , status , milestone ,
569
+ .Sy footnote .
570
+ Each follows the universal
571
+ .Sy [id] ["title"] [key:value...]
572
+ pattern.
573
+ .Ss swimlane \(em group items by team / area / stream
574
+ .Bd -literal -offset indent
575
+ swimlane platform owner:platform capacity:5
576
+ item auth-refactor "Auth refactor" size:l after:kickoff
577
+ item platform-qa "Platform QA" size:s capacity:2
578
+ .Ed
579
+ .Pp
580
+ Items, parallels, and groups are indented beneath.
581
+ Properties:
582
+ .Bl -tag -width "utilization-over-at"
583
+ .It Sy owner:
584
+ Person or team id.
585
+ .It Sy capacity:
586
+ Per-timestep budget.
587
+ Integer or decimal only; no percent form.
588
+ .It Sy utilization-warn-at: , Sy utilization-over-at:
589
+ Thresholds for the lane utilization underline.
590
+ Each accepts a percent literal
591
+ .Pq Sy 80% ,
592
+ a positive decimal interpreted as a fraction
593
+ .Pq Sy 0.8 ,
594
+ or the bareword
595
+ .Sy none
596
+ to opt out of that color band.
597
+ Defaults
598
+ .Sy 80%
599
+ and
600
+ .Sy 100% .
601
+ When both numeric thresholds are set,
602
+ .Sy warn-at \(<= over-at .
603
+ .El
604
+ .Ss item \(em work item
605
+ Items live inside swimlanes (or
606
+ .Sy parallel /
607
+ .Sy group
608
+ blocks) and must declare at least one of
609
+ .Sy size:
610
+ or
611
+ .Sy duration: .
612
+ See
613
+ .Sx ITEM PROPERTIES
614
+ below.
615
+ .Bd -literal -offset indent
616
+ swimlane platform
617
+ item auth-refactor "Auth refactor" size:l status:done
618
+ item "Quick cleanup" size:s
619
+ item sso size:m
620
+ .Ed
621
+ .Ss parallel \(em parallel execution block
622
+ .Sy parallel
623
+ runs its children in parallel.
624
+ Children can be bare items or groups.
625
+ .Bd -literal -offset indent
626
+ swimlane platform
627
+ item auth "Auth refactor" size:l
628
+ parallel
629
+ item api-v2 "API v2" size:m
630
+ item sdk-update "SDK update" size:s
631
+ item integration "Integration" size:s
632
+ .Ed
633
+ .Pp
634
+ .Sy api-v2
635
+ and
636
+ .Sy sdk-update
637
+ start at the same time (after
638
+ .Sy auth
639
+ finishes).
640
+ When the
641
+ .Sy parallel
642
+ block ends, the next sibling
643
+ .Pq Sy integration
644
+ waits for all parallel children to complete (implicit join on
645
+ dedent).
646
+ A
647
+ .Sy parallel
648
+ block must contain at least 2 children; a single-child parallel
649
+ emits a warning.
650
+ .Ss group \(em sequential item bundle
651
+ .Sy group
652
+ bundles items into a named sequential track.
653
+ Inside a swimlane (outside a parallel block), the group is
654
+ sequential with respect to its siblings.
655
+ .Bd -literal -offset indent
656
+ swimlane platform
657
+ group api-work "API Work" labels:enterprise
658
+ item api-v2 "API v2" size:m
659
+ item api-docs "API docs" size:s
660
+ item deploy "Deploy" size:s
661
+ .Ed
662
+ .Pp
663
+ A
664
+ .Sy group
665
+ with
666
+ .Sy style: ,
667
+ .Sy labels: ,
668
+ or other visual properties renders with a visible bounding box
669
+ plus a small title chiclet.
670
+ A
671
+ .Sy group
672
+ with no styling is purely structural \(em it only governs
673
+ sequencing and inner row growth, with no visible artefact.
674
+ .Ss anchor \(em named date on the timeline
675
+ .Bd -literal -offset indent
676
+ anchor kickoff date:2026-01-06
677
+ anchor code-freeze "Code Freeze" date:2026-05-01
678
+ .Ed
679
+ .Pp
680
+ .Sy date:
681
+ is required.
682
+ Anchors are referenced by
683
+ .Sy after:
684
+ and
685
+ .Sy before:
686
+ on items, parallels, groups, and milestones to pin their position.
687
+ .Ss label \(em semantic tag / chip vocabulary
688
+ Labels live in the roadmap section so content and vocabulary live
689
+ together; visual defaults live in
690
+ .Sy config
691
+ via
692
+ .Sy default label
693
+ and referenced
694
+ .Sy style
695
+ blocks.
696
+ .Bd -literal -offset indent
697
+ label enterprise "Enterprise readiness" style:enterprise
698
+ label security "Security hardening" style:enterprise-red
699
+ label low-confidence style:risky-dotted
700
+ .Ed
701
+ .Pp
702
+ A
703
+ .Sy label
704
+ line accepts
705
+ .Sy style:id
706
+ plus universal properties
707
+ .Pq Sy labels: , Sy link: , description .
708
+ Raw style properties are
709
+ .Em not
710
+ allowed on a
711
+ .Sy label
712
+ line.
713
+ Labels used on items without a matching
714
+ .Sy label
715
+ declaration are valid; they render with chip defaults from
716
+ .Sy default label
717
+ or system defaults.
718
+ .Ss size \(em named effort budget
719
+ A
720
+ .Sy size
721
+ maps a named t-shirt size to a single-engineer effort budget.
722
+ .Bd -literal -offset indent
723
+ size xs "Extra Small" effort:0.5d
724
+ size s "Small" effort:3d
725
+ size m "Medium" effort:1w
726
+ size l "Large" effort:2w
727
+ size xl "Extra Large" effort:1m
728
+ .Ed
729
+ .Pp
730
+ .Sy effort:
731
+ is required and must be a positive raw duration literal
732
+ .Pq decimal-aware: Sy 0.5d , Sy 1.5w .
733
+ The id must not match the raw duration pattern
734
+ .Sy \&\ed+(\e.\ed+)?[dwmqy]
735
+ or be a bare
736
+ .Sy d , w , m , q , y
737
+ \(em this avoids ambiguity at the call site.
738
+ .Pp
739
+ On items, the on-bar size chip renders the size's optional
740
+ .Sy title
741
+ when provided, falling back to the id verbatim.
742
+ .Sy size m "M" effort:1w
743
+ renders
744
+ .Qq M ;
745
+ .Sy size m effort:1w
746
+ renders
747
+ .Qq m .
748
+ .Pp
749
+ .Sy size
750
+ declarations must precede any item that references them.
751
+ .Ss status \(em custom status value
752
+ .Bd -literal -offset indent
753
+ status awaiting-review "Awaiting Review"
754
+ status in-review "In Review"
755
+ status deferred "Deferred"
756
+ .Ed
757
+ .Pp
758
+ Extends the built-in set
759
+ .Po
760
+ .Sy planned ,
761
+ .Sy in-progress
762
+ .Pq alias Sy active ,
763
+ .Sy done
764
+ .Pq alias Sy completed ,
765
+ .Sy at-risk ,
766
+ .Sy blocked
767
+ .Pc .
768
+ The aliases canonicalize at the layout boundary; both spellings
769
+ are valid input.
770
+ .Pp
771
+ Custom statuses have no inherent semantics beyond what renderers
772
+ assign; the DSL only guarantees the value resolves and can carry
773
+ a display title.
774
+ Renderers may map custom statuses to visual treatments via
775
+ .Sy default item style:...
776
+ or entity-level
777
+ .Sy style:
778
+ overrides.
779
+ .Pp
780
+ .Sy status
781
+ declarations must precede any entity that references them.
782
+ .Ss milestone \(em achievement marker
783
+ .Bd -literal -offset indent
784
+ milestone v1-ga "v1 GA" date:2026-06-30
785
+ milestone beta "Beta" after:auth-refactor
786
+ milestone v1-ga "v1 GA" after:[core-api, audit-log]
787
+ milestone v1-ga "v1 GA" date:2026-06-30 after:[core-api, audit-log]
788
+ .Ed
789
+ .Pp
790
+ At least one of
791
+ .Sy date:
792
+ or
793
+ .Sy after:
794
+ is required.
795
+ With both, the
796
+ .Sy date:
797
+ is an intended target, not a hard cap; slippage (dependencies not
798
+ converging by the target date) is a rendering concern, not a
799
+ validation error.
800
+ .Ss footnote \(em attachable annotation
801
+ .Bd -literal -offset indent
802
+ footnote "Vendor dependency" on:audit-log
803
+ description "Blocked until vendor contract is signed."
804
+
805
+ footnote capacity-risk "Team capacity risk" on:[mobile, platform]
806
+ description "Both teams are understaffed through Q2."
807
+ .Ed
808
+ .Pp
809
+ .Sy on:
810
+ is required and references one or more identifiers (item,
811
+ swimlane, anchor, milestone, person, team).
812
+ Use bracket notation for multiples:
813
+ .Sy on:[id1, id2] .
814
+ Footnotes are numbered sequentially by document order; a
815
+ superscript number appears on every entity the footnote attaches
816
+ to.
817
+ .Ss person and team \(em organisational vocabulary
818
+ .Bd -literal -offset indent
819
+ person sam "Sam Chen" link:https://github.com/samchen
820
+ person jen "Jennifer Wu"
821
+
822
+ team engineering "Engineering"
823
+ team platform "Platform Team"
824
+ person sam
825
+ person jen
826
+ team mobile "Mobile Team"
827
+ .Ed
828
+ .Pp
829
+ A
830
+ .Sy person
831
+ may be declared at the roadmap top level or nested inside a
832
+ .Sy team .
833
+ .Bl -tag -width "person <id>"
834
+ .It Sy person <id>
835
+ Bare reference.
836
+ Inside a
837
+ .Sy team
838
+ it denotes membership.
839
+ At the roadmap top level it is a no-op (parser may emit a
840
+ warning).
841
+ .It Sy person <id> ["title"] [properties]
842
+ Declaration.
843
+ Creates the person.
844
+ If nested inside a
845
+ .Sy team ,
846
+ the declaration also establishes membership.
847
+ .El
848
+ .Pp
849
+ Person identifiers are global within the merged file scope
850
+ regardless of where they are declared.
851
+ A person may be declared at most once in the merged scope;
852
+ duplicate declarations are an error.
853
+ .Pp
854
+ .Sy team
855
+ nesting inside another
856
+ .Sy team
857
+ is always a declaration.
858
+ Teams cannot be referenced with a bare
859
+ .Sy team <id>
860
+ line.
861
+ .Pp
862
+ Both
863
+ .Sy person
864
+ and
865
+ .Sy team
866
+ support
867
+ .Sy link:
868
+ and the
869
+ .Sy description
870
+ sub-directive.
871
+ .Sh UNIVERSAL PROPERTIES
872
+ These properties are valid on every entity type: items, swimlanes,
873
+ parallel blocks, groups, milestones, anchors, persons, teams,
874
+ labels, sizes, statuses, footnotes.
875
+ .Bl -tag -width "description"
876
+ .It Sy labels:
877
+ List.
878
+ Tags for filtering and display.
879
+ .Sy labels:enterprise
880
+ or
881
+ .Sy labels:[enterprise, security] .
882
+ On an item, each label renders as an atomic chiclet inside the
883
+ bar.
884
+ .It Sy link:
885
+ Bare URL (no quotes).
886
+ One link per entity.
887
+ .It Sy style:
888
+ Identifier.
889
+ Single reference to a named style declared in
890
+ .Sy config .
891
+ This is the only visual property allowed on a roadmap-section
892
+ entity.
893
+ .It Sy description
894
+ Sub-directive.
895
+ Indented under the entity.
896
+ Longer explanatory text:
897
+ .Sy description "Details here" .
898
+ .El
899
+ .Pp
900
+ .Sy Content vs. rendering separation .
901
+ Entities in the roadmap section carry only semantic information
902
+ plus an optional single
903
+ .Sy style:id
904
+ reference.
905
+ Raw style properties
906
+ .Po
907
+ .Sy bg , Sy fg , Sy text , Sy border , Sy icon , Sy shadow ,
908
+ .Sy font , Sy weight , Sy italic , Sy text-size , Sy padding ,
909
+ .Sy spacing , Sy header-height , Sy corner-radius , Sy bracket ,
910
+ .Sy capacity-icon , Sy timeline-position , Sy minor-grid
911
+ .Pc
912
+ may only appear in
913
+ .Sy style
914
+ blocks and
915
+ .Sy default <entity>
916
+ lines \(em both of which live in
917
+ .Sy config .
918
+ .Sh ITEM PROPERTIES
919
+ .Sy status , owner , after ,
920
+ and
921
+ .Sy before
922
+ are also valid on swimlanes, parallel blocks, and groups.
923
+ The rest are item-only.
924
+ .Bl -tag -width "remaining"
925
+ .It Sy status:
926
+ Built-in:
927
+ .Sy planned ,
928
+ .Sy in-progress
929
+ .Pq alias Sy active ,
930
+ .Sy done
931
+ .Pq alias Sy completed ,
932
+ .Sy at-risk ,
933
+ .Sy blocked .
934
+ Custom:
935
+ .Sy status:awaiting-review
936
+ matching a
937
+ .Sy status
938
+ declaration.
939
+ .It Sy owner:
940
+ Person or team id.
941
+ Singular \(em one accountable owner.
942
+ .It Sy after:
943
+ Identifier or bracketed list.
944
+ The entity starts after the referenced entity finishes.
945
+ .Sy after:[a, b]
946
+ starts after the latest finisher.
947
+ Accepts item, milestone, anchor, parallel, or group ids.
948
+ .It Sy before:
949
+ Identifier or bracketed list.
950
+ The entity must finish before the referenced entity starts.
951
+ .Sy before:[a, b]
952
+ finishes before the earliest starter.
953
+ .It Sy size:
954
+ Size alias.
955
+ .Sy size:l
956
+ references a
957
+ .Sy size
958
+ declaration; the item's calendar duration is
959
+ .Sy effort \(di item_capacity
960
+ .Pq Sy capacity:
961
+ defaults to
962
+ .Sy 1
963
+ when absent.
964
+ Items only \(em not valid on
965
+ .Sy parallel
966
+ or
967
+ .Sy group .
968
+ .It Sy duration:
969
+ Raw duration literal only
970
+ .Pq Sy 2w , Sy 3m , Sy 0.5d ;
971
+ no alias names.
972
+ .Sy size:
973
+ is the alias mechanism.
974
+ When set alongside
975
+ .Sy size: ,
976
+ .Sy duration:
977
+ wins for bar width and meta-line driver (size chip omitted).
978
+ Items only.
979
+ .It Sy remaining:
980
+ Work remaining.
981
+ Two equivalent forms: percent
982
+ .Pq Sy remaining:30%
983
+ or single-eng effort literal
984
+ .Pq Sy remaining:1w , Sy remaining:0.5d .
985
+ A literal is normalized to a percent during layout.
986
+ Both forms render identically.
987
+ .Sy status:done
988
+ takes priority.
989
+ Items only.
990
+ .It Sy capacity:
991
+ Concurrent capacity consumed by this item while it runs.
992
+ Positive integer
993
+ .Pq Sy capacity:2 ,
994
+ decimal
995
+ .Pq Sy capacity:0.5 ,
996
+ or percent literal
997
+ .Pq Sy capacity:50%
998
+ which parses to a decimal.
999
+ Items only.
1000
+ .El
1001
+ .Pp
1002
+ .Sy Required properties .
1003
+ .Sy item
1004
+ declarations must include at least one of
1005
+ .Sy size:
1006
+ or
1007
+ .Sy duration: .
1008
+ .Sy anchor
1009
+ declarations require
1010
+ .Sy date: .
1011
+ .Sy milestone
1012
+ declarations require at least one of
1013
+ .Sy date:
1014
+ or
1015
+ .Sy after: .
1016
+ .Sy footnote
1017
+ declarations require
1018
+ .Sy on: .
1019
+ Omitting a required property is a validation error that names the
1020
+ entity by id or title.
1021
+ .Sh CAPACITY
1022
+ .Sy capacity:
1023
+ is an optional annotation that models per-timestep throughput.
1024
+ Both swimlanes and items may declare it, and the two annotations
1025
+ are fully independent \(em neither requires the other.
1026
+ .Bd -literal -offset indent
1027
+ swimlane platform capacity:5
1028
+ item auth size:l capacity:2
1029
+ parallel
1030
+ item api size:m capacity:2
1031
+ item sdk size:m capacity:1
1032
+ item qa size:s capacity:50%
1033
+ .Ed
1034
+ .Pp
1035
+ The unit is opaque to the DSL: authors decide whether
1036
+ .Sy 5
1037
+ means engineers, story points, FTE, hours, or any other measure
1038
+ .Pq same opacity contract as Sy size:l until a Sy size declaration gives it meaning .
1039
+ .Pp
1040
+ Where it can appear:
1041
+ .Bl -tag -width "swimlane"
1042
+ .It Sy swimlane
1043
+ Integer or decimal only (no percent form).
1044
+ The lane's per-timestep budget.
1045
+ .It Sy item
1046
+ Integer, decimal, or percent literal.
1047
+ The item's concurrent consumption.
1048
+ .It Sy parallel , Sy group
1049
+ Not valid \(em derived from children (sum at each timestep across
1050
+ parallel; pass-through for group).
1051
+ Same exclusion family as
1052
+ .Sy size , duration , remaining .
1053
+ .El
1054
+ .Pp
1055
+ Default capacity:
1056
+ .Bl -tag -width "Duration-literal items"
1057
+ .It Sy Sized items
1058
+ .Sy size:
1059
+ declared, no explicit
1060
+ .Sy capacity: \(em
1061
+ capacity defaults to
1062
+ .Sy 1
1063
+ in both duration derivation
1064
+ .Pq Sy duration = effort \(di 1 = effort
1065
+ and overload accounting.
1066
+ .It Sy Duration-literal items
1067
+ .Sy duration:
1068
+ declared, no
1069
+ .Sy size: ,
1070
+ no explicit
1071
+ .Sy capacity: \(em
1072
+ capacity stays unset and the item contributes
1073
+ .Sy 0
1074
+ to overload (uncounted).
1075
+ The literal duration is the bar width regardless.
1076
+ .It Sy Explicit Sy capacity:N
1077
+ Always wins for both purposes.
1078
+ .El
1079
+ .Pp
1080
+ Lifetime: capacity is constant for the item's full duration.
1081
+ No ramps in
1082
+ .Sy v1 .
1083
+ .Pp
1084
+ .Sy Utilization thresholds .
1085
+ Swimlanes that declare
1086
+ .Sy capacity:
1087
+ paint a tri-state utilization underline (green / yellow / red)
1088
+ along the bottom of the band based on the per-timestep load
1089
+ function
1090
+ .Sy f(x) = \(*S items[i].capacity for items active at x .
1091
+ .Bl -tag -width "utilization-over-at"
1092
+ .It Sy utilization-warn-at:N% Pq default Sy 80%
1093
+ At or above this fraction of
1094
+ .Sy capacity: ,
1095
+ the segment paints
1096
+ .Sy yellow .
1097
+ .It Sy utilization-over-at:N% Pq default Sy 100%
1098
+ At or above this fraction of
1099
+ .Sy capacity: ,
1100
+ the segment paints
1101
+ .Sy red .
1102
+ .El
1103
+ .Pp
1104
+ Below
1105
+ .Sy warn-at
1106
+ the segment paints
1107
+ .Sy green .
1108
+ Both thresholds accept the literal value
1109
+ .Sy none
1110
+ to opt out of that color band:
1111
+ .Sy utilization-warn-at:none
1112
+ collapses to a binary green/red indicator;
1113
+ .Sy utilization-over-at:none
1114
+ removes red entirely; setting both to
1115
+ .Sy none
1116
+ suppresses the underline outright.
1117
+ .Sh SIZING PRECEDENCE
1118
+ When an item declares both
1119
+ .Sy size:
1120
+ and
1121
+ .Sy duration: ,
1122
+ the explicit
1123
+ .Sy duration:
1124
+ literal wins for bar width and the meta line: the size chip is
1125
+ not shown (only the literal appears as the driver token).
1126
+ .Bl -column -offset indent "size:" "duration:" "capacity:" "Resulting duration"
1127
+ .It Sy size: Ta Sy duration: Ta Sy capacity: Ta Resulting duration
1128
+ .It l Ta \(em Ta \(em Ta size.l.effort \(di 1 (e.g. 2w)
1129
+ .It l Ta \(em Ta 2 Ta size.l.effort \(di 2 (e.g. 1w)
1130
+ .It l Ta 2w Ta 2 Ta 2w (literal wins; no chip)
1131
+ .It \(em Ta 2w Ta 2 Ta 2w (capacity does not divide a literal)
1132
+ .It \(em Ta \(em Ta \(em Ta validation error
1133
+ .El
1134
+ .Sh STYLE PROPERTIES
1135
+ Properties valid inside a
1136
+ .Sy style
1137
+ block (and on
1138
+ .Sy default <entity>
1139
+ lines):
1140
+ .Bl -tag -width "timeline-position"
1141
+ .It Sy bg
1142
+ Background/fill color or
1143
+ .Sy none .
1144
+ Named
1145
+ .Po
1146
+ .Sy red , blue , yellow , green , orange ,
1147
+ .Sy purple
1148
+ .Pq alias Sy violet ,
1149
+ .Sy gray
1150
+ .Pq alias Sy grey ,
1151
+ .Sy navy , white
1152
+ .Pc ,
1153
+ hex
1154
+ .Pq Sy #2563eb ,
1155
+ or
1156
+ .Sy none
1157
+ (transparent).
1158
+ .It Sy fg
1159
+ Border/outline color.
1160
+ Named, hex, or
1161
+ .Sy none
1162
+ (no border).
1163
+ .It Sy text
1164
+ Text color.
1165
+ Named, hex, or
1166
+ .Sy none
1167
+ (hides text).
1168
+ .It Sy border
1169
+ .Sy solid | dashed | dotted .
1170
+ .It Sy icon
1171
+ Identifier or string.
1172
+ Built-in identifiers
1173
+ .Po
1174
+ .Sy shield , warning , lock , plus the capacity-icon vocabulary
1175
+ .Pc ;
1176
+ custom: any identifier declared by a
1177
+ .Sy symbol
1178
+ declaration; inline: a double-quoted Unicode literal
1179
+ .Pq Sy "\(rs"
1180
+ \(em font-dependent.
1181
+ .It Sy shadow
1182
+ .Sy none Pq default | subtle | soft | hard .
1183
+ .It Sy font
1184
+ .Sy sans Pq default | serif | mono .
1185
+ .It Sy weight
1186
+ .Sy thin | light | normal Pq default | bold .
1187
+ .It Sy italic
1188
+ .Sy true | false Pq default .
1189
+ .It Sy text-size
1190
+ .Sy xs | sm | md Pq default | lg | xl .
1191
+ .It Sy padding
1192
+ .Sy none | xs | sm | md Pq default | lg | xl .
1193
+ .It Sy spacing
1194
+ .Sy none | xs | sm | md | lg | xl .
1195
+ Default varies by entity.
1196
+ .It Sy header-height
1197
+ .Sy none | xs | sm | md Pq default | lg | xl .
1198
+ Roadmap-only.
1199
+ .It Sy corner-radius
1200
+ .Sy none | xs | sm | md | lg | xl | full .
1201
+ .It Sy bracket
1202
+ .Sy none Pq default | solid | dashed .
1203
+ Parallel-only.
1204
+ .It Sy capacity-icon
1205
+ Glyph used as the suffix to capacity numbers.
1206
+ Built-in identifiers:
1207
+ .Sy none ,
1208
+ .Sy multiplier
1209
+ .Pq default \(em "\(mu" ,
1210
+ .Sy person ,
1211
+ .Sy people ,
1212
+ .Sy points
1213
+ .Pq "\(em" ,
1214
+ .Sy time
1215
+ .Pq "\(em" .
1216
+ Custom: any
1217
+ .Sy symbol
1218
+ id; inline: a double-quoted Unicode literal.
1219
+ .It Sy timeline-position
1220
+ .Sy top Pq default | bottom | both .
1221
+ Roadmap-only.
1222
+ .Sy both
1223
+ mirrors the date strip at the chart bottom.
1224
+ .It Sy minor-grid
1225
+ .Sy true | false Pq default .
1226
+ Roadmap-only.
1227
+ When
1228
+ .Sy true ,
1229
+ draws faint dotted grid lines at every tick boundary.
1230
+ .El
1231
+ .Pp
1232
+ Built-in icon names are rendered from a curated SVG library
1233
+ shipped with the renderer, not from Unicode emoji codepoints.
1234
+ This guarantees consistent visual output across every platform
1235
+ (web, CLI, exports).
1236
+ Authors who want platform-default emoji rendering use an inline
1237
+ Unicode literal instead of the named identifier.
1238
+ .Sh GRAMMAR
1239
+ .Ss Universal declaration pattern
1240
+ Every entity declaration follows the same shape:
1241
+ .Bd -literal -offset indent
1242
+ keyword [id] ["title"] [key:value ...]
1243
+ .Ed
1244
+ .Bl -tag -width "Identifier"
1245
+ .It Sy Identifier
1246
+ Unquoted, matches
1247
+ .Sy [a-zA-Z_][a-zA-Z0-9_-]* .
1248
+ Used for referencing.
1249
+ Optional \(em auto-generated from the title (kebab-cased) if
1250
+ omitted.
1251
+ .It Sy Title
1252
+ Double-quoted string.
1253
+ Human-readable display name.
1254
+ Optional.
1255
+ Always double-quoted, even single-word titles \(em the quote is
1256
+ how the parser distinguishes id from title.
1257
+ .El
1258
+ .Pp
1259
+ At least one of
1260
+ .Sy id
1261
+ or
1262
+ .Sy "title"
1263
+ must be present.
1264
+ Every other input is a keyed property using
1265
+ .Sy key:value .
1266
+ .Pp
1267
+ The
1268
+ .Sy nowline
1269
+ directive is the only construct without an id or title; every
1270
+ other declaration follows this pattern.
1271
+ .Ss Identifiers
1272
+ Identifiers match
1273
+ .Sy [a-zA-Z_][a-zA-Z0-9_-]* \(em
1274
+ letters, digits, underscores, and dashes, starting with a letter
1275
+ or underscore.
1276
+ They must be unique across the merged result (the file and all
1277
+ its includes); items, parallel blocks, groups, anchors, persons,
1278
+ teams, milestones, footnotes share one namespace.
1279
+ .Pp
1280
+ Idiomatic Nowline uses kebab-case but
1281
+ .Sy authRefactor ,
1282
+ .Sy auth_refactor ,
1283
+ and
1284
+ .Sy MED
1285
+ are equally valid.
1286
+ .Pp
1287
+ When omitted, the parser generates one by slugifying the title to
1288
+ kebab-case:
1289
+ .Qq Audit log v2
1290
+ becomes
1291
+ .Sy audit-log-v2 .
1292
+ .Ss Lists
1293
+ Any list-typed property accepts a single value without brackets or
1294
+ multiple values with bracket notation:
1295
+ .Bd -literal -offset indent
1296
+ labels:enterprise
1297
+ labels:[enterprise, security]
1298
+ .Ed
1299
+ .Pp
1300
+ No quotes around identifiers in lists.
1301
+ Comma-separated, optional spaces.
1302
+ .Ss Dependencies
1303
+ .Sy after:
1304
+ and
1305
+ .Sy before:
1306
+ each accept a single identifier or a bracketed list.
1307
+ References may target items, milestones, anchors, parallel
1308
+ blocks, or groups.
1309
+ .Bl -bullet -offset indent -compact
1310
+ .It
1311
+ .Sy after:id
1312
+ \(em this entity starts after the referenced entity finishes (or
1313
+ after the referenced anchor date).
1314
+ .It
1315
+ .Sy after:[id1, id2, ...]
1316
+ \(em starts after
1317
+ .Em all
1318
+ referenced entities finish (i.e. after the latest of them).
1319
+ .It
1320
+ .Sy before:id
1321
+ \(em this entity must finish before the referenced entity starts
1322
+ (or before the referenced anchor date).
1323
+ .It
1324
+ .Sy before:[id1, id2, ...]
1325
+ \(em finishes before the
1326
+ .Em earliest
1327
+ of the referenced entities starts.
1328
+ .El
1329
+ .Pp
1330
+ Circular dependencies across the full graph (including every
1331
+ element of list-form references) are a validation error.
1332
+ .Ss Line continuation
1333
+ A trailing
1334
+ .Sq \e
1335
+ means the next line continues the same declaration.
1336
+ Indentation on the continuation line is cosmetic.
1337
+ Only valid at the end of a property line \(em not inside strings
1338
+ or comments.
1339
+ Use
1340
+ .Sq \e\e
1341
+ for a literal backslash.
1342
+ .Bd -literal -offset indent
1343
+ item auth "Auth refactor" duration:2w status:in-progress \e
1344
+ owner:sam labels:[security,enterprise] \e
1345
+ link:https://github.com/acme/auth/issues/123 \e
1346
+ style:flagged
1347
+ .Ed
1348
+ .Ss Comments
1349
+ .Bd -literal -offset indent
1350
+ // This is a single-line comment
1351
+
1352
+ /* This is a
1353
+ multi-line comment */
1354
+ .Ed
1355
+ .Sh VALIDATION
1356
+ The parser produces clear error messages with file position and
1357
+ suggestions (fuzzy-match
1358
+ .Qq did you mean X?
1359
+ hints).
1360
+ Rules group as follows; full prose lives in
1361
+ .Pa specs/dsl.md .
1362
+ .Ss Structural
1363
+ .Bl -bullet -offset indent -compact
1364
+ .It
1365
+ Exactly one
1366
+ .Sy roadmap
1367
+ declaration per file (subject to
1368
+ .Sy include
1369
+ .Sy roadmap:
1370
+ mode).
1371
+ .It
1372
+ All identifiers are unique across the merged result.
1373
+ Parent wins on collision, with a warning.
1374
+ .It
1375
+ Every entity must have at least an identifier or a title (or
1376
+ both).
1377
+ .It
1378
+ File structure must follow the section order:
1379
+ .Sy nowline
1380
+ directive (optional, first non-comment line),
1381
+ .Sy include ,
1382
+ .Sy config ,
1383
+ .Sy roadmap .
1384
+ .It
1385
+ The
1386
+ .Sy nowline
1387
+ directive version must match
1388
+ .Sy v\&\ed+ .
1389
+ A version newer than the parser supports is an error identifying
1390
+ the required version.
1391
+ .It
1392
+ At least one swimlane is required in the merged result.
1393
+ .It
1394
+ Indentation must be consistent within a file: spaces
1395
+ .Em or
1396
+ tabs, not both.
1397
+ Mixed indentation is a parse error identifying the first offending
1398
+ line.
1399
+ .It
1400
+ .Sy label ,
1401
+ .Sy size ,
1402
+ and
1403
+ .Sy status
1404
+ declarations must appear in the roadmap section.
1405
+ Placing them before
1406
+ .Sy roadmap
1407
+ is an error.
1408
+ .El
1409
+ .Ss References
1410
+ .Bl -bullet -offset indent -compact
1411
+ .It
1412
+ All elements of
1413
+ .Sy after: ,
1414
+ .Sy before: ,
1415
+ and
1416
+ .Sy on:
1417
+ must resolve to declared identifiers within the merged scope.
1418
+ .It
1419
+ A
1420
+ .Sy size:
1421
+ or
1422
+ .Sy status:
1423
+ reference must resolve to a declaration that appears
1424
+ .Em earlier in the file
1425
+ (or in an earlier include).
1426
+ Forward references are an error.
1427
+ .It
1428
+ No circular dependencies in
1429
+ .Sy after / before
1430
+ chains.
1431
+ .El
1432
+ .Ss Values
1433
+ .Bl -bullet -offset indent -compact
1434
+ .It
1435
+ .Sy anchor date:
1436
+ and dated
1437
+ .Sy milestone date:
1438
+ values are valid ISO 8601 dates
1439
+ .Pq Pa YYYY-MM-DD , calendar-valid .
1440
+ .It
1441
+ .Sy duration:
1442
+ and
1443
+ .Sy scale:
1444
+ values match the raw duration pattern
1445
+ .Sy \&\ed+(\e.\ed+)?[dwmqy] .
1446
+ .It
1447
+ A
1448
+ .Sy size
1449
+ declaration's id must not match the raw duration pattern and must
1450
+ not be a bare
1451
+ .Sy d , w , m , q , y .
1452
+ .It
1453
+ Every
1454
+ .Sy size
1455
+ declaration must specify
1456
+ .Sy effort: ;
1457
+ the value must be a positive raw duration literal.
1458
+ .It
1459
+ .Sy capacity:
1460
+ on a
1461
+ .Sy swimlane
1462
+ must be a positive integer or decimal (no percent form).
1463
+ .Sy capacity:
1464
+ on an
1465
+ .Sy item
1466
+ must be a positive integer, decimal, or percent literal.
1467
+ .Sy capacity:
1468
+ is not valid on
1469
+ .Sy parallel
1470
+ or
1471
+ .Sy group .
1472
+ .It
1473
+ .Sy utilization-warn-at:
1474
+ and
1475
+ .Sy utilization-over-at:
1476
+ must each be a positive percent literal, a positive decimal
1477
+ fraction, or
1478
+ .Sy none .
1479
+ When both numeric thresholds are set,
1480
+ .Sy warn-at \(<= over-at .
1481
+ .It
1482
+ .Sy capacity-icon:
1483
+ value must be a built-in identifier
1484
+ .Po
1485
+ .Sy none , Sy multiplier , Sy person , Sy people , Sy points , Sy time
1486
+ .Pc ,
1487
+ an identifier matching a
1488
+ .Sy symbol
1489
+ declaration in scope, or a double-quoted Unicode literal.
1490
+ Same contract for
1491
+ .Sy icon: .
1492
+ .It
1493
+ .Sy remaining:
1494
+ is either a percentage
1495
+ .Pq Sy 0% \(en Sy 100%
1496
+ or a single-eng effort literal.
1497
+ When the literal exceeds total effort (computed percent
1498
+ .Sy > 100% ) ,
1499
+ the layout step emits a soft warning and clamps the painted bar
1500
+ to 100% remaining; rendering is never blocked.
1501
+ .El
1502
+ .Ss Calendar
1503
+ .Bl -bullet -offset indent -compact
1504
+ .It
1505
+ .Sy calendar:
1506
+ on
1507
+ .Sy roadmap
1508
+ must be one of
1509
+ .Sy business , full , custom .
1510
+ .It
1511
+ A
1512
+ .Sy calendar
1513
+ config block is only valid when the roadmap declares
1514
+ .Sy calendar:custom .
1515
+ .It
1516
+ When
1517
+ .Sy calendar:custom ,
1518
+ all four
1519
+ .Sy days-per-*
1520
+ entries are required and must be positive integers.
1521
+ .El
1522
+ .Ss Roadmap start property
1523
+ .Bl -bullet -offset indent -compact
1524
+ .It
1525
+ .Sy roadmap start:
1526
+ must be a valid ISO 8601 date.
1527
+ .It
1528
+ If a file contains any
1529
+ .Sy anchor
1530
+ or any dated
1531
+ .Sy milestone ,
1532
+ .Sy start:
1533
+ is required.
1534
+ .It
1535
+ Every anchor date and every dated milestone date must be on or
1536
+ after
1537
+ .Sy start: .
1538
+ .El
1539
+ .Ss Persons and teams
1540
+ .Bl -bullet -offset indent -compact
1541
+ .It
1542
+ A
1543
+ .Sy person
1544
+ may be declared at most once in the merged file scope.
1545
+ A declaration is identified by the presence of a title or any
1546
+ keyed property on the line.
1547
+ .It
1548
+ A bare
1549
+ .Sy person <id>
1550
+ inside a
1551
+ .Sy team
1552
+ denotes membership and is valid with or without a separate
1553
+ declaration.
1554
+ .It
1555
+ A bare
1556
+ .Sy person <id>
1557
+ at roadmap top level with no matching declaration anywhere is a
1558
+ no-op (parser may emit a warning).
1559
+ .El
1560
+ .Ss Includes
1561
+ .Bl -bullet -offset indent -compact
1562
+ .It
1563
+ .Sy include
1564
+ paths must resolve to an existing
1565
+ .Pa .nowline
1566
+ file relative to the including file's directory.
1567
+ .It
1568
+ No circular includes.
1569
+ .It
1570
+ .Sy include
1571
+ declarations appear before
1572
+ .Sy config
1573
+ and
1574
+ .Sy roadmap
1575
+ (after the
1576
+ .Sy nowline
1577
+ directive if present).
1578
+ .It
1579
+ Duplicate
1580
+ .Sy include
1581
+ of the same file in a single file is an error.
1582
+ .It
1583
+ .Sy config:
1584
+ must be
1585
+ .Sy merge , ignore , or isolate .
1586
+ .Sy roadmap:
1587
+ must be
1588
+ .Sy merge , ignore , or isolate .
1589
+ .It
1590
+ On
1591
+ .Sy config:isolate ,
1592
+ .Sy style:
1593
+ references within the isolated file must resolve within that
1594
+ file's own config.
1595
+ .It
1596
+ On
1597
+ .Sy roadmap:isolate ,
1598
+ the included file must contain a
1599
+ .Sy roadmap
1600
+ declaration.
1601
+ .It
1602
+ For any
1603
+ .Sy include
1604
+ whose
1605
+ .Sy roadmap:
1606
+ mode is not
1607
+ .Sy ignore ,
1608
+ parent and child must agree on
1609
+ .Sy start: \(em
1610
+ both absent or both present with identical values.
1611
+ A mismatch is an error reported on the parent's
1612
+ .Sy include
1613
+ line.
1614
+ .El
1615
+ .Ss Parallel and group
1616
+ .Bl -bullet -offset indent -compact
1617
+ .It
1618
+ .Sy parallel
1619
+ must contain at least 2 children.
1620
+ A single-child parallel emits a warning.
1621
+ .It
1622
+ .Sy group
1623
+ must contain at least 1 child.
1624
+ .It
1625
+ .Sy size , duration , remaining , capacity
1626
+ are not valid on
1627
+ .Sy parallel
1628
+ or
1629
+ .Sy group
1630
+ (computed from children).
1631
+ .It
1632
+ .Sy parallel
1633
+ is valid inside swimlane or group.
1634
+ .Pp
1635
+ .Sy group
1636
+ is valid inside swimlane, parallel, or group.
1637
+ .El
1638
+ .Ss Defaults
1639
+ .Bl -bullet -offset indent -compact
1640
+ .It
1641
+ The first positional argument after
1642
+ .Sy default
1643
+ must be one of:
1644
+ .Sy item , label , swimlane , roadmap , parallel , group ,
1645
+ .Sy milestone , footnote , anchor .
1646
+ .It
1647
+ Duplicate
1648
+ .Sy default <entity>
1649
+ declarations for the same entity type within a single file are
1650
+ an error.
1651
+ .It
1652
+ A
1653
+ .Sy default <entity>
1654
+ that sets a banned property
1655
+ .Pq see Sx CONFIG SECTION
1656
+ is an error.
1657
+ .El
1658
+ .Ss Symbols
1659
+ .Bl -bullet -offset indent -compact
1660
+ .It
1661
+ Every
1662
+ .Sy symbol
1663
+ declaration must specify a non-empty
1664
+ .Sy unicode:"<string>" .
1665
+ .It
1666
+ .Sy ascii: ,
1667
+ if present, must be a quoted string of length \(<= 3 ASCII
1668
+ characters.
1669
+ .It
1670
+ A
1671
+ .Sy symbol
1672
+ id must not shadow a built-in icon name.
1673
+ .It
1674
+ A
1675
+ .Sy symbol
1676
+ reference
1677
+ .Pq Sy icon:NAME or Sy capacity-icon:NAME
1678
+ must resolve to a built-in or an earlier
1679
+ .Sy symbol
1680
+ declaration.
1681
+ Forward references are an error.
1682
+ .El
1683
+ .Sh EXAMPLES
1684
+ A complete
1685
+ .Pa .nowline
1686
+ file exercising the major language features:
1687
+ .Bd -literal -offset indent
1688
+ nowline v1
1689
+
1690
+ include "shared/teams.nowline"
1691
+
1692
+ config
1693
+
1694
+ style enterprise "Enterprise readiness"
1695
+ bg: blue
1696
+ fg: navy
1697
+ text: white
1698
+ border: solid
1699
+ icon: shield
1700
+
1701
+ style risky
1702
+ border: dashed
1703
+ fg: orange
1704
+
1705
+ default item status:planned shadow:subtle
1706
+ default label style:subtle corner-radius:full
1707
+ default swimlane padding:sm spacing:none
1708
+
1709
+ roadmap platform-2026 "Platform 2026" \e
1710
+ author:"Acme Engineering" \e
1711
+ logo:"./brand/acme.svg" \e
1712
+ start:2026-01-06 scale:2w calendar:business
1713
+
1714
+ person sam "Sam Chen" link:https://github.com/samchen
1715
+ person jen "Jennifer Wu"
1716
+
1717
+ team engineering "Engineering"
1718
+ team platform "Platform Team"
1719
+ person sam
1720
+ person jen
1721
+ team mobile "Mobile Team"
1722
+
1723
+ anchor kickoff date:2026-01-06
1724
+ anchor code-freeze "Code Freeze" date:2026-05-01
1725
+ anchor ga-date "GA Date" date:2026-06-01
1726
+
1727
+ size xs "Extra Small" effort:1d
1728
+ size s "Small" effort:3d
1729
+ size m "Medium" effort:1w
1730
+ size l "Large" effort:2w
1731
+ size xl "Extra Large" effort:1m
1732
+
1733
+ status awaiting-review "Awaiting Review"
1734
+
1735
+ label enterprise "Enterprise readiness" style:enterprise
1736
+ label security "Security hardening" style:enterprise
1737
+ label low-confidence style:risky
1738
+
1739
+ swimlane platform owner:platform capacity:5
1740
+ item auth-refactor "Auth refactor" size:l after:kickoff \e
1741
+ status:done owner:sam labels:enterprise capacity:3 \e
1742
+ link:https://github.com/acme/auth/issues/123
1743
+ parallel after:auth-refactor
1744
+ group audit-track "Audit Track" labels:security
1745
+ item audit-log "Audit log v2" size:xl before:code-freeze \e
1746
+ remaining:30% labels:[enterprise, security] capacity:2
1747
+ description "Comprehensive audit trail for admin actions"
1748
+ item audit-ui "Audit UI" size:m capacity:1
1749
+ item sso "SSO plugins" size:m \e
1750
+ labels:[enterprise, low-confidence] capacity:50%
1751
+ item platform-qa "Platform QA" size:s capacity:2
1752
+
1753
+ swimlane mobile owner:mobile capacity:2
1754
+ item offline "Offline mode" size:l after:kickoff owner:jen \e
1755
+ status:at-risk remaining:60% capacity:3
1756
+ item push-v2 "Push notifications v2" size:m owner:mobile capacity:1
1757
+
1758
+ milestone beta "Beta" after:auth-refactor
1759
+ milestone v1-ga "v1 GA" after:[auth-refactor, audit-log]
1760
+ milestone ga-launch "GA launch" date:2026-06-01 \e
1761
+ after:[auth-refactor, audit-log]
1762
+
1763
+ footnote "Vendor dependency" on:audit-log
1764
+ description "Blocked until vendor contract is signed."
1765
+ footnote capacity-risk "Team capacity risk" on:[mobile, platform]
1766
+ description "Mobile team is down to 2 engineers through Q2."
1767
+ .Ed
1768
+ .Sh SEE ALSO
1769
+ .Xr nowline 1
1770
+ .Pq Sy man 1 nowline
1771
+ .Pp
1772
+ The
1773
+ .Sy specs/
1774
+ directory in the source repository documents the DSL grammar in
1775
+ prose
1776
+ .Pq Pa specs/dsl.md ,
1777
+ the layout / rendering pipeline
1778
+ .Pq Pa specs/rendering.md ,
1779
+ the localization model
1780
+ .Pq Pa specs/localization.md ,
1781
+ and OSS milestones
1782
+ .Pq Pa specs/milestones.md .
1783
+ .Sh AUTHORS
1784
+ .An Lolay Aq Mt packages@lolay.com