{"version":"v1.0","client_state":{"DocsNavigation.default":{"fields":{"query":""},"persist":"memory","send_to_server":true},"ColorScheme.default":{"fields":{"mode":"system"},"persist":"local","send_to_server":true}},"endpoints":{"action":"/_bretzel/action","sse":"/_bretzel/sse","refetch":"/_bretzel/refetch"},"csrf":"c57a017f6c11efcd2611031b5ce56b9a","page_id":"aabc8848328e44128a6f4a25dcd0ce39","address":""}

The client runtime

The server stays the source of truth, but something runs in the browser: a home-made engine, with no npm and no third-party reactive framework. This page says what it guarantees, then enumerates its vocabulary.

You do not write this

In a Bretzel app, the `bz-*` directives are emitted by the components: passing `visible=binding` produces a `bz-show`, `value=binding` produces a `bz-model`. This page is the emergency exit — what one reads to understand what was emitted, or to write by hand the case the components do not cover.

The three guarantees

A client runtime is judged on what it promises when the server rewrites the page under its feet.
GuaranteeThe mechanism
A client state survives a server refreshEvery scope is keyed by bz-id. After a morph, the subtree is re-scanned: the bindings are thrown away then rewired, and the effects restore what the morph overwrote (text, display, value, classes).
No round trip just to display somethingA client binding compiles into a JS expression evaluated in the browser. Showing, hiding, computing a class: nothing goes over the network.
The transport boundary is the runtime'sA component never POSTs. It declares a handler; the bridge adds the HMAC signature, the CSRF token, the protocol headers and the client-state snapshot.

What the runtime weighs

The bundle is concatenated from `_src/*.js`, with no bundler and no minifier — the file served is the one you debug. The numeric prefix IS the load order.
25 modulescore: 8 files, 2940 linesbundle : 336 KB
core8
FileRoleLines
00_index.jsbootstrap + window.$bz wiring.447
01_signals.jsreactive primitives : signal / effect / computed.117
02_directives.jsthe 13 bz-* directives + the binding engine.761
03_scope.jsbz-data component-scoped state, keyed by bz-id.268
04_persistence.jsstorage adapters per ClientState instance.99
05_bridge.jsHTMX glue : signal snapshot out, <bz-patch> in.567
06_helpers.jsshared helpers for overlay-class components.531
06_locale.jsmonth and weekday names, derived from the language.150
component engine17
FileRoleLines
07_calendar.js<bz-calendar> custom element (stateful day grid).942
08_file_upload.js$bz.fileUpload.makeScope factory for ui.file_upload.488
09_notification.jstoast stack manager (bz-data scope factory).137
10_charts.jsshared chart tooltip + legend scope factories.334
11_number_input.jsshared scope for the NumberInput component.112
12_slider.jsshared scope for the Slider component.122
13_select.jsshared scopes for the Select component.72
14_combobox.jsshared scopes for the Combobox component.204
15_pagination.jsthe Pagination component's shared scope.135
16_accordion.jsthe shared scopes of Accordion, Tree, Tabs, Stepper294
17_carousel.jsthe Carousel component's shared scope.231
18_time_picker.jsthe TimePicker component's shared scope.158
19_dnd.jsthe node-DnD gesture shared by `dropzone` / `draggable`.721
20_resizable.jsthe shared scope of the Resizable component (split panes).389
21_signature_pad.jsthe SignaturePad component's shared scope.262
22_verbs.jsthe CLIENT half of `bretzel.runtime.verbs`.126
23_diagram.jsthe highlighting of neighbours, in `ui.diagram`.131

The directives

