Chirp 0.8.1

A third signal binding helper (signal_attrs), signal emit/derived deduplication, a reactive Lucky Cat showcase wave (auth + Markets IA), and a batch of framework auth/streaming and contract fixes.

Focus: round out thesignal()reactive primitive shipped in 0.8.0 and prove it end to end in the flagship example.

This is a patch release on top of 0.8.0. It adds the third signal binding helper, makes coalescing signals skip redundant work, and lands a large Lucky Cat showcase wave (an authentication walkthrough and a four-destination Markets information architecture) that exercises the reactive and auth subsystems against a realistic app. It also fixes a batch of framework auth/streaming papercuts and tightens two startup contracts. No breaking changes.


Highlights

signal_attrs() — bind a signal on an element you already have

A third binding helper alongsidesignal() / signal_block(). It emits the binding attributes only (sse-swap="name" hx-target="this") for placement inside an existing element:

<section class="board" {{ signal_attrs('market_stats') }}>
  {{ stat_strip_body(stats) }}
</section>

A layout's own CSS-grid / flex container (or a <ul>) becomes a live sink without an injected wrapper<span>/<div>breaking its layout. Unlike a hand-written sse-swap, the signal_attrs('x')call is recorded for topic scoping and recognized by thesignal_dead_bindingcontract by its call-site — so the binding is validated even though thesse-swapattribute is produced at render time.

Signals skip redundant emits

A coalescing signal (coalesce=True, the default) now skips the wire event and the derived cascade when its new value equals the current one — a purerender maps equal values to equal payloads, so the swap would be byte-identical. Derived signals dedup the same way: an unchanged projection no longer re-emits or propagates. This makes the compute-once / broadcast-many dashboard pattern cheap. Append-style / drop-sensitive topics opt out withcoalesce=False.

Lucky Cat — reactive + authenticated showcase

The flagship ChirpUI example grew into a full demonstration of the auth subsystem (three gating levels: full-page@login_required, current_user()component chrome, and action-route backstops) and a four-destination Markets information architecture (Home lobby, Favorites, Trending, Research) backed by a shared query seam. The lobby is fully reactive off a single source signal plus derived projections, and the example's inline docs were rewritten for newcomers. See the examples/chirpui/lucky_cat README and DESIGN.md.


Also in this release

  • Framework auth / streaming fixes — assorted correctness fixes across the auth flows and streaming context preservation (the example no longer needs to manually re-capture auth/CSRF across streamed responses).
  • DXAppConfig.from_env()now accepts keyword overrides applied after env loading (no moredataclasses.replace(...)), and app.check()dead-template detection scans route-handler modules forFragment(...)/Template(...)string literals and module-level*.htmlconstants, so Python-referenced templates are no longer false-positive orphans.
  • Contracts — signal dead-binding checks now validate hand-writtensse-swap on pages composed under asignal_connect()layout (with an INFO nudge to prefer signal_attrs()), while pages that open their own sse_scope()stream are excluded.
  • chirp-ui floor bumped to>=0.10.0 across the uiextra, dev group, and the chirp newscaffold.

See the full changelog for the complete list.


Dependencies

No dependency floor changes from 0.8.0 (bengal-pounce>=0.8.0, kida-templates, anyio). The ui extra now pins chirp-ui>=0.10.0.


Upgrading

pip install --upgrade bengal-chirp

0.8.1 is a drop-in upgrade from 0.8.0 — no code changes required.