Project layout
What lives under app/, and what the build generates.
Only cataract.toml and app/routes are required. Everything else is convention that can be moved in [paths].
cataract.toml
app/
routes/ pages and API routes; the tree is the route table
layouts/ document chrome; every page names one
lib/ shared modules
islands/ client-side components
public/ static files, content-addressed at build time
.cataract/ generated sources and processed assets
dist/ the compiled binaryModule declarations are mandatory
Every .chpl file under app/ must wrap its contents in an explicit module declaration, and the name must be unique across the project. The scanner reads the declared name back out of the source and generates code that calls it.
module PagePostsIndex {
// ...
}What the build generates
.cataract/generated holds three modules, rewritten on every build and safe to delete:
| Module | Contents |
|---|---|
CataractAssets.chpl | The asset lookup, compiled to a jump table |
GeneratedRoutes.chpl | One handler class per route, plus registerRoutes |
CataractMain.chpl | main, the config consts and the middleware stack |
Files that are no longer emitted are pruned, so a stale module cannot survive a rebuild and quietly keep answering requests.
Route and library modules are passed as sources
Routes, layouts and everything under app/lib are handed to chpl as source files rather than through -M, precisely because their module names deliberately do not match their filenames. The runtime is passed as module search paths instead.
Files the scanner ignores
Any name beginning with _ or . is skipped — directories included — and is never scanned or compiled. That makes app/routes/_drafts/ a working area rather than a route.
A directory wrapped in parentheses is a route group: it organises files without contributing a path segment, so app/routes/(marketing)/pricing.chpl answers /pricing.