{"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":"a9f4777165f51eac12c0de34f57d6d78","page_id":"01dc4ad7fecf4df2ad8f2f3c050190fa","address":""}

App structure

Everything is a feature, flat. Each decorates itself; `main` gathers them. No `app/` folder, no central wiring.

The skeleton

examples/docs/
├── main.py            # creates Bretzel(...) + app.include(...)
├── features/          # everything flat
│   ├── shell.py       # @layout — the shell (nav, chrome)
│   ├── home.py        # @page("/")
│   ├── components.py  # @page("/components")
│   ├── errors.py      # @error_page(404) / @error_page(500)
│   └── …
└── lib/               # shared helpers (introspect, blocks)

A feature decorates itself

The decorator only MARKS the function. The actual registration happens in `app.include(…)` — the import order has no effect at all.
# features/home.py
from bretzel import page, ui
from examples.docs.features.shell import shell

@page("/", layout=shell, title="Home")
def home_page() -> None:
    ui.heading("Welcome")

main gathers

`app.include(module, …)` scans the modules for their marks. The `shell` (`@layout`) does not need including — it resolves by reference through `layout=shell`.
# main.py
from bretzel import Bretzel

app = Bretzel(secret_key="…", mode="dev")

from examples.docs.features import home, components, errors
app.include(home, components, errors)

Flat, yes — but not necessarily

“Flat” is the default, not a constraint. One folder per domain works, and the framework has nothing to know: `include` scans the top-level callables of the module it is given. So it is enough for the sub-folder's `__init__.py` to RE-EXPORT its pages.
myapp/
├── main.py
└── billing/              # one domain, one folder
    ├── __init__.py       # re-exports the pages
    ├── quotes.py         # @page("/quotes")
    └── invoices.py       # @page("/invoices")
# billing/__init__.py
from myapp.billing.quotes import quotes_page
from myapp.billing.invoices import invoices_page

# main.py
from myapp import billing
app.include(billing)          # both routes mount
Re-export the FUNCTIONS, not the modules
The trap is there, and it is silent: if the `__init__.py` re-exports the MODULES (`from . import quotes, invoices`) instead of the functions, `include` finds no mark and the routes return 404 — with no error at startup. Measured. In that case, include the modules themselves: `app.include(billing.quotes, billing.invoices)`.

The 11 markers

A feature does not declare views only. Everything that follows is placed the same way — one decorates a function at module level, and `include` picks it up.
What one writesWhat it declares
@page("/pricing")a route that renders a view
@layouta reusable shell (nav, chrome) — referenced by `layout=`
@error_page(404)the rendering of an HTTP status
@download("/export.csv")a route that returns a FILE, not a page
@refreshable(deps=[Cart])a zone that re-renders when a state mutates
@backgroundwork launched after the response, off the critical path
@idempotentan action a double click must not run twice
@auth.sourcewhere an identity can come from (an API token, a trusted proxy…)
@auth.door(OIDC(...))an OAuth/OIDC door, and the decision to accept the profile
@middlewareone pass on every request
@startup / @shutdownopening and closing the app's resources
Every row is checked at display time: the symbol is really resolved. A renamed decorator would flag itself here instead of letting you believe it exists.

When the app grows: declaring a contract

Flat and with no contract, nothing stops a feature importing another quietly. `Feature` makes the dependency explicit: what I provide, what I use, what I read. The graph is checked at startup — an unknown dependency, a cycle and a name collision are errors, not run-time surprises.
# features/cart/feature.py
from bretzel import Feature
from .state import CartState
from .ui import cart_page

feature = Feature(
    name="cart",
    kind="page",
    provides=[CartState, cart_page],   # my public surface
    uses=["catalog_data", "money"], # the only ones I may import
)
`kind=` takes one of these 10 values: `data`, `error`, `facade`, `infra`, `job`, `layout`, `logic`, `page`, `shell`, `state`.
The graph rendered live on a demo app:App map →

Having the structure judged

`check` reads the code written against the framework. With `--deep`, it mounts the named app and arbitrates its map too — which reading files alone cannot see.
py -m bretzel.cli.main check examples
py -m bretzel.cli.main check --deep examples.docs.main:app
These docs run exactly like that: `examples/docs/features/` flat, `shell.py` as the `@layout`, `main.py` doing the `include`. What you are reading IS the pattern. `core/` (when it exists) carries the global-only: shared states, cross-cutting config — no views.