@nowline/cli 0.0.0-dev.20260601071750.g04bdff9

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