@orkestrel/scaffold 0.0.64 → 0.0.65

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 (26) hide show
  1. package/README.md +11 -1
  2. package/dist/host/agents/skills/enterprise-bootstrap/SKILL.md +184 -177
  3. package/dist/host/agents/skills/enterprise-bootstrap/references/bootstrap-reference.md +299 -76
  4. package/dist/host/agents/skills/enterprise-bootstrap/references/color-modes.md +241 -0
  5. package/dist/host/agents/skills/enterprise-bootstrap/references/components.md +83 -36
  6. package/dist/host/agents/skills/enterprise-bootstrap/references/frontend-design.md +297 -98
  7. package/dist/host/agents/skills/enterprise-bootstrap/references/inputs.md +25 -14
  8. package/dist/host/agents/skills/enterprise-bootstrap/references/inspection.md +216 -128
  9. package/dist/host/agents/skills/enterprise-bootstrap/references/responsive-layout.md +187 -0
  10. package/dist/host/agents/skills/enterprise-bootstrap/references/utilities.md +105 -16
  11. package/dist/host/claude/rules/workspace.md +2 -2
  12. package/dist/host/claude/settings.json +1 -1
  13. package/dist/host/claude/skills/enterprise-bootstrap/SKILL.md +10 -9
  14. package/dist/host/guides/scaffold.md +63 -22
  15. package/dist/host/manifest.json +25 -13
  16. package/dist/host/scripts/codex.sh +0 -0
  17. package/dist/host/scripts/cursor.sh +0 -0
  18. package/dist/host/scripts/deps.sh +0 -0
  19. package/dist/host/scripts/ollama.sh +322 -13
  20. package/dist/src/core/index.cjs +33 -12
  21. package/dist/src/core/index.cjs.map +1 -1
  22. package/dist/src/core/index.d.cts +31 -9
  23. package/dist/src/core/index.d.ts +31 -9
  24. package/dist/src/core/index.js +32 -13
  25. package/dist/src/core/index.js.map +1 -1
  26. package/package.json +4 -4
@@ -24,7 +24,7 @@
24
24
  .bg-opacity-10, .bg-opacity-25, .bg-opacity-50, .bg-opacity-75, .bg-opacity-100
25
25
  ```
26
26
 
27
- Prefer `bg-body-*` and `*-subtle` over `bg-white`/`bg-light` — they track `data-bs-theme` so dark mode works without extra rules.
27
+ Prefer `bg-body`, `bg-body-secondary`, `bg-body-tertiary`, and `bg-*-subtle` for quiet surfaces; inherit text without an added foreground class. Treat original contextual `bg-*`, including `bg-light` and `bg-dark`, as non-adaptive in stock 5.3. Take ownership and exceptions from [color-modes.md](color-modes.md).
28
28
 
29
29
  ### Borders
30
30
 
@@ -39,7 +39,11 @@ Prefer `bg-body-*` and `*-subtle` over `bg-white`/`bg-light` — they track `dat
39
39
  .rounded-0, .rounded-1, .rounded-2, .rounded-3, .rounded-4, .rounded-5
40
40
  ```
41
41
 
42
- For borders that must stay visible in both color modes, prefer the `border-*-subtle` classes (theme-adaptive) over raw color borders.
42
+ Use adaptive border roles for quiet separation. Measure boundaries needed to identify a control or state; `border-*-subtle` adapts but does not automatically meet the contrast bar.
43
+
44
+ - **`border-{1..5}` sets `border-width` on every side.** On a component that already has a border (`.card`, `.alert`) it thickens the whole box. For a one-side accent, zero first, restore one side, then widen — `card border-0 border-top border-4 border-primary` — utility source order (`border` → `border-{side}` → `border-width`) makes it hold, and the cleared sides have no border style so their width never paints.
45
+ - Strengthen a rule that reads too faint with `border-2` on its soft color, not with a darker color; heavier width keeps the softness.
46
+ - `border-{color}` is the fixed brand color in both modes; check an accent against a dark `bg-*-subtle` before shipping it.
43
47
 
44
48
  ### Colors (Text)
45
49
 
@@ -48,10 +52,13 @@ For borders that must stay visible in both color modes, prefer the `border-*-sub
48
52
  .text-body, .text-body-secondary, .text-body-tertiary, .text-body-emphasis
49
53
  .text-primary-emphasis, .text-secondary-emphasis, .text-success-emphasis, .text-danger-emphasis, .text-warning-emphasis, .text-info-emphasis, .text-light-emphasis, .text-dark-emphasis
50
54
  .text-black, .text-white, .text-black-50, .text-white-50
51
- .text-muted /* DEPRECATED in 5.3 — use .text-body-secondary; removed in v6 */
55
+ .text-muted /* Deprecated in 5.3; use a deliberate .text-body-secondary role instead. */
56
+ .text-reset /* Restore inherited color; not the same as .text-body. */
52
57
  .text-opacity-25, .text-opacity-50, .text-opacity-75, .text-opacity-100
53
58
  ```
54
59
 
60
+ Default ordinary text to inheritance. Original contextual `text-*` colors do not adapt in stock 5.3; body-role and `text-*-emphasis` colors do. `text-body-secondary` (body color at .75 alpha) clears 4.5:1 on every stock body surface in both modes; `text-body-tertiary` (.5 alpha) measures 3.0–4.1:1 and is decoration or disabled only. Neither, nor `text-white-50`, is a quiet tier on a colored fill — take the same-hue token from [color-modes.md](color-modes.md) → Text tiers. Do not add emphasis text automatically to subtle fills, and do not replace a component's native foreground without inspecting its state contract.
61
+
55
62
  ### Display
56
63
 
57
64
  ```css
@@ -120,6 +127,8 @@ For borders that must stay visible in both color modes, prefer the `border-*-sub
120
127
  .link-offset-1, .link-offset-2, .link-offset-3
121
128
  ```