Grouped by what they guarantee. The vocabulary has two halves — a Python constant declares it, a JS module wires it — and the runtime cannot import Python. A gate already checks that at commit time (test_python_js_mirror.py); this table shows it, one notch stricter: comments stripped, and per source module.
DOM structure4
Written into the HTMLWhat it guaranteesDeclared by
bz-data="{ open: false }"Opens a local scope, keyed by bz-id — it SURVIVES the morph of a server refresh. Inside a scope method, write this.field.BZ_DATA_PREFIX — component-local scope declaration
bz-for="v in liste :key=v.id :flip"Keyed iteration over a single-root <template>. :key reuses the nodes; :flip animates the reflow of the rows that survive.BZ_FOR_PREFIX — keyed client-side iteration
bz-if="expr"Really mounts / unmounts the subtree. Every mount starts from a fresh tree.BZ_IF_PREFIX — mount/unmount conditional
bz-teleport="body"Projects the content elsewhere in the DOM; the scope stays resolved at the original place. Re-projects if the source changed.BZ_TELEPORT_PREFIX — render at another DOM location
reactive display4
Written into the HTMLWhat it guaranteesDeclared by
bz-attr:aria-expanded="open"A one-way reactive attribute. false/null/undefined remove the attribute; on a native form field, the property is updated too (otherwise a morph would empty the input).BZ_ATTR_PREFIX — generic one-way attribute bind
bz-class="{ actif: open }"Adds / removes classes by truthiness. The static class= rendered by the server is a baseline that is never removable.BZ_CLASS_PREFIX — class object/array bind
bz-show="expr"Toggles display. The element stays mounted (hence stays in the DOM for focus, measurement, tests).BZ_SHOW_PREFIX — display:none toggle (stays mounted)
bz-text="expr"textContent follows the value. Display only.BZ_TEXT_PREFIX — textContent (display-only)
two-way input1
Written into the HTMLWhat it guaranteesDeclared by
bz-model="$bz.state.Form.default.email"Two-way binding, form controls only.BZ_MODEL_PREFIX — two-way binding on form inputs
user gesture1
Written into the HTMLWhat it guaranteesDeclared by
bz-on:click="open = !open"Listens for an event. An element marked aria-disabled STARTS no interaction: activation events are ignored, the others pass (closing stays possible).BZ_ON_PREFIX — event handler (client-only)
the node's lifecycle3
Written into the HTMLWhat it guaranteesDeclared by
bz-effect="void geom"A continuous reactive effect: replayed on every mutation of a signal it reads.BZ_EFFECT_PREFIX — continuous reactive effect
bz-init="setup()"Once only, at the node's first mount — and not replayed by a re-bind after a morph.BZ_INIT_PREFIX — one-shot on-mount hook
bz-ref="track"Names the node in $refs. Registered across the whole tree BEFORE any binding, so a parent bz-init sees a child ref.BZ_REF_PREFIX — named DOM reference
Wiring order on a single elementref → model → attr → class → text → show → on → effect → initRead from the engine. It is not cosmetic: bz-ref is wired first (a neighbour can read it), bz-init last (the node is fully wired when it runs).

Inside an expression

A directive expression is compiled once then cached. The current scope is on the scope chain — a bare name reads the scope — and a few variables are injected.
scope1
VariableContents
$scopeThe current bz-data scope. It is on the scope chain too, so a bare name reads it.
the node2
VariableContents
$elThe element carrying the directive.
$refsThe nodes named by bz-ref in this scope.
the event2
VariableContents
$eventThe DOM event — inside a bz-on: only.
$valueThe value written — inside a bz-model only.
act2
VariableContents
$dispatch$dispatch(name, detail) — a CustomEvent bubbling up from $el.
$nextTick$nextTick(fn) — after the signal flush, hence after the DOM has been rewritten.
{ open: false, pick(v) { this.open = false; } }
The trap: the rebinding of bare names holds for inline expressions, not for a scope's methods. Inside a method it is `this.field` — without the `this`, you create a global.

The $bz surface

