Chirp 0.6.0

Mounted apps, named routes, deeper contract diagnostics, DevTools Swap Doctor, ChirpUI 0.6, Kida 0.8, and production deployment defaults.

Focus: make larger hypermedia apps easier to assemble, route, deploy, and debug without weakening Chirp's return-type and contract-check model.

This release adds mounted-app composition, named routes with reverse URL generation, richer startup diagnostics, an in-process benchmark suite, and production defaults for Railway deployments. It also tightens several correctness paths around cache keys, shell outlets, block-scoped forms, Kida 0.8 template references, and cross-thread event delivery.


Highlights

Mounted app composition

app.mount_app(prefix, sub_app) hoists a pre-freeze Chirp app into a parent app at a URL prefix. Sub-app routes are path-prefixed, middleware/hooks/loaders/contract checks are appended, template extension points merge with parent-wins semantics, and dropped merge entries are surfaced as mount_app_mergeINFO issues.

Mounted sub-apps are consumed after mounting. Callingsub_app.freeze() or sub_app.run() raises RuntimeError, avoiding an accidental half-mounted standalone runtime. See docs/build-apps/pages-navigation/mounting.md and docs/rfcs/005-mount-app.mdfor merge rules and unsupported state.

Named routes andurl_for

Mounted filesystem pages now receive default dotted names (/contacts/{contact_id} -> contacts.contact_id, / -> index), with per-page overrides via module-level name = "...". Reverse routes with:

app.url_for("contacts.contact_id", contact_id=42)

or from templates:

{{ url_for("contacts.contact_id", contact_id=42) }}

Path params are percent-encoded, remaining kwargs become query parameters, and None values are dropped. A new route_names contract check fails app.check()when two different paths claim the same route name.

DevTools Swap Doctor

Expanded htmx activity rows now explain swap behavior from the server's point of view: effectivehx-*inheritance, selector-match checks, target presence, render intent, render-plan context, broad-target warnings, full-document fragment smells, and no-op swap detection. Overlapping htmx requests keep diagnostics attached to the correct row through XHR correlation when available.

New scaffolded apps includeAGENTS.mdguidance for activating DevTools, and browser-capable agents can discover the diagnostics API with:

window.ChirpHtmxDebug.help()

Contract coverage and page handlers

chirp check --coveragereports coverage counters for POST form contracts, mounted page contracts, app-shell targets, and OOB regions. Contract output is grouped by concern and includes total elapsed time.

The newpage_handlers contract check catches filesystem page.py files that define no recognized handler (get, post, other HTTP method names, or handler) before requests fall through to a runtime 404/500. Handler-shaped typos such as def handle, def GET, and def indexemit warnings.

ChirpUI 0.6 and Kida 0.8

Chirp's optionalui extra and scaffolded projects now require chirp-ui>=0.6.0. use_chirp_ui(app) injects ChirpUI's packaged starter theme after chirpui.css, while new scaffolds keep app-owned static/theme.css as the override slot. app.check() now reports ChirpUI 0.6 manifest/runtime metadata and emits chirpui_runtime INFO when app templates import ChirpUI without use_chirp_ui(app).

Kida moves to>=0.8.0. Contract checks now resolve relative template references (./, ../) and configured @alias/prefixes before dead-template and inherited swap-safety analysis.

Production defaults

AppConfig.from_env() now recognizes Railway environments: it falls back to Railway's PORT, binds to 0.0.0.0 when Railway is detected, and includes RAILWAY_PUBLIC_DOMAIN plus healthcheck.railway.app in default allowed_hosts when CHIRP_ALLOWED_HOSTSis absent. New deployment docs cover production and Railway setup.

Chirp's docs build dependency now requiresbengal>=0.3.2so non-workspace production builds pick up Bengal's latest build fixes.


Fixed

  • Cache keys now include query string and htmx response shape so paginated views, full-page responses, boosted responses, and local fragments do not collide underCacheMiddleware.
  • Shell outlets keep boosted navigation responses selectable by inheritedhx-select contracts, and app.check()warns when broad shell targets/selectors are missing outlet metadata.
  • Form contracts now respect nested template blocks and Kida control tags when validating block-scopedFormContractentries.
  • Cross-thread event delivery inReactiveBus, ToolEventBus, PostgreSQL LISTEN helpers, and the standalone chat example is handed back to each subscriber's owning event loop.
  • Example drift was cleaned up across ChirpUI and standalone examples, including the newexamples/chirpui/forum_shellreference app.

Dependencies

  • chirp-ui>=0.6.0
  • kida-templates>=0.8.0
  • bengal-pounce>=0.6.0

Upgrading

uv pip install --upgrade "bengal-chirp>=0.6.0"
pip install --upgrade "bengal-chirp>=0.6.0"