122
129
 
130
+ Keep normal links on Bootstrap's link rules inside prose. Where most things are links — navigation, lists, tables — use `link-body-emphasis link-underline-opacity-0 link-underline-opacity-100-hover link-offset-2`: body tone, underline on hover and focus, and the one colored-link helper that adapts to dark mode; add `fw-semibold` where the link is the row's identity. For a brand underline that completes on hover: `link-underline-primary link-underline-opacity-50 link-underline-opacity-100-hover link-offset-2`. Do not replace hover/focus rules with a text-color utility.
131
+
123
132
  ### Object Fit
124
133
 
125
134
  ```css
@@ -133,6 +142,8 @@ For borders that must stay visible in both color modes, prefer the `border-*-sub
133
142
  .opacity-0, .opacity-25, .opacity-50, .opacity-75, .opacity-100
134
143
  ```
135
144
 
145
+ Opacity is not a text tier: it reads as disabled and lets the surface show through the glyphs. Do not use whole-element opacity to quiet a region containing readable text. Color-opacity utilities affect only rules that consume their variable; stock subtle backgrounds do not consume `--bs-bg-opacity`. Measure the composited result rather than assuming a tint.
146
+
136
147
  ### Overflow
137
148
 
138
149
  ```css
@@ -160,6 +171,8 @@ For borders that must stay visible in both color modes, prefer the `border-*-sub
160
171
  .shadow-none, .shadow-sm, .shadow, .shadow-lg
161
172
  ```
162
173
 
174
+ Three elevation steps: `shadow-sm` (`0 .125rem .25rem` at .075) for slightly raised cards and controls, `shadow` (`0 .5rem 1rem` at .15) for floating menus and a dragged item, `shadow-lg` (`0 1rem 3rem` at .175) for dialogs. Stock dropdowns, popovers, toasts, and modals all sit on `--bs-box-shadow`; lift a modal to the top step through `--bs-modal-box-shadow` ([bootstrap-reference.md](bootstrap-reference.md) → Elevation and depth). No shadow is a valid role.
175
+
163
176
  ### Sizing
164
177
 
165
178
  Bootstrap ships exactly these — nothing else (no `.vw-25`, `.vh-50`, `.mw-auto`, or `.min-vh-75`; add missing steps through the utilities API if a project truly needs them — see [bootstrap-reference.md](bootstrap-reference.md)):
@@ -222,14 +235,16 @@ Notes: `s`/`e` are logical start/end — they flip automatically under RTL; neve
222
235
  /* Size */
223
236
  .fs-1, .fs-2, .fs-3, .fs-4, .fs-5, .fs-6
224
237
 
225
- /* Truncate — needs display block/inline-block or a flex child with min-width 0 */
238
+ /* Truncate — needs a constrained inline width and block/inline-block layout */
226
239
  .text-truncate
