Bengal 0.5.1
A real CSS engine and a refreshed default theme — a tokenizer-based minifier that can't corrupt your stylesheets, OKLCH palettes with light-dark() dark mode, a dependency-free knowledge graph, and byte-reproducible build output.
Key theme: A real CSS engine, and a default theme that earns its zero-dependency promise. Bengal 0.5.1 replaces the regex-based CSS minifier with a proper CSS Syntax Level 3 engine that tokenizes before it serializes — so it can no longer glue tokens together and silently corrupt a stylesheet — and it re-authors the default theme around modern CSS: OKLCH palettes,light-dark()dark mode, structured data, and a knowledge graph that no longer pulls D3 from a CDN. Build output is now byte-reproducible across rebuilds, and a few free-threading correctness fixes round it out.
Highlights
A real CSS engine
The CSS minifier was a pile of regexes. It is nowbengal.css: a CSS Syntax Level 3 engine that tokenizes the stylesheet before serializing it. The bug that prompted the rewrite — @scope (...) to (...) getting glued into to(...), which made the parser treat to as a function and silently drop the scoped rule — is gone, and the new tokenizer makes that whole class of "identifier glued to (" corruption structurally impossible (#510).
The engine verifies its own work. After minifying, it re-parses its output and compares an independent meaning signature — selector combinators, declaration values, and (at the aggressive level) the resolved cascade — against the input. On any mismatch it returns the input unchanged, so it can never emit corrupted CSS.
minify_css also gained a levelargument:
"safe"(default) — lossless whitespace and comment removal. The default build path is unchanged."optimize"— adds safe value normalizations: named colors when shorter than hex, unquotedurl()bodies, length-context unitless zeros (margin:0px→margin:0), and collapsed shorthands (margin:0 0 0 0→margin:0) (#515)."aggressive"— adds cascade-invariant structural rewrites: empty-rule removal, exact-duplicate dedup, and adjacent-rule merging.
Two opt-in passes layer on top:flatten_nesting=True de-sugars native CSS nesting into flat selectors for legacy browser targets while preserving the cascade (#516), and intra-stylesheet dead-code removal strips unused @keyframes, @font-face, and custom properties (#512). Native CSS nesting (&:hover) is now preserved by default rather than flattened (it's Baseline 2023).
A refreshed default theme
The default theme was re-authored around modern CSS and a zero-dependency runtime:
- No third-party CDNs by default. The theme no longer loads Mermaid, D3, KaTeX, or Google Fonts from third-party CDNs at runtime. Opt in via
[capabilities]inbengal.tomlto self-host diagram and math vendors at build time (#533). - OKLCH palettes. Colors are now authored in OKLCH for wide-gamut richness, and the five built-in palettes derive their hover, active, border, surface, and state variants automatically from a handful of anchors via relative-color and
color-mix— retuning a palette no longer means editing a hand-painted hex matrix. The focus ring is palette-aware instead of falling back to a fixed blue (#534). light-dark()dark mode. Dark colors flow through a singlelight-dark()token set selected bycolor-scheme, replacing the duplicated dark token matrix. Dark mode now renders correctly in every named palette and follows the OS preference with no flash of the wrong theme (#535).- Structured data. Pages emit correct
og:typeper kind,WebSite/CollectionPageJSON-LD on landing and list surfaces, andBreadcrumbListdata; the docs right-sidebar graph minimap is consolidated into shared partials (#536). - One JavaScript model. Interactive regions — table of contents, docs nav, learning-track sidebar, and the REST API catalog — are now custom elements (
<bengal-toc>,<bengal-docs-nav>,<bengal-track-nav>,<bengal-api-catalog>) that initialize themselves when they appear (including content inserted after load) and tear their listeners down when removed. This retires the redundant second script-loading registry. Every page still degrades gracefully with JavaScript disabled (#537).
A dependency-free knowledge graph
The graph minimap and the full/graph/ explorer are now rendered by a first-party, dependency-free engine. Node positions are computed at build time and the explorer draws to a canvas, so it stays responsive on large sites. The opt-in d3capability is removed — the graph no longer depends on D3, and the runtime CDN request for it is gone.
Reproducible output
Two builds of unchanged content now produce byte-identical output. The knowledge graph'sgraph/graph.json and the search index.json previously used a per-process randomized hash (and absolute paths), with process-dependent edge and tag ordering; ids are now a stable hash of the site-relative path, and edges and tags sort deterministically. Sitemap and agent.jsonaggregates use stable URL/path ordering so results no longer depend on page discovery order (#431).
Free-threading correctness
Provenance-cache races that could return stale warm-build output under free-threaded Python — when records were loaded or verified concurrently — are fixed (#438), and free-threading detection is consolidated to the canonicalbengal.utils.concurrencyhelper so executor selection and render paths no longer drift on GIL-fallback logic (#381).
Added
- Opt-in intra-stylesheet removal of unused
@keyframes,@font-face, and custom properties (#512). minify_css(..., flatten_nesting=True)de-sugars nested rules into flat selectors for legacy targets while preserving the cascade (#516).
Changed
- The CSS minifier is now a tokenizing CSS Syntax Level 3 engine (
bengal.css) withsafe/optimize/aggressivelevels;optimizeadds safe color,url(), and numeric normalizations (#510, #515). - Default theme re-authored in OKLCH with anchor-derived palettes and a palette-aware focus ring (#534).
- Default theme dark mode uses a single
light-dark()token set selected bycolor-scheme, correct in every palette and following OS preference (#535). - Default theme no longer loads Mermaid, D3, KaTeX, or Google Fonts from third-party CDNs; opt in via
[capabilities]to self-host at build time (#533). - Default theme emits
og:type,WebSite/CollectionPageJSON-LD, andBreadcrumbListstructured data; docs sidebar graph minimap consolidated into shared partials (#536). - Default theme JavaScript uses one custom-element enhancement model (
<bengal-toc>,<bengal-docs-nav>,<bengal-track-nav>,<bengal-api-catalog>), retiring the redundant script registry (#537). - The knowledge graph minimap and
/graph/explorer are rendered by a dependency-free, first-party engine that computes layout at build time. - Core: per-heading search index records for deep-link search results (#546); renderer-agnostic data-table contract decoupled from Tabulator config (#547); optional git-derived last-modified field for pages (#548); code-fence attributes (title, diff, line ranges) parsed through to the highlighter (#549).
- Free-threading detection consolidated to
bengal.utils.concurrencyso executor selection and render paths don't drift on GIL fallback (#381).
Fixed
- The CSS minifier no longer corrupts
@scope (...) to (...)by gluing it intoto(...)and dropping the rule; the tokenizing engine makes that class of corruption impossible, and it verifies its own output before emitting (#510). graph/graph.jsonand the searchindex.jsonare byte-identical across rebuilds of unchanged content (stable ids, deterministic edge/tag ordering).- Sitemap and
agent.jsonaggregate output uses stable URL/path ordering, independent of discovery order (#431). - Provenance-cache races that could return stale warm-build output under free-threaded Python are fixed (#438).
bengal fixnow receives per-source link metadata, so it can suggest repairs for every broken internal link on a page, not just the first few shown in validator details (#508).
Removed
- The opt-in
d3capability and the runtime D3 CDN request from the/graph/page; the knowledge graph works by default with no third-party scripts. - The obsolete
@supports (color: color-mix(...))feature-query fallbacks in the default theme —color-mix()is now Baseline, so the guarded branches apply unconditionally (#534). - The legacy CSS code paths: the
bengal.assets.css_minifiershim and the regex-basedbengal/core/asset/css_transforms.py(lossless_minify_css,remove_duplicate_bare_h1_rules,transform_css_nesting). Importminify_cssfrombengal.css(#510).
Upgrading
uv pip install --upgrade bengal
# or
pip install --upgrade bengal
A few things to know:
- The CSS minifier moved. If you imported CSS helpers from internals, switch to
from bengal.css import minify_css. Thebengal.assets.css_minifiershim andbengal/core/asset/css_transforms.pyare gone. Native CSS nesting is now preserved by default rather than flattened; passflatten_nesting=Trueif you target browsers without nesting support. - The default theme is CDN-free by default. If you relied on Mermaid, D3, KaTeX, or Google Fonts loading at runtime, opt in under
[capabilities]inbengal.tomlto self-host them at build time. The knowledge graph needs no opt-in — it's dependency-free now, and thed3capability is removed. - Reproducible builds. Graph and search output is now byte-identical across rebuilds of unchanged content; if you diff or cache build artifacts, expect previously-noisy
graph.json/index.json/sitemap output to settle.