The global object, read module by module. The scope factories are what a component spreads into its `bz-data`; the rest is the engine. The “exposes” column is read from the JS literal, never copied by hand.
reactivity3
NameWhat it isExposesDefined in
$bz.computedcomputed(fn) → {get, peek, dispose}. A memoised derivation, recomputed when a dependency moves.—01_signals.js
$bz.effecteffect(fn) → {dispose}. Runs straight away, runs again when a signal it read changes. The writes of a single tick are merged into one re-execution.—01_signals.js
$bz.signalsignal(init) → {get, set, peek, subscribe}. get() subscribes the current effect, peek() reads without subscribing, set() triggers nothing if the value is identical.—01_signals.js
state & transport4
NameWhat it isExposesDefined in
$bz.notifyPushes a toast onto the notification stack.—00_index.js
$bz.pendingpending(element|action_id, delay_ms) → the “an action is in flight” signal. An element walks up to the carrier of its hx-post; a string addresses the action from elsewhere in the page. The delay is what avoids the flash on short round trips. On the Python side: ``ui.pending()``.—05_bridge.js
$bz.state$bz.state.<Class>.<key>.<field> — the signal of a client-state field, materialised at boot from the envelope.—00_index.js
$bz.versionThe bundle's protocol version.—00_index.js
shared helpers5
NameWhat it isExposesDefined in
$bz.helpersThe bricks shared by the overlays and by the pointer-drag family.focusTrap, escapeKey, onWindow, pushUrl, urlParam, scrollLock, clickOutside, floating, prefersReducedMotion, emitChange, capturePointer, releasePointer06_helpers.js
$bz.localeThe month and day names, derived from ``<html lang>`` by ``Intl``. Python cannot produce them: its ``locale`` module is process-global state.tag, monthNames, monthName, weekdayNames, weekdayLongNames06_locale.js
$bz.multiSelectThe membership algebra of a multiple selection, shared by Select and Combobox._picked, _isPicked, _hasPicked, _togglePick, _removeOne, _pick, _setValue, _clearAll06_helpers.js
$bz.numPure numeric primitives: precision implied by a step.precisionFromStep, cachedPrecision06_helpers.js
$bz.verbsThe client half of the VERBS (``bretzel.copy`` …): a browser action triggered from an ``on_*=``. Only ``copy`` lives there — ``print`` and ``fullscreen`` fit in an expression Python writes out in full. It carries the fallback outside a secure context, without which an internal tool served over ``http://`` on a local IP would copy nothing, in silence.share, vibrate, copy22_verbs.js
gesture engine1
NameWhat it isExposesDefined in
$bz.dndThe Pointer Events drag-and-drop engine, shared by draggable and dropzone.MOUSE_THRESHOLD_PX, TOUCH_HOLD_MS, TOUCH_TOLERANCE_PX, _state, _axisOf, _accepts, _canEnter, _indexOf19_dnd.js
component scope18
NameWhat it isExposesDefined in
$bz.accordionA scope factory, spread into the component's bz-data.single, multi16_accordion.js
$bz.carouselA scope factory, spread into the component's bz-data.scope17_carousel.js
$bz.chartsA scope factory, spread into the component's bz-data.tooltipScope, lineScope, scatterScope, hide10_charts.js
$bz.comboboxA scope factory, spread into the component's bz-data.optionOf, paintOptions, common, single, multi14_combobox.js
$bz.diagramA scope factory, spread into the component's bz-data.scope23_diagram.js
$bz.fileUploadA scope factory, spread into the component's bz-data.makeScope08_file_upload.js
$bz.notificationA scope factory, spread into the component's bz-data.—09_notification.js
$bz.numberInputA scope factory, spread into the component's bz-data.scope11_number_input.js
$bz.paginationA scope factory, spread into the component's bz-data.scope15_pagination.js
$bz.resizableA scope factory, spread into the component's bz-data.scope20_resizable.js
$bz.selectA scope factory, spread into the component's bz-data.single, multi13_select.js
$bz.signaturePadA scope factory, spread into the component's bz-data.scope21_signature_pad.js
$bz.sliderA scope factory, spread into the component's bz-data.scope12_slider.js
$bz.stepperA scope factory, spread into the component's bz-data.scope16_accordion.js
$bz.tabsA scope factory, spread into the component's bz-data.scope16_accordion.js
$bz.timeA scope factory, spread into the component's bz-data.scope, fill18_time_picker.js
$bz.tooltipA scope factory, spread into the component's bz-data.scope16_accordion.js
$bz.treeA scope factory, spread into the component's bz-data.scope16_accordion.js