227
240
  ```
228
241
 
242
+ `fs-6…1` = 1 · 1.25 · 1.5 · 1.75 · 2 · 2.5 rem (16–40 px at the default root); `display-6…1` = 2.5–5 rem. Values above 1.25 rem scale down fluidly below a 1200 px viewport under RFS; `fs-5`, `fs-6`, `.lead`, and controls do not. There is no `rem` step below 1 rem: `.small` and `<small>` are `.875em`, so use one level only — `.small` inside `.small` is 12.25 px, off every scale — and take a 14 px or 12 px role from the generated `fs-sm`/`fs-xs` ([bootstrap-reference.md](bootstrap-reference.md) → Layout and type extensions). Stock 5.3 ships no letter-spacing utility; generate `ls-tight`/`ls-wide` there for display text and `text-uppercase` labels. `fw-light`/`fw-lighter` (300) belong only at display size; `.lead` and `display-*` ship at 300 by design.
243
+
229
244
  The composition traps in this group:
230
245
 
231
246
  - **`fs-*` without `lh-1` grows the row.** A resized glyph or mark keeps the parent's line-height, so the line box stretches and the row sits taller than its neighbors. Pair `fs-*` with `lh-1` on anything that is a mark rather than a paragraph.
232
- - **`text-truncate` zeroes a flex item's automatic minimum size** (that's the `min-width: 0` it carries). Inside a flex _column_, that also removes the floor that kept a heading at its own height: a growing sibling then squeezes the title from the bottom until it clips. Floor the title with `flex-shrink-0` and let the growing sibling absorb the change.
247
+ - **`text-truncate` is not a minimum-size utility.** It sets hidden overflow, ellipsis, and no wrapping; it does not declare `min-width: 0`. Give the truncating element a constrained width and make its flex ancestry shrink where required. In a constrained column, protect a title from height loss with `flex-shrink-0`. Take any missing inline-size utility from the project's generated scale, never an invented `.min-w-0`.
233
248
 
234
249
  ### Vertical Align
235
250
 
@@ -261,6 +276,17 @@ The composition traps in this group:
261
276
  | `5` | $spacer \* 3 (3rem = 48px) |
262
277
  | `auto` | auto |
263
278
 
279
+ Use the installed scale as the first choice. Assign its steps to internal, group, panel, and section
280
+ gaps; keep inter-group gaps larger than internal gaps. Compare adjacent steps before adding one.
281
+ The displayed pixel equivalents assume the default root size; they are not fixed pixel constraints.
282
+
283
+ The shipped jumps are +100 / +100 / +50 / +100 %: coarse above 16 px, with no 12 px or 32 px
284
+ step and nothing above 48 px for section rhythm. A missing step is not permission to type `p-2.5`
285
+ or `p-6`; those resolve to no rule and fail silently. Add a named step through
286
+ [bootstrap-reference.md](bootstrap-reference.md) → Layout and type extensions and verify the
287
+ generated class in the shipped build. Take type, width, and spacing decisions from
288
+ [frontend-design.md](frontend-design.md).
289
+
264
290
  ## Z-index Scale (components)
265
291
 
266
292
  | Component | Z-index |
@@ -299,14 +325,77 @@ Helpers are single-purpose classes that sit alongside utilities.
299
325
 
300
326
  ### Composition habits
301
327
 
302
- - **Spacing scale:** prefer `gap-*` on flex/grid parents over scattering `m-*` on every child — the parent owns rhythm, children stay reorderable. Use `p-3` / `p-4` for panel padding; reserve `p-5` for sparse marketing-like empty states.
303
- - **Body surfaces:** `bg-body`, `bg-body-secondary`, `bg-body-tertiary` track `data-bs-theme` — raw `bg-white` / `bg-light` freeze the surface in light mode.
304
- - **Text hierarchy:** `text-body` for content, `text-body-secondary` for meta, `text-*-emphasis` for any status a reader acts on. The plain `text-success` / `text-danger` / `text-warning` colors and `text-body-tertiary` are the decoration tier ([SKILL.md](../SKILL.md) → Surfaces, color, contrast).
305
- - **Opacity traps:** `text-white-50` / `text-black-50` often fail contrast — prefer `text-opacity-75` on a known solid, or `text-body-secondary`. Every one of these pairings is measured against the shipped cascade in both themes; a skin retunes the same token names.
306
- - **Flex floors:** a flex column gives its items an automatic minimum size, and `text-truncate` removes it. Titles and marks that must keep their height carry `flex-shrink-0`; only the growing sibling absorbs the slack.
307
- - **Flex toolbars:** `d-flex align-items-center gap-2 flex-wrap` (or `flex-nowrap overflow-auto` for dense bars). Equal-height siblings: `align-items-stretch` + `h-100` on cards.
308
- - **Responsive hide:** show the best layout per breakpoint (`d-none d-md-block` vs `d-md-none`) rather than cramming one layout everywhere. Below `sm`, hide button captions (`d-none d-sm-inline` on the label span, `aria-label` on the control so the accessible name stays) before you let the brand or page title truncate.
309
- - **RTL safety:** always `ms-*`/`me-*`/`ps-*`/`pe-*`, `text-start`/`text-end`, `float-start`/`float-end` — the logical model is what lets one build serve LTR and RTL.
310
- - **Density as a system:** when a screen offers compact/comfortable density, drive it from a token or wrapper class that swaps padding — not ad-hoc `-sm` sprinkling per element ([bootstrap-reference.md](bootstrap-reference.md) → Design tokens).
311
- - **Shadows:** `shadow-sm` for panels in product UI; `shadow-lg` rarely belongs in dense admin screens.
312
- - **Print:** mark chrome `d-print-none`; keep the data table/results printable.
328
+ - **Spacing:** let the parent own rhythm with `gap-*`; use margins where the relationship requires
329
+ them. Choose panel padding from the shared scale, not a separate value per card. Keep labels,
330
+ controls, help, and errors closer together than neighboring groups: `.form-label` ships `.5rem`
331
+ below, so field groups take `mb-3` or `row g-3`. Headings ship `margin-bottom: .5rem` and no top
332
+ margin, so a section heading after a paragraph attaches to the wrong block — add `mt-4`/`mt-5`
333
+ or let a `vstack gap-4` parent own the rhythm. In a row, `hstack gap-2` inside a group and
334
+ `gap-4` between groups. Start a gap one step too large and step down.
335
+ - **Hierarchy:** use `fw-normal` for reading and `fw-semibold`/`fw-bold` for emphasis; headings
336
+ ship at 500, barely a step above body on a system stack, so pair a smaller heading class with
337
+ `fw-semibold` (`<h2 class="h5 fw-semibold">`) rather than a large heading at 500. Never
338
+ `fw-light` on UI text. Start ordinary text and quiet status with inheritance; add
339
+ `text-body-secondary` as the one quiet tier. Do not make metadata tiny or translucent to quiet
340
+ it. Quiet a heavy icon beside a label with `text-body-secondary` on the icon, not a larger label.
341
+ Quiet an active nav item's competitors (inherited text, normal weight) before making the active
342
+ item louder.
343
+ - **Type:** `fs-*` changes size, not semantic heading level. Choose `lh-*` by the text's role;
344
+ `lh-1` suits a glyph or suitable display treatment, not every paragraph. Keep prose start-aligned
345
+ and bound its measure independently of wider content.
346
+ - **Baseline:** use `align-items-baseline` for mixed-size text on one row. Keep `align-items-center`
347
+ for controls or icon/text combinations where the boxes, rather than text baselines, need to align.
348
+ - **Body surfaces:** `bg-body`, `bg-body-secondary`, and `bg-body-tertiary` track `data-bs-theme`.
349
+ Keep ordinary text inherited on those surfaces; use an explicit pair only at an owned boundary.
350
+ Take exceptions from [color-modes.md](color-modes.md).
351
+ - **Opacity:** do not use `text-white-50`, `text-black-50`, or `text-opacity-*` as the default secondary
352
+ tier. On colored fills, inherit the tested foreground or use a scoped opaque token. Any opacity
353
+ changes the composited contrast, including opacity on an ancestor.
354
+ - **Width:** use `w-100` inside a content-led maximum width, not `w-50` merely to avoid a wide form.
355
+ Stock Bootstrap has no prose-measure, fixed-rail, or zero-inline-minimum utility. Generate needed
356
+ roles through [bootstrap-reference.md](bootstrap-reference.md) → Layout and type extensions.
357
+ - **Flex floors:** allow a flexible main region to shrink without clipping its essential content.
358
+ Protect titles or marks that must retain height with `flex-shrink-0`. Do not add `overflow-hidden`
359
+ to an ancestor to conceal a layout bug; it can clip menus and focus rings.
360
+ - **Toolbars:** start with `d-grid gap-2` or labelled `row g-2` controls; expand with `d-sm-flex
361
+ flex-sm-wrap` or `col-md-auto` only when the container fits. Do not default to a horizontal
362
+ scroller for search or primary actions. Keep matching control sizes and usable hit areas. Align equal-height
363
+ cards only where their content benefits, not to fill empty space.
364
+ - **Responsive content:** follow [responsive-layout.md](responsive-layout.md); unprefixed utilities define the complete narrow task. A class that resolves can still implement the wrong layout. Reflow and prioritize before truncating. Hide a button caption only when
365
+ its remaining icon is recognizable and its accessible name remains complete; unfamiliar or
366
+ consequential actions keep visible labels. Do not erase task information to save the brand's width.
367
+ - **Links:** use persistent underlines for inline prose links. In conventional navigation, quieter
368
+ color and weight can carry hierarchy; retain visible hover and focus. Never rely on hover alone
369
+ for discovery. An action remains a button even when styled with `btn-link`.
370
+ - **RTL:** use `ms-*`/`me-*`/`ps-*`/`pe-*`, `text-start`/`text-end`, and logical custom properties;
371
+ verify the matching RTL build and the content's writing direction.
372
+ - **Density:** drive compact/comfortable variants from shared tokens or a wrapper, not scattered
373
+ per-element tweaks. Dense data retains readable text and ≥24px control targets.
374
+ - **Boundaries and depth:** separate with spacing first, then a surface change, then a shadow, then
375
+ a line: `bg-body-tertiary` panels instead of bordered ones; `card border-0 shadow-sm` on a page
376
+ surface that differs from the card; `list-group-flush`, `accordion-flush`, `table-borderless`,
377
+ `border-0` on a `card-header`; `gap-4` instead of an `<hr>`. Remove a border where a distinct
378
+ background already separates. Use `border-0` or `shadow-none` only when grouping and control
379
+ recognition survive. Assign `shadow-sm`, `shadow`, and `shadow-lg` by layer role; do not shadow
380
+ every panel or replace the focus indicator with depth. A `bg-body` panel on `bg-body-tertiary`
381
+ reads raised and `bg-body-secondary` inside `bg-body` reads inset — depth with no shadow, in
382
+ both modes.
383
+ - **Accents and decoration:** one accent border per region (see [Borders](#borders)); the shipped
384
+ `nav-underline` is the active-item accent. Alternate `bg-body` and `bg-body-tertiary` sections
385
+ before decorating; a `bg-primary-subtle` band emphasizes one panel. `bg-gradient` is a
386
+ white-to-transparent fade over the current fill, not a hero gradient.
387
+ - **Overlap:** `position-relative translate-middle-y` for a card that straddles two surfaces;
388
+ `mt-n*` only after `$enable-negative-margins`. Ring an overlapping avatar in the body color
389
+ with `rounded-circle border border-3` plus the `ring-body` class from
390
+ [bootstrap-reference.md](bootstrap-reference.md) → Elevation and depth, never `border-white`.
391
+ - **Images:** combine a declared frame or ratio with `object-fit-cover` only when cropping is safe;
392
+ take `object-fit-contain` when the whole asset matters. Guard a user upload against bleeding into
393
+ a same-color surface with `border border-black border-opacity-10` — translucent, so it does not
394
+ clash with the photo. Reduce a photo's dynamics before placing text on it: a `bg-dark
395
+ bg-opacity-50` (or `-75`) overlay layer under `card-img-overlay`, measured at every crop. Keep a
396
+ small glyph near 16–24 px inside `rounded-circle bg-primary-subtle p-3` rather than scaling it up.
397
+ Keep useful image detail and icon optical size rather than stretching assets to fill a box.
398
+ - **Lists and quotes:** `list-unstyled` with a meaningful glyph per item (`d-flex gap-2
399
+ align-items-baseline`, glyph `aria-hidden="true"`); `.blockquote` with `.blockquote-footer`.
400
+ - **Print:** mark chrome `d-print-none` and keep results readable; do not hide data merely because
401
+ its interactive controls have no print role.
@@ -166,8 +166,8 @@ the `test:bench` script joins no chain, so no gate runs either mode; the project
166
166
  ignored by git; and `.claude/rules/tests.md` governs what may live there.
167
167
 
168
168
  - Define a cross-cutting project only for a proof the package actually has.
169
- - A live-service project is the `service` project in the preceding table, `scripts/service.sh`
170
- provisions what it drives, and `.claude/rules/tests.md` governs it. Name it `service` whatever it
169
+ - Prepare the external service before invoking the `service` project. Use `tests/setupService.ts`
170
+ to verify readiness, apply `.claude/rules/tests.md`, and name the project `service` whatever it
171
171
  drives.
172
172
  - In a publishing workspace, a project leaves the default run when it drives a live external
173
173
  service or is hermetic but slow — it spawns processes, packs, installs, or drives a real build.
@@ -977,7 +977,7 @@
977
977
  },
978
978
  {
979
979
  "type": "command",
980
- "command": "\"$CLAUDE_PROJECT_DIR\"/scripts/ollama.sh",
980
+ "command": "if [ \"${CLAUDE_CODE_REMOTE:-}\" = \"true\" ]; then \"$CLAUDE_PROJECT_DIR\"/scripts/ollama.sh; fi",
981
981
  "timeout": 600
982
982
  },
983
983
  {
@@ -1,19 +1,20 @@
1
1
  ---
2
2
  name: enterprise-bootstrap
3
3
  description: >-
4
- Design and build distinctive, production-grade user interfaces with Bootstrap
5
- 5.3 and intentional frontend craft, in any host project and on any stack. Use
6
- for Bootstrap user-interface work — creating, restyling, or
4
+ Design and build distinctive, production-grade UI with Bootstrap 5.3 on any
5
+ stack. Use for any Bootstrap interface work — creating, restyling, or
7
6
  extending pages, screens, components, layouts, app shells, dashboards, admin
8
7
  panels, SaaS tools, data tables, filter bars, forms, wizards, navigation,
9
8
  modals, empty/loading/error states, dark mode, marketing surfaces — whenever
10
9
  the task touches HTML/CSS/visual design, mentions Bootstrap or its components,
11
- or must look professional and avoid templated defaults. Covers aesthetics,
12
- typography, color modes, design tokens, accessibility (WCAG 2.2 AA),
13
- responsive layout, and enterprise app patterns. The `orkestrel-polish-surface`
14
- skill owns a requested verdict, round, or campaign over a surface that already
15
- renders, including a review that changes nothing. In that campaign's fix
16
- units, use this skill for Bootstrap craft.
10
+ asks for visual hierarchy, polish, a design system, or spacing/type/color
11
+ scales, or must look professional rather than like stock Bootstrap. Covers
12
+ aesthetics, typography, color modes, design tokens, elevation, finishing
13
+ details, accessibility (WCAG 2.2 AA), responsive layout, and enterprise app
14
+ patterns. The `orkestrel-polish-surface` skill owns a requested verdict,
15
+ round, or campaign over a surface that already renders, including a review
16
+ that changes nothing; in that campaign's fix units, use this skill for
17
+ Bootstrap craft.
17
18
  ---
18
19
 
19
20
  # Load the canonical workflow
@@ -33,7 +33,7 @@ print. Limits states what that leaves unproven and what covers it instead.
33
33
  npm install --save-dev @orkestrel/scaffold
34
34
  ```
