File-system routes
Literal segments, index files, route groups and skipped names.
The scanner walks app/routes, turns each .chpl file into a path pattern, reads the module to decide whether it is a page or an API route, and records the result in a manifest that codegen consumes.
Literal segments
Directory and file names become path segments verbatim. routes/guides/deploy.chpl answers /guides/deploy. The extension is stripped; nothing else about the name is transformed.
Index files
A file named index.chpl contributes no segment of its own, so it answers the path of its directory:
routes/posts/index.chpl -> /posts
routes/posts/[id].chpl -> /posts/[id]Route groups
A directory wrapped in parentheses organises files without appearing in the URL:
routes/(marketing)/pricing.chpl -> /pricing
routes/(marketing)/changelog.chpl -> /changelogGroups are for keeping a large routes/ tree readable — a marketing group, an admin group — without that structure leaking into the addresses users see.
Skipped names
Any file or directory whose name begins with _ or . is skipped entirely. It is never scanned, never compiled and never routed:
routes/_drafts/unreleased.chpl never built
routes/.scratch.chpl never builtThis is the mechanism for partial work: an incomplete route can live in the tree without breaking the build.
Duplicate routes are a build error
Two files that resolve to the same path and the same method set stop the build with both source paths named. The same path with disjoint method sets is allowed, and the method masks merge so that a 405 still reports an accurate Allow header.
Inspecting the table
cataract routesmatch order (most specific first)
api /api/search GET ./app/routes/api/search.chpl
page /docs/[...path] GET ./app/routes/docs/[...path].chpl
api /docs GET ./app/routes/docs/index.chpl
page /[...path] GET ./app/routes/[...path].chpl
page / GET ./app/routes/index.chplThe command runs the scan without invoking chpl, so it answers "what will this tree route?" in well under a second.