@rse/specbook 0.9.5 → 0.9.7

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 (61) hide show
  1. package/README.md +108 -328
  2. package/dst/specbook-api.d.ts +13 -20
  3. package/dst/specbook-api.js +43 -39
  4. package/dst/specbook-cli.js +42 -55
  5. package/dst/specbook-cmd-describe.d.ts +5 -2
  6. package/dst/specbook-cmd-describe.js +30 -91
  7. package/dst/specbook-cmd-export.d.ts +3 -3
  8. package/dst/specbook-cmd-export.js +23 -19
  9. package/dst/specbook-cmd-init.d.ts +3 -3
  10. package/dst/specbook-cmd-init.js +38 -15
  11. package/dst/specbook-cmd-lint.d.ts +5 -6
  12. package/dst/specbook-cmd-lint.js +61 -24
  13. package/dst/specbook-config.d.ts +2 -2
  14. package/dst/specbook-config.js +82 -73
  15. package/dst/specbook-diagnostic.js +4 -1
  16. package/dst/specbook-diagram.d.ts +6 -5
  17. package/dst/specbook-diagram.js +94 -104
  18. package/dst/specbook-export-ast.d.ts +3 -3
  19. package/dst/specbook-export-ast.js +1 -1
  20. package/dst/specbook-export-common.d.ts +11 -9
  21. package/dst/specbook-export-common.js +34 -22
  22. package/dst/specbook-export-html-search.js +10 -14
  23. package/dst/specbook-export-html.css +37 -32
  24. package/dst/specbook-export-html.d.ts +4 -4
  25. package/dst/specbook-export-html.js +153 -107
  26. package/dst/specbook-export-logo-dark.svg +35 -0
  27. package/dst/specbook-export-logo-light.svg +35 -0
  28. package/dst/specbook-export-md.d.ts +3 -3
  29. package/dst/specbook-export-md.js +50 -24
  30. package/dst/specbook-export-pdf.d.ts +4 -2
  31. package/dst/specbook-export-pdf.js +48 -38
  32. package/dst/{specbook-struct-schema.d.ts → specbook-format-schema.d.ts} +3 -2
  33. package/dst/{specbook-struct-schema.js → specbook-format-schema.js} +8 -4
  34. package/dst/specbook-format-spec.d.ts +31 -0
  35. package/dst/{specbook-struct-spec.js → specbook-format-spec.js} +10 -10
  36. package/dst/specbook-format.md +750 -0
  37. package/dst/specbook-link.d.ts +3 -2
  38. package/dst/specbook-link.js +7 -4
  39. package/dst/specbook-mcp.d.ts +2 -1
  40. package/dst/specbook-mcp.js +30 -62
  41. package/dst/specbook-parse-common.d.ts +5 -3
  42. package/dst/specbook-parse-common.js +8 -0
  43. package/dst/specbook-parse-semantic.d.ts +6 -4
  44. package/dst/specbook-parse-semantic.js +98 -106
  45. package/dst/specbook-parse-syntax.d.ts +2 -2
  46. package/dst/specbook-parse-syntax.js +175 -144
  47. package/dst/specbook-parse-value.d.ts +1 -1
  48. package/dst/specbook-parse-value.js +6 -3
  49. package/dst/specbook-parse.d.ts +4 -7
  50. package/dst/specbook-parse.js +28 -35
  51. package/dst/specbook-verbose.d.ts +2 -0
  52. package/dst/specbook-verbose.js +17 -0
  53. package/package.json +3 -7
  54. package/dst/specbook-cmd-edit.d.ts +0 -9
  55. package/dst/specbook-cmd-edit.js +0 -74
  56. package/dst/specbook-cmd-import.d.ts +0 -9
  57. package/dst/specbook-cmd-import.js +0 -78
  58. package/dst/specbook-export-logo.svg +0 -35
  59. package/dst/specbook-llm.d.ts +0 -13
  60. package/dst/specbook-llm.js +0 -51
  61. package/dst/specbook-struct-spec.d.ts +0 -31
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- <img src="https://raw.githubusercontent.com/rse/specbook/master/etc/specbook-logo.svg" width="400" align="right" alt=""/>
2
+ <img src="https://raw.githubusercontent.com/rse/specbook/master/etc/specbook-logo-blue-light.svg" width="400" align="right" alt=""/>
3
3
 
4
4
  SpecBook
5
5
  ========
@@ -13,22 +13,76 @@ About
13
13
  format* which can be configured for the specifications of particular
14
14
  contexts through a YAML-based *schema configuration*. SpecBook allows
15
15
  specifications to be *initialized*, *linted*, *exported* (JSON, JSON5,
16
- YAML, TOON, HTML, PDF, and normalized Markdown), *described* to LLMs,
17
- and LLM-assisted *imported* and *edited* -- through an API class with
18
- methods `<cmd>()`, a CLI with commands `specbook <cmd>`, and an MCP
19
- service with tools `specbook_<cmd>()`.
16
+ YAML, TOON, HTML, PDF, and normalized Markdown), and *described* to
17
+ LLMs.
18
+
19
+ **SpecBook** ships with an API class with methods `<xxx>()`, a
20
+ CLI with commands `specbook <xxx>`, and an MCP service with tools
21
+ `specbook_<xxx>()`.
20
22
 
21
23
  **SpecBook** provides the following distinct features:
22
24
 
23
- - hierarchical object structure
24
- - strict Markdown-based input format
25
- - complex and concise object to Markdown mappings
26
- - Wiki-style hierarchy-aware object hyperlinks
27
- - canonical Markdown output format
28
- - AST-based JSON, JSON5, YAML, and TOON output formats
29
- - HTML output format for online reading
30
- - PDF output format for printing and archiving
31
- - CLI, MCP, and API interfaces
25
+ - **Hierarchical Object Model**:
26
+ A specification is a tree of typed objects, each with a kind and
27
+ name, an optional id, optional properties, optional description, and
28
+ optional child objects. The allowed object hierarchy is defined per
29
+ context by the YAML schema configuration.
30
+
31
+ - **Versatile Object to Markdown Mapping**:
32
+ Objects are authored as plain Markdown headings, property lists,
33
+ and description prose. The objects can be mapped to nested sections
34
+ ("complex" format) or a compact bullet point lists ("concise" and
35
+ "group" format).
36
+
37
+ - **Wiki-Style Object Linking**:
38
+ Objects can hierarchically reference each other through Wiki-style
39
+ `[[xxx]]` references, which are resolved against the locally-unique
40
+ ids and names of all objects. In the HTML and PDF exports they become
41
+ navigable links onto precise anchors.
42
+
43
+ - **Strict Validation with Custom Schema**:
44
+ The YAML schema configuration strictly defines the allowed object
45
+ kinds, hierarchies, and properties, whose values are constrained by an
46
+ expression language (regex, enum, tags, list, and reference). Violations
47
+ are reported as file- and line-precise diagnostics.
48
+
49
+ - **Object Model Diagram Visualisation**:
50
+ Object kinds can declare "graph", "hub", or "grid" diagrams in the
51
+ schema, whose nodes and edges are automatically derived from the
52
+ object model and its references. The diagrams are rendered with the
53
+ sibling project [Gradia](https://github.com/rse/gradia), which is
54
+ specialized on rendering object models.
55
+
56
+ - **CLI, MCP, and API Interface**:
57
+ All commands are implemented once in the API class `SpecBook`, on
58
+ which both the CLI and the MCP service are just thin wrappers.
59
+ This way, humans, scripts, and AI agents use exactly the same
60
+ functionality.
61
+
62
+ - **AST Exports for AI/LLMs**:
63
+ The parsed specification Abstract Syntax Tree (AST) can be exported in
64
+ JSON, JSON5, YAML, or TOON format for machine consumption. Together
65
+ with the `describe` command, which explains the models and formats,
66
+ this enables LLMs to both read and write specifications.
67
+
68
+ - **HTML Export for Developers**:
69
+ The HTML export is a self-contained single document with a
70
+ table-of-contents, full-text search, embedded images, and a light/dark
71
+ theme toggle. It is intended for the day-to-day online reading during
72
+ development. The HTML export can map all object kinds to nested
73
+ sections or compact tables, or an automatic mixture which collapses
74
+ only the deepest level into tables.
75
+
76
+ - **PDF Export for Customers**:
77
+ The PDF export prints the HTML rendering via Chromium and post-processes
78
+ it with page numbers, headers/footers, and a hierarchical PDF outline.
79
+ It is intended as a polished, paginated offline document for handing
80
+ over to customers.
81
+
82
+ Overview Poster
83
+ ---------------
84
+
85
+ [![poster](etc/poster.png)](etc/poster.pdf)
32
86
 
33
87
  Rendering Example
34
88
  -----------------
@@ -45,308 +99,31 @@ Rendering Example
45
99
 
46
100
  ![screenshot-print](etc/screenshot-print.png)
47
101
 
48
- Specification Format
49
- --------------------
50
-
51
- ### Artifact Files
52
-
53
- A specification consists of Markdown *artifact* files, which are
54
- scanned recursively from a base directory. Every file has to start with
55
- a frontmatter block carrying the `Created:` and `Modified:` timestamps
56
- (format `yyyy-LL-dd HH:mm`):
57
-
58
- ```
59
- ---
60
- Created: 2026-06-18 10:18
61
- Modified: 2026-06-18 10:18
62
- ---
63
- ```
64
-
65
- Every level 1 heading opens a new *artifact*, so usually each file
66
- carries exactly one. Both ATX headings (`# <text/>`, `## <text/>`, ...)
67
- and Setext headings (`<text/>` underlined with `===` or `---`) are
68
- supported.
69
-
70
- ### Object Model
71
-
72
- An artifact carries a tree of *objects*. Every object has a mandatory
73
- *kind* (e.g. `ENTITY`), a mandatory *name*, a unique anchor *id*
74
- (explicitly given or derived from the name), an optional *primary*
75
- marker, optional *properties* (key/value pairs), an optional
76
- *description* statement with an optional rationale, and optional *child*
77
- objects. Which kinds, properties, and nestings are allowed is defined by
78
- the schema configuration (see below); object kinds and property keys are
79
- case-sensitive and have to be written exactly as configured. Backquotes
80
- in names and property values are preserved as code markup for rendering,
81
- but are ignored when matching names, references, and constraints.
82
-
83
- Three concrete syntaxes exist:
84
-
85
- ### Complex Format
86
-
87
- Usually used on object hierarchy levels 1-3 (`#`, `##`, `###`). A
88
- heading opens the object, an optional unordered list carries its
89
- properties, and the remaining content up to the next heading is its
90
- description:
91
-
92
- ```
93
- # <kind/>: <name/> (<id/>)
94
-
95
- - <key/>: <value/>
96
- - [...]
97
-
98
- <statement/>, BECAUSE <rationale/>.
99
- ```
100
-
101
- The heading level directly reflects the nesting level: a `##` object
102
- becomes a child of the preceding `#` object, a `###` object a child of
103
- the preceding `##` object, etc. Skipping a level (a heading without a
104
- parent object on the level above) is an error.
105
-
106
- ### Concise Format
107
-
108
- Usually used on level 4 and deeper. A single unordered list item carries
109
- the entire object as `;`-separated segments -- the `<kind/>: <name/>`
110
- head, the `<key/>: <value/>` properties, and the trailing description --
111
- and may wrap over multiple (indented) lines:
112
-
113
- ```
114
- - <kind/>: <name/>; <key/>: <value/>; [...];
115
- <statement/>, BECAUSE <rationale/>.
116
- ```
117
-
118
- A list item is recognized as a Concise Format object (instead of a
119
- property of the enclosing object) by carrying at least one `;` on its
120
- first line. Every segment of the form `<key/>: <value/>` becomes a
121
- property (unless it contains a ` BECAUSE `), all remaining segments are
122
- joined into the description. Child objects nest as indented list items
123
- below their parent item, where key/value items become properties and
124
- concise items become child objects of that parent:
125
-
126
- ```
127
- - <kind/>: <name/>; <key/>: <value/>;
128
- <statement/>, BECAUSE <rationale/>.
129
- - <kind/>: <name/>; <key/>: <value/>;
130
- <statement/>, BECAUSE <rationale/>.
131
- ```
132
-
133
- ### Grouped Format
134
-
135
- A heading carrying just a *kind* and no `<kind/>: <name/>` pair opens a
136
- *grouping container* instead of an object. The list items below it are
137
- Concise Format items whose kind comes from that heading, so they start
138
- with the (optionally backquoted) name directly:
139
-
140
- ```
141
- ### <kinds/>
142
-
143
- - `<name/>`; <key/>: <value/>; [...];
144
- <statement/>, BECAUSE <rationale/>.
145
- ```
146
-
147
- The heading kind is singularized by stripping one trailing `S`, so both
148
- `### STATES` and `### STATE` group objects of kind `STATE`. The grouped
149
- objects become children of the object the heading is nested under. An
150
- unquoted name must not contain a `:` (else the item would look like a
151
- key/value pair) -- backquote it in this case.
152
-
153
- When **SpecBook** itself generates specification Markdown, it emits
154
- the Complex Format on levels 1-3 and the Concise Format from level 4
155
- upwards. When **SpecBook** edits existing files, it mirrors the format
156
- each existing object already uses.
157
-
158
- ### Names, Anchors, and Ids
159
-
160
- In all formats, the `<name/>` may carry trailing decorations, in any
161
- order:
162
-
163
- - `{{<id/>}}`: the explicit Wiki-style anchor, setting the object id
164
- (e.g. `## ENTITY: Attendee Browser {{attendee}}`).
165
-
166
- - `(*)`: the *primary* marker, flagging the object as primary (e.g.
167
- the primary attributes of an entity).
168
-
169
- - `(<token/>)`: a parenthesized token with three possible roles: on
170
- level 1 it becomes the artifact id (e.g. `# SPEC: Data Model (DM)`);
171
- on deeper levels it is either accepted as the value of a still
172
- missing configured property whose constraint it matches (e.g.
173
- `### SCENARIO: Successful Token Login (Main)` satisfying an
174
- `enum(Main,Alternative,Exceptional)` property), or else acts as the
175
- implicit anchor id.
176
-
177
- - `<a id="<id/>"></a>`: an HTML anchor at the very end of a heading,
178
- as an alternative to `{{<id/>}}` (emitted by **SpecBook** itself
179
- when exporting normalized Markdown).
180
-
181
- When no explicit id is given, the id is derived by slugifying the name
182
- (lowercased, with non-alphanumeric character runs dashed). An explicit
183
- `{{<id/>}}` anchor always takes precedence over a `(<token/>)` id. When
184
- the schema configures a fixed `id` for an object, it has to be
185
- explicitly written in the input, via either `{{<id/>}}` or `(<id/>)`.
186
-
187
- ### Properties
188
-
189
- In the Complex Format, each property is an unordered list item of the
190
- form `<key/>: <value/>`, whose value may continue on the following
191
- indented lines of the item (joined with spaces). In the Concise Format,
192
- each property is a `<key/>: <value/>` segment. A property key may carry
193
- a trailing parenthesized annotation (e.g. `WHEN (Context)`), which is
194
- kept for rendering but ignored when matching the key against the schema.
195
-
196
- A multi-token convenience exists for pattern-constrained properties:
197
- when a property value fails its (regex or enum) constraint as a whole,
198
- but consists of multiple whitespace-separated tokens of which one
199
- matches the property's own constraint, that token is kept as the value
200
- and the remaining tokens are distributed (case-insensitively) across the
201
- other still unset pattern-constrained properties of the object. Tokens
202
- assignable to no property are reported as errors.
203
-
204
- ### Descriptions and Rationales
205
-
206
- The description of a Complex Format object is all block content below
207
- its heading (up to the next heading) except the property list:
208
- paragraphs, blockquotes, ordered lists (e.g. scenario steps), and
209
- fenced code blocks. A fenced code block
210
- of language `gradia` is skipped, as it is the derived diagram which
211
- **SpecBook** itself emits into exported Markdown and which must not
212
- become authored content on a re-parse. In the Concise Format, the
213
- description is formed by the non-property segments of the item.
214
-
215
- A description is split into its *statement* and *rationale* at the first
216
- `, BECAUSE ` (or `, **BECAUSE** `) occurrence:
217
-
218
- ```
219
- The event is created and configured but not visible to attendees,
220
- BECAUSE an event needs a private setup phase.
221
- ```
222
-
223
- ### Wiki-Style References
224
-
225
- A `[[<reference/>]]` anywhere in a name, property value, description, or
226
- rationale is a Wiki-style reference to another object, which is checked
227
- for unique resolvability and rendered as a hyperlink in the HTML/PDF
228
- exports. A reference is a `.`-separated path of segments, where each
229
- segment matches a single object as:
230
-
231
- - `<id/>`: the object id or explicit anchor (e.g. `[[attendee]]`)
232
- - `<name/>`: the object name (e.g. `[[Attendee Browser]]`)
233
- - `<kind/>:<name-or-id/>`: kind-qualified (e.g. `[[ENTITY:Event]]`)
234
- - `<kind/>:*` or `*`: wildcards (for match sets, see below)
235
-
236
- Each part can be double-quoted to allow spaces, dots, and colons inside
237
- it (e.g. `[["Vue.js"]]`, whose dot would otherwise be taken as a path
238
- separator). A multi-segment path matches object chains connected by
239
- direct parent-to-child steps, where the leading segments up to the root
240
- may be omitted (e.g. `[[FV.relay]]` matches the object `relay` directly
241
- below the artifact with id `FV`).
242
-
243
- A reference has to resolve to exactly one object: a single-segment
244
- reference tries the variants (1) id/anchor, (2) name, and (3)
245
- `<kind/>:<name-or-id/>` in order, where the first variant yielding any
246
- matches decides; several matches are an ambiguity and zero matches an
247
- unresolvable reference, both reported by the linter. Wildcard references
248
- resolve into match *sets* and are used in the schema configuration to
249
- constrain reference-valued properties (e.g. `[[PERSONA:*]]` or
250
- `[[DM.ENTITY:*]]`).
251
-
252
- ### Image Embeddings
253
-
254
- A Markdown image `![<alt/>](<file/>)` inside a description or property
255
- value embeds a local image file, resolved relative to the artifact file:
256
- SVG files are inlined as-is; PNG/JPEG files are embedded as base64
257
- `data:` URLs. URLs and other file types are left untouched.
258
-
259
- ### Normalization
260
-
261
- The semantic phase validates the parsed objects against the schema
262
- configuration (unknown kinds and properties, missing required properties
263
- and child kinds, and violated value constraints are reported with
264
- file/line-precise diagnostics) and then normalizes the specification:
265
- artifacts, child objects, and properties are stably reordered along the
266
- schema definition, so the exports always present them in their
267
- configured canonical order.
268
-
269
- Schema Configuration
270
- --------------------
271
-
272
- The YAML schema configuration (see
273
- [`ase.specbook.yaml`](smp/ase.specbook.yaml) for a comprehensive
274
- example) defines which domain-specific objects are allowed: the artifact
275
- kinds with their `file` mapping on the first level, the object kinds of
276
- the deeper levels, and their properties with optional value constraints:
277
- regular expressions `/xxx/`, object references `[[xxx]]`, enumerations
278
- `enum(xxx,yyy)`, tag sets `tags(xxx,yyy)`, and lists `list(xxx[, ...])`
279
- of such alternatives. The `file` field is only allowed on the first
280
- (artifact) level.
281
-
282
- An object kind can additionally carry a `diagram` field, which derives a
283
- [Gradia](https://github.com/rse/gradia) diagram for every object of that
284
- kind. Its `type` selects the diagram shape (`graph`, `hub`, or `grid`),
285
- `nodes` and `edges` select the participating objects through
286
- comma-separated `[[xxx]]` reference patterns (`nodes` defaults to the
287
- object itself plus all objects below it), `center` names the object a
288
- `hub` is projected onto (default: `self`), `onlyConnected` drops the
289
- edge-less nodes of a `graph`, `collapse` (default: `true`) omits a
290
- degenerated diagram consisting of a single node only, `qualified` labels
291
- every node with its object kind, `properties` lists the property names
292
- whose values are attached to the nodes as key/value annotations (with
293
- every `[[xxx]]` reference stripped to its target object name), and
294
- `config` passes arbitrary Gradia rendering options (e.g.
295
- `grid-columns-max: 5`) through to the diagram.
296
-
297
- The edges are derived from the `[[xxx]]` references of the node objects
298
- -- from their property values only, or, with `links: all`, from their
299
- descriptions as well. As the *nesting* of the objects carries no such
300
- reference, `hierarchy: true` additionally derives a containment edge
301
- from every node object to each of its child objects which is part of the
302
- node set. This is what turns a parent object into the hub of its own
303
- children, as the `TIER` objects of the sample schema configuration
304
- demonstrate:
305
-
306
- ```yaml
307
- - kind: TIER
308
- diagram:
309
- type: hub
310
- center: self
311
- hierarchy: true
312
- ```
313
-
314
- A `grid` is edge-less by definition and hence accepts neither `edges`
315
- nor `hierarchy`.
316
-
317
- An object kind can furthermore carry a `format` field, which controls
318
- how the HTML/PDF export renders the child objects of every object of
319
- that kind. Its `type` selects the rendering: `complex` (nested
320
- sections), `concise` (compact per-kind tables), or the default `auto`,
321
- which collapses only the deepest level into tables. Below a `concise`
322
- object, unconfigured children implicitly stay `concise` and render as
323
- sub-tables inside the description cells, while an explicitly configured
324
- `type` is always honored, even a `complex` rendering pressed into a
325
- cell. `maxTableColumns` (default: `4`) bounds the columns of the compact
326
- tables below the object (wider groups chunk their properties into
327
- embedded per-object tables), and `withUnusedProps` (default: `false`)
328
- unconditionally renders the defined but unused properties of that kind,
329
- as empty property table lines or table columns. Objects collapsed into
330
- tables carry no headings and hence leave the table of contents and the
331
- PDF outline.
332
-
333
102
  Usage
334
103
  -----
335
104
 
336
105
  ### CLI
337
106
 
338
107
  ```
339
- $ specbook init [-v] [-c <yaml-file>] [-b <basedir>]
340
- $ specbook lint [-v] [-c <yaml-file>] [-b <basedir>]
341
- $ specbook export [-v] [-c <yaml-file>] [-b <basedir>] [-o [<format>:]<output-file>] [...]
342
- $ specbook describe [-v] [-c <yaml-file>] [-o <markdown-file>]
343
- $ specbook import [-v] [-c <yaml-file>] [-b <basedir>] <input-files...>
344
- $ specbook edit [-v] [-c <yaml-file>] [-b <basedir>] <query>
108
+ $ specbook init [-v] -c <yaml-file> [-b <basedir>]
109
+ $ specbook lint [-v] -c <yaml-file> [-b <basedir>]
110
+ $ specbook export [-v] -c <yaml-file> [-b <basedir>] [-o [<format>:]<output-file>] [...]
111
+ $ specbook describe [-v] [-c <yaml-file>] [-b <basedir>] [-e] [-o <markdown-file>]
345
112
  $ specbook mcp [-v]
346
113
  ```
347
114
 
348
- The base directory `-b`/`--basedir` (default: `.`) is scanned
349
- recursively for the specification Markdown files, and generated
115
+ The YAML schema configuration `-c`/`--config` is mandatory for `init`,
116
+ `lint`, and `export`, as it determines the specification: exactly the
117
+ artifact files its `file` fields reference are loaded and parsed, all
118
+ other Markdown files below the base directory are ignored. A referenced
119
+ file which is absent is reported, unless all of its artifacts are
120
+ `optional`, and so is an artifact absent from its present file, unless
121
+ it is `optional` itself. Both `lint` and `export` report all
122
+ diagnostics and fail on any of them, so a partial or invalid
123
+ specification is never exported.
124
+
125
+ The base directory `-b`/`--basedir` (default: `.`) is the directory the
126
+ referenced artifact files are resolved against, and generated
350
127
  specification Markdown files are placed inside it, too.
351
128
 
352
129
  The export output option `-o`/`--output` (default: `-` for stdout) can
@@ -355,41 +132,44 @@ occur multiple times. The format (`json`, `json5`, `yaml`, `toon`,
355
132
  it is explicitly given as a `<format>:` prefix, and plain `-` (stdout)
356
133
  defaults to JSON.
357
134
 
135
+ The `describe` command outputs the description of the SpecBook models
136
+ and formats. If the configuration file `-c`/`--config` or the base
137
+ directory `-b`/`--basedir` is given, it additionally appends a *SpecBook
138
+ Project Instantiation* section which points to these artifacts of the
139
+ particular project. With `-e`/`--embed` the YAML schema configuration is
140
+ embedded verbatim instead of just being referenced, so the resulting
141
+ document describes the specification format of the project entirely on
142
+ its own.
143
+
358
144
  The default value of every CLI option `--xxx` can be overridden by a
359
145
  corresponding `SPECBOOK_XXX` environment variable (e.g.
360
146
  `SPECBOOK_BASEDIR`, `SPECBOOK_CONFIG`, `SPECBOOK_OUTPUT`,
361
- `SPECBOOK_VERBOSE`), while an explicitly supplied option always wins.
147
+ `SPECBOOK_VERBOSE`), while an explicitly supplied option always wins. A
148
+ `SPECBOOK_CONFIG` value also satisfies the otherwise mandatory
149
+ `-c`/`--config` option.
362
150
 
363
151
  ### API
364
152
 
365
153
  ```ts
366
- import { SpecBook } from "@rse/specbook"
154
+ import { SpecBook, renderVerbose } from "@rse/specbook"
367
155
 
368
- const specbook = new SpecBook({ verbose: (msg) => console.error(msg) })
369
- const result = await specbook.lint({ config: "smp/ase.specbook.yaml", basedir: "smp/broadcast" })
156
+ const specbook = new SpecBook({
157
+ verbose: (cmd, msg) => console.error(`specbook: ${cmd}: ${renderVerbose(msg)}`)
158
+ })
159
+ const result = await specbook.lint({
160
+ config: "smp/ase.specbook.yaml",
161
+ basedir: "smp/broadcast"
162
+ })
370
163
  ```
371
164
 
372
165
  ### MCP
373
166
 
374
- Run `specbook mcp` to serve the tools `specbook_init`,
375
- `specbook_lint`, `specbook_export`, `specbook_describe`,
376
- `specbook_import`, and `specbook_edit` over stdio.
377
-
378
- ### AI Configuration
379
-
380
- The commands `import` and `edit` use an LLM. The environment variables
381
- `SPECBOOK_AI_PROVIDER` (`anthropic`, `openai`, `openrouter`, or
382
- `ollama`) and
383
- `SPECBOOK_AI_MODEL` provide the defaults, which the CLI options
384
- `--provider`/`--model` (respectively the MCP/API parameters `provider`/
385
- `model`) override. The provider API keys come from the standard
386
- environment variables (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`,
387
- `OPENROUTER_API_KEY`), while `ollama` needs no key and uses the local
388
- Ollama service.
167
+ Run `specbook mcp` to serve the tools `specbook_init`, `specbook_lint`,
168
+ `specbook_export`, and `specbook_describe` over stdio.
389
169
 
390
170
  License
391
171
  -------
392
172
 
393
- Copyright &copy; 2026 Dr. Ralf S. Engelschall (http://engelschall.com/)<br/>
394
- Licensed under Apache 2.0 (https://spdx.org/licenses/Apache-2.0)
173
+ Copyright &copy; 2026 [Dr. Ralf S. Engelschall](http://engelschall.com/)<br/>
174
+ Licensed under [Apache 2.0](https://spdx.org/licenses/Apache-2.0)
395
175
 
@@ -1,47 +1,40 @@
1
1
  import { renderDiagnostic, renderDiagnosticVerbose, type Diagnostic } from "./specbook-diagnostic.js";
2
2
  import { type LintResult } from "./specbook-cmd-lint.js";
3
3
  import { parseOutputSpec, formats, type ExportFormat } from "./specbook-cmd-export.js";
4
+ import { literal, renderVerbose } from "./specbook-verbose.js";
5
+ export { literal, renderVerbose };
4
6
  export { formats, parseOutputSpec, type ExportFormat };
5
7
  export { renderDiagnostic, renderDiagnosticVerbose, type Diagnostic };
6
8
  export { type LintResult };
7
- export type { Specification, Artifact, Object, Description, Property } from "./specbook-struct-spec.js";
8
- export type { SchemaSpecification, SchemaObject, SchemaProperty } from "./specbook-struct-schema.js";
9
+ export type { Spec, SpecArtifact, SpecObject, SpecDescription, SpecProperty } from "./specbook-format-spec.js";
10
+ export type { Schema, SchemaObject, SchemaProperty } from "./specbook-format-schema.js";
9
11
  export declare const version: string;
12
+ export type VerboseSink = (cmd: string, msg: string) => void;
10
13
  export interface SpecBookOptions {
11
- verbose?: (msg: string) => void;
14
+ verbose?: VerboseSink;
12
15
  }
13
16
  export declare class SpecBook {
14
17
  private verbose;
15
18
  constructor(options?: SpecBookOptions);
19
+ private verboseOf;
20
+ private requireConfigFile;
16
21
  private requireConfig;
17
22
  init(options: {
18
- config?: string;
23
+ config: string;
19
24
  basedir?: string;
20
25
  }): Promise<string[]>;
21
26
  lint(options: {
22
- config?: string;
27
+ config: string;
23
28
  basedir?: string;
24
29
  }): Promise<LintResult>;
25
30
  export(options: {
26
- config?: string;
31
+ config: string;
27
32
  basedir?: string;
28
33
  formats?: ExportFormat[];
29
34
  }): Promise<Buffer[]>;
30
35
  describe(options: {
31
36
  config?: string;
32
- }): Promise<string>;
33
- import(options: {
34
- config?: string;
35
37
  basedir?: string;
36
- inputs: string[];
37
- provider?: string;
38
- model?: string;
39
- }): Promise<string[]>;
40
- edit(options: {
41
- config?: string;
42
- basedir?: string;
43
- query: string;
44
- provider?: string;
45
- model?: string;
46
- }): Promise<string[]>;
38
+ embed?: boolean;
39
+ }): Promise<string>;
47
40
  }