Pages & routing

The directory is the router. Configuration is only for what can't be inferred.

The tree is the router

An application root is the directory containing crisptastic.toml. Source discovery never follows paths outside it. Routes, assets, partials, error handlers and local defaults are inferred from structure; configuration exists only for facts that cannot be inferred.

Route source files

Source suffixRouteContent type
index.html.crisp/text/html
about.html.crisp/abouttext/html
account/index.html.crisp/account/text/html
api/profile.json.crisp/api/profile.jsonapplication/json
guide/index.md.crisp/guide/text/html (Markdown → HTML)
robots.txt.crisp/robots.txttext/plain

Canonical directory routes end with /. /account may redirect to /account/ with status 308 when only the directory route exists.

Dynamic segments

blog/[slug].html.crisp   →   /blog/:slug

[name] matches exactly one non-empty decoded path segment. Static routes outrank dynamic ones; more static segments outrank fewer; longer routes outrank shorter; remaining ties are compile-time ambiguity errors. Catch-all segments are not in profile 1.

Reserved namespaces

_partials/     private reusable sources
_errors/       private error handlers
_triggers/     private synthetic-event routes
assets/        public build assets
.crisptastic/  local generated state
dist/          conventional build output

Any path segment beginning with _ is private and never becomes a public route, but may be included by public routes.

Route policy

Default methods are GET and HEAD. A route that uses a mutating method must declare it in the manifest, which prevents accidental mutation endpoints:

[routes."/api/profile.json"]
methods = ["GET", "PATCH"]
body = "json"
max_body_bytes = 65536
auth = "required"
capabilities = ["data"]

Unknown policy keys and policies for nonexistent routes are build errors. OPTIONS is host-generated from the method policy.

Assets

Every regular file under assets/ is an asset input. .scss entry files (not beginning with _) compile to .css; Sass partials are inputs only. Other assets are byte-preserving. Every output gets a SHA-256 digest, length and content type; the Capsule stores bytes once by digest and maps public paths to them. Public asset URLs are served from /assets/....

Error handlers

_errors/404.html.crisp
_errors/500.html.crisp
_errors/default.html.crisp

Handlers receive a safe error context, run with a quarter of the render budget, and cannot perform mutating capability operations.

The manifest

crisptastic.toml declares what cannot be inferred: the app identity, minimum runtime version and language profile, deploy authorities and health route, and resource limits.

schema = 1
name = "example"

[runtime]
minimum_version = "0.2.0"
language_profile = 1

[deploy]
authorities = ["example.com", "www.example.com"]
health_route = "/_health.json"

[limits]
render_ms = 5000
response_bytes = 8388608
capability_operations = 32