35
35
 
36
- The executable needs Node 22.12 or later. Run it through `npx` without installing:
36
+ The executable needs Node 22.18.0 or later. Run it through `npx` without installing:
37
37
 
38
38
  ```sh
39
39
  npx @orkestrel/scaffold --help
@@ -149,13 +149,14 @@ Exported from `@orkestrel/scaffold`, and reachable from
149
149
  | `MAX_TOTAL_ARTIFACT_BYTES` | const | Caps the bytes retained across one whole plan or audit. |
150
150
  | `MAX_TOTAL_REGISTRY_BYTES` | const | Caps the decoded bytes accepted across one registry-reading call. |
151
151
  | `MINIMUM_NODE_VERSION` | const | Names the oldest Node version the generated toolchain supports. |
152
+ | `MINIMUM_NPM_VERSION` | const | Names the oldest npm version the generated toolchain supports. |
152
153
  | `NAME_PATTERN` | const | Matches the bare workspace name syntax: lowercase alphanumeric with hyphens, letter first. |
153
154
  | `ORCHESTRATION_PATH_NAMES` | const | Lists the exact root paths that wire an agent bench or own an orchestration directory, frozen. |
154
155
  | `ORCHESTRATION_PATH_PREFIXES` | const | Lists the path prefixes whose contents instruct or wire an agent, frozen. |
155
156
  | `ORKESTREL_RANGE_PATTERN` | const | Matches the exact caret-pinned pre-1.0 range accepted for an `@orkestrel/*` runtime dependency. |
156
157
  | `PRINT_WIDTH` | const | Caps the columns one emitted line may occupy, matching `printWidth` in `.oxfmtrc.json`. |
157
158
  | `RELEASE_PROOF_COMMAND` | const | Names the `prepublishOnly` row that runs the packed-package proof against a real registry. |
158
- | `SERVICE_SCRIPT_PATH` | const | Names the provisioner skeleton a workspace with declared service vendors is given once. |
159
+ | `SERVICE_SCRIPT_PATH` | const | Names the inventory skeleton a workspace with declared service vendors is given once. |
159
160
  | `SERVICE_SETUP_PATH` | const | Names the live-service readiness module whose presence makes a workspace `service`. |
160
161
  | `SERVICE_TEST_INCLUDE` | const | Names the include the live-service project covers, which is a directory rather than one proof. |
161
162
  | `SHOWCASE_CONFIG_PATH` | const | Names the Vite wrapper whose presence makes a workspace `showcase`. |
@@ -164,6 +165,7 @@ Exported from `@orkestrel/scaffold`, and reachable from
164
165
  | `SRC_MATRIX` | const | Holds the build and export settings each published `src` environment contributes, frozen. |
165
166
  | `TAB_WIDTH` | const | Sets the columns one tab occupies when the formatter measures a line, matching `tabWidth`. |
166
167
  | `VERSION_PATTERN` | const | Matches the exact `major.minor.patch` version syntax a blueprint declares. |
168
+ | `WORKSPACE_DEV_ENGINES` | const | Holds the `devEngines` record every generated manifest carries. |
167
169
  | `WORKSPACE_OWNED_PATHS` | const | Lists the vendored paths whose present bytes belong to each workspace, frozen. |
168
170
 
169
171
  #### Guards
@@ -565,9 +567,10 @@ other structural facts do not need creation flags. Add a root `tests/setup*.test
565
567
  `setup`, `tests/guides.test.ts` for `guides`, `tests/integration.test.ts` for `integration`,
566
568
  `tests/conformance.test.ts` for `conformance`, `tests/setupService.ts` for `service`,
567
569
  `tests/setupGlobal.ts` for `global`, and `configs/app/vite.showcase.config.ts` for `showcase`;
568
- reading verbs detect each exact-case file and register its fixed machinery. Add `scripts/service.sh`
569
- for `vendors`. Reading verbs preserve and protect that birth-owned script, but do not infer its
570
- vendor list from edited text.
570
+ reading verbs detect each exact-case file and register its fixed machinery. An explicitly supplied
571
+ plan with `vendors` owns and protects the birth-owned `scripts/service.sh` inventory skeleton.
572
+ Reading verbs do not infer its vendor list from edited text and cannot preserve an arbitrary present
573
+ script on that basis.
571
574
 
572
575
  `distribution` is not on that list. Publishing at least one `src` environment is its whole
573
576
  condition, and scaffold writes `tests/distribution.test.ts` itself rather than waiting for you to.
@@ -586,10 +589,10 @@ and `configs/app/vite.showcase.config.ts` selects `showcase`. A containing direc
586
589
  the fact by itself. `tests/distribution.test.ts` selects nothing: the published `src` axis the
587
590
  target ships already decides the `distribution` project, and the file is planned from that.
588
591
 
589
- `vendors` is not reconstructed. Its only artifact, `scripts/service.sh`, is birth-owned, so edited
590
- script text is not a trustworthy declaration of a vendor list. A present script remains in the
591
- target and remains protected from deletion through the owned scripts inventory, but a reading verb
592
- does not infer vendors from it.
592
+ `vendors` is not reconstructed. Its artifact, `scripts/service.sh`, is a birth-owned inventory
593
+ skeleton rather than a working installer, so edited script text is not a trustworthy declaration of
594
+ a vendor list. A target-reading verb derives no vendor list from a present script. Only an
595
+ explicitly supplied plan with `vendors` owns that birth artifact.
593
596
 
594
597
  That is why the live-service project follows `service` rather than `vendors`. A reading verb has to
595
598
  plan the project before it can say anything about a target that runs one, and a vendor list it
@@ -774,7 +777,7 @@ const blueprint = createBlueprint('router', {
774
777
  })
775
778
 
776
779
  blueprint.version // '0.0.1'
777
- blueprint.engines // '>=22.12.0'
780
+ blueprint.engines // '>=22.18.0'
778
781
  ```
779
782
 
780
783
  `src` selects published library environments and `app` selects private application environments.
@@ -846,12 +849,13 @@ is the one proof scaffold generates from the workspace's own shape.
846
849
 
847
850
  `service` says the workspace runs a live-service Vitest project over `tests/service`, and it alone
848
851
  registers that project, its `test:service` script, and the `tests/setupService.ts` readiness module
849
- the project names. A publishing workspace invokes it from `prepublishOnly`; a `private: true`
850
- workspace invokes it from `test`, which is the only gate it has. Its longer timeouts and disabled
851
- file parallelism are the same in both. `vendors` names each external service the workspace drives
852
- and emits `scripts/service.sh`, the provisioner that starts them. Neither is derivable from the
853
- other: a workspace may declare vendors before it writes a suite, and a suite may drive a service the
854
- skeleton does not start.
852
+ the project names. The caller prepares the external service before it invokes the project, and the
853
+ setup module verifies readiness. A publishing workspace invokes the project from `prepublishOnly`;
854
+ a `private: true` workspace invokes it from `test`, which is the only gate it has. Its longer
855
+ timeouts and disabled file parallelism are the same in each workspace form. `vendors` names each external service the
856
+ workspace drives and emits `scripts/service.sh`, an inventory skeleton that starts nothing. The
857
+ vendor inventory and live-service setup are independent: a workspace may declare vendors before it
858
+ writes a suite, and a suite may drive a service the skeleton does not start.
855
859
 
856
860
  `integration` projects a cross-environment composition proof for any workspace, independently of
857
861
  whether it has a published `src`. Its generated seed imports every selected `src` and `app`
@@ -901,7 +905,7 @@ one that answers it. So `new` refuses on any question, blocking or not, before i
901
905
  `audit` and `repair` carry the same questions through, because a target that already has that shape
902
906
  still has to be described and restored.
903
907
 
904
- A library caller creating a fresh workspace applies `new`'s rule itself:
908
+ A library caller creating a fresh workspace itself applies the rule the `new` command follows:
905
909
 
906
910
  ```ts
907
911
  import { Compiler, createBlueprint } from '@orkestrel/scaffold'
@@ -1059,8 +1063,9 @@ after a write it prints `next: npm run format`.
1059
1063
 
1060
1064
  Scaffold owns the `scripts` directory. An audit for the orchestration group reports every unplanned
1061
1065
  member as foreign. `overwrite` deletes an unplanned tracked member only when the tree is clean, its
1062
- observed bytes still match, and the path is not protected. A planned birth-owned
1063
- `scripts/service.sh` survives that deletion pass.
1066
+ observed bytes still match, and the path is not protected. An unplanned tracked
1067
+ `scripts/service.sh` is retired on that basis. An explicitly planned birth-owned script survives
1068
+ that deletion pass.
1064
1069
 
1065
1070
  `tests/distribution.test.ts` is the one proof scaffold generates, and the one test artifact it
1066
1071
  claims by presence. Generation is the line, not writing: scaffold writes the vendored
@@ -1252,11 +1257,30 @@ licence, the harness permission file, the scaffold-owned `scripts` directory, th
1252
1257
  shared policy register, the shared policy proof, the shared policy plugin, the shared configuration
1253
1258
  leaf and its proof, the byte-identical root dotfiles, and the guide mirrors a generated workspace
1254
1259
  starts from. It is a candidate list rather than a plan, because a workspace never mirrors its own
1255
- guide. The session-start hooks inside `scripts` split by job:
1256
- the bench probe reports whether a bench CLI resolves, and the dependency hook installs the
1257
- lockfile's closure in a remote session. What wires a bench stays in the canon, and a session reads
1260
+ guide. The session-start hooks inside `scripts` split by job. The bench probe reports whether a
1261
+ bench CLI resolves, and the dependency hook installs the lockfile's closure in a remote session.
1262
+ The Ollama hook invokes `scripts/ollama.sh` only when `CLAUDE_CODE_REMOTE=true`; direct invocation
1263
+ remains available for live-service setup. What wires a bench stays in the canon, and a session reads
1258
1264
  it at its primary root.
1259
1265
 
1266
+ `scripts/ollama.sh` defaults to `http://127.0.0.1:11434` and `qwen3.5:2b-q4_K_M`. It requires Node
1267
+ for native URL and JSON handling and curl for the HTTP protocol. The script accepts an HTTP or HTTPS
1268
+ origin without credentials, path, query, or fragment. It reuses any reachable daemon without
1269
+ requiring a local Ollama executable. It inspects the selected model through `/api/show`, pulls only
1270
+ after a `404` absence response, and warms the model through a completed non-streaming `/api/chat`
1271
+ request with a 30-minute keep-alive. Version readiness, pull completion, and warm completion each
1272
+ require a `2xx` HTTP status; redirects and error statuses fail even when their bodies report
1273
+ completion.
1274
+
1275
+ When an HTTP loopback endpoint is unreachable, the script may start an installed Ollama executable
1276
+ in an owned POSIX process group. A failure sends that owned group `TERM`, then sends `KILL` if it
1277
+ does not stop within 5 seconds; a reused daemon remains untouched. Direct reuse works from Git Bash on Windows, but local startup there fails because Bash
1278
+ cannot safely terminate the Windows process tree. Automatic installation is limited to Linux cloud
1279
+ or CI automation. The official installer download follows only HTTPS redirects, must be nonempty,
1280
+ and runs within the remaining setup deadline. The installer may require root or `sudo`, and its own
1281
+ platform prerequisites remain authoritative. The full setup deadline is 590 seconds, including a
1282
+ 60-second local startup allowance, within the hook's 600-second timeout.
1283
+
1260
1284
  `CANON_PATHS` is the instruction canon, staged for reading instead: the `AGENTS.md` coding contract,
1261
1285
  the `CLAUDE.md` harness bridge, the `.agents/orchestration.md` agent-operation contract, the rules
1262
1286
  under `.claude/rules/` and `.cursor/rules/`, the skills under `.agents/skills/` and `.claude/skills/`,
@@ -1424,6 +1448,23 @@ except the manifest.
1424
1448
  - One host artifact per vendored path the workspace selects. A vendored directory is one planned
1425
1449
  path that expands into the files the data root stores beneath it.
1426
1450
 
1451
+ Every generated manifest declares the toolchain it is gated on. The `engines.node` field carries
1452
+ the blueprint's `engines` value, which defaults to the `>=22.18.0` range. The
1453
+ `devEngines.packageManager` record names npm at the `>=11.6.0` range with its `onFail` key set to
1454
+ the `error` value, and no blueprint field varies that record. An npm at 10.9.0 or later reads that
1455
+ record. Such an npm earlier than 11.6.0 refuses the `npm install` command in a generated workspace
1456
+ with the `EBADDEVENGINES` code, before resolving the dependency graph.
1457
+ npm 10.9.7 refuses an `npm run` command in such a workspace with the same code. The releases
1458
+ measured earlier than 10.9.0, npm 10.5.0 and npm 10.8.3, ignore the record and fail inside
1459
+ dependency resolution instead. Every Node release at 22.18.0 or later bundles an npm at 10.9.0 or
1460
+ later. A generated workspace on Node 22.18.0 or later therefore meets an npm that ignores the record
1461
+ only under an npm other than the bundled one. Run a generated workspace on npm 11.6.0 or later:
1462
+ every release from 10.9.0 up to 11.6.0 refuses it, and 11.6.0 installs it. Read the ambient
1463
+ version with the `npm --version` command. Raise it with the `npm install --global npm@11.6.0`
1464
+ command before the first install; that command installs an npm that reports
1465
+ 11.6.0. The npm readings come from a Linux host on Node 22.22.2, on 2026-09-13, and the bundled
1466
+ versions come from the Node release index read that day.
1467
+
1427
1468
  A workspace publishing a `src` environment rolls each published face's declarations up from that
1428
1469
  face's own Vite config. The seeded config calls `declarationRollup` from the vendored
1429
1470
  `configs/helpers.ts`, which runs the workspace's own compiler as a command —
@@ -28,7 +28,7 @@
28
28
  "storage": "agents/skills/enterprise-bootstrap/SKILL.md",
29
29
  "destination": ".agents/skills/enterprise-bootstrap/SKILL.md",
30
30
  "executable": false,
31
- "digest": "6ed9e288539cbe7a7fbd25b13cf759ecedd72101189e0317fbabf82d1aa1aef4"
31
+ "digest": "f58af98acfa62de842476c17e71c1a98aad250cb4336a160019320a5dd6dacad"
32
32
  },
33
33
  {
34
34
  "storage": "agents/skills/enterprise-bootstrap/agents/openai.yaml",
@@ -40,37 +40,49 @@
40
40
  "storage": "agents/skills/enterprise-bootstrap/references/bootstrap-reference.md",
41
41
  "destination": ".agents/skills/enterprise-bootstrap/references/bootstrap-reference.md",
42
42
  "executable": false,
43
- "digest": "98379b5905cba4cc3725df7ddd8fd9ec19dce75ff89e68499b20ac27c53478c7"
43
+ "digest": "07ab83158aeeaabd965c285de6a30cbe28241e808bcad848fd6c7197fa6b9d12"
44
+ },
45
+ {
46
+ "storage": "agents/skills/enterprise-bootstrap/references/color-modes.md",
47
+ "destination": ".agents/skills/enterprise-bootstrap/references/color-modes.md",
48
+ "executable": false,
49
+ "digest": "c089bd32922e1d6ec74b55afc7cac184f6f8c58a75653647c26ddc814682bcdb"
44
50
  },
45
51
  {
46
52
  "storage": "agents/skills/enterprise-bootstrap/references/components.md",
47
53
  "destination": ".agents/skills/enterprise-bootstrap/references/components.md",
48
54
  "executable": false,
49
- "digest": "252de08e786aa41834f13df4d115e33b3c56d897ccea00b95ed4912da62fbd89"
55
+ "digest": "f4c9b5f2f8e7482aac2aebb0c3a837095c3ff9e8a309db1ee256673a7fdf2553"
50
56
  },
51
57
  {
52
58
  "storage": "agents/skills/enterprise-bootstrap/references/frontend-design.md",
53
59
  "destination": ".agents/skills/enterprise-bootstrap/references/frontend-design.md",
54
60
  "executable": false,
55
- "digest": "8ce1985267316610f4b68582cc993fa2d3f3a504e3e7f2c35e9d9d0e982891a1"
61
+ "digest": "90e5242046776118b18f0489e5cbc82ac498935dc8c29ec2644b53327d89955c"
56
62
  },
57
63
  {
58
64
  "storage": "agents/skills/enterprise-bootstrap/references/inputs.md",
59
65
  "destination": ".agents/skills/enterprise-bootstrap/references/inputs.md",
60
66
  "executable": false,
61
- "digest": "17fb8a977d34a0ef25f5155ac6459e805cc4f691d819995eb85838dca6c8fa46"
67
+ "digest": "7e536b0651a3347019b140d1fac29e00dba38234ae37a93e3c34281086da0cdf"
62
68
  },
63
69
  {
64
70
  "storage": "agents/skills/enterprise-bootstrap/references/inspection.md",
65
71
  "destination": ".agents/skills/enterprise-bootstrap/references/inspection.md",
66
72
  "executable": false,
67
- "digest": "48b202e331c17a26f8262b30095898e6d147906847a74d3779907c0aad4de43b"
73
+ "digest": "152548af42ef9322cfb398b9a6d64352f39c912c31ee324016c13959e4cfa34b"
74
+ },
75
+ {
76
+ "storage": "agents/skills/enterprise-bootstrap/references/responsive-layout.md",
77
+ "destination": ".agents/skills/enterprise-bootstrap/references/responsive-layout.md",
78
+ "executable": false,
79
+ "digest": "a933fdf530d4001cc9a75d24b103d111efc428d146d2c8cf9ea934891ca21019"
68
80
  },
69
81
  {
70
82
  "storage": "agents/skills/enterprise-bootstrap/references/utilities.md",
71
83
  "destination": ".agents/skills/enterprise-bootstrap/references/utilities.md",
72
84
  "executable": false,
73
- "digest": "0601721056882a7d45bfaa9ca0a03aa39e1259876f16546d4bf19b4b9496e023"
85
+ "digest": "5176a2b292cab40a1b954134042c27c4a19077a999c9f13f9bc16d8dd007063b"
74
86
  },
75
87
  {
76
88
  "storage": "agents/skills/orkestrel-align-packages/SKILL.md",
@@ -448,7 +460,7 @@
448
460
  "storage": "claude/rules/workspace.md",
449
461
  "destination": ".claude/rules/workspace.md",
450
462
  "executable": false,
451
- "digest": "5e69fa5bb2b439c640d1d73204418309d310a9de5a28212b8756de09f4af5d2d"
463
+ "digest": "5fbf4f0e9803ef1e4cbaa12a2cfb896cec1188f9c2fc3e020b93923319c91b2f"
452
464
  },
453
465
  {
454
466
  "storage": "claude/rules/writing.md",
@@ -460,13 +472,13 @@
460
472
  "storage": "claude/settings.json",
461
473
  "destination": ".claude/settings.json",
462
474
  "executable": false,
463
- "digest": "c5c379bf5001754d11b94e692f7624e0a59c7e4b2b2072569b115c3723c24ee7"
475
+ "digest": "52c5aafe0f3a891a909a5ce26ad761abb38f2ab931f084f5ca147abb7680c419"
464
476
  },
465
477
  {
466
478
  "storage": "claude/skills/enterprise-bootstrap/SKILL.md",
467
479
  "destination": ".claude/skills/enterprise-bootstrap/SKILL.md",
468
480
  "executable": false,
469
- "digest": "1e2c83abb2a7c6a2e41dc210202d25124f6a30cfdc1bbd44d6b9c59dded6d93f"
481
+ "digest": "0973f97ccd042e53d33f72396fe1924b1de98f2a2c27338615279bb1d569e000"
470
482
  },
471
483
  {
472
484
  "storage": "claude/skills/orkestrel-align-packages/SKILL.md",
@@ -682,7 +694,7 @@
682
694
  "storage": "guides/scaffold.md",
683
695
  "destination": "guides/scaffold.md",
684
696
  "executable": false,
685
- "digest": "660f6f9443c16252ad92afb0c78802908c5d2ded69a461a8e83bb12c71ea43db"
697
+ "digest": "3f26b6d6649a7fb5882c02d674c5c10386706e87a5305b863a0d2028a2bf5043"
686
698
  },
687
699
  {
688
700
  "storage": "scripts/codex.sh",
@@ -706,7 +718,7 @@
706
718
  "storage": "scripts/ollama.sh",
707
719
  "destination": "scripts/ollama.sh",
708
720
  "executable": true,
709
- "digest": "666979b75f02c7f550c3acc74a02b67594407b887e6a8b90f0ba38a0d79bec07"
721
+ "digest": "be5cb42991792190d7f61c7b8eef568eaf207db67cce5d2ccc223af814f2d6fa"
710
722
  },
711
723
  {
712
724
  "storage": "tests/config.test.ts",
@@ -773,5 +785,5 @@
773
785
  ".cursor/rules",
774
786
  "scripts"
775
787
  ],
776
- "digest": "0327bc72ce35efe56b959fea41d06a8334b9c9fd318b6ea005efd46b8ef0fd46"
788
+ "digest": "06692c3a078815c3d4e0ed00c4280ce381119a1c1005334b1372c137e758dc18"
777
789
  }
File without changes
File without changes
File without changes