Documentation

Last updated: 2026-07-28

Downloads & redirects

Beyond rendered pages, a site's site.toml serves two things directly: redirects and file downloads (composed assets). Both are matched before page rendering and are read fresh on every request, so a git push applies changes with no restart.

Redirects

A [[redirect]] maps an exact request path to a target with a 302:

[[redirect]]
from = "/old-page"
to   = "/new-page"
FieldDescription
fromThe request path to match — exact, the whole path
toThe redirect target (a local path or an absolute URL)
  • Matching is exact: one block maps one path. A path that does not match any from is handled normally (page, asset, or 404).
  • Served Cache-Control: no-cache, so a moving target (such as a latest alias) is never cached by clients.
  • to can point anywhere, including another origin.

Example: send downloads to object storage

The download page links to in-domain paths like /dl/latest/qwen3/everlock-linux-amd64v3, and the self-updater polls the same shape. One redirect per file hands those requests off to the release bucket:

[[redirect]]
from = "/dl/latest/qwen3/everlock-linux-amd64v3"
to   = "https://everlock.s3.eu-central-1.amazonaws.com/dl/0.5.0/everlock-linux-qwen3-amd64v3"

[[redirect]]
from = "/dl/latest/qwen3/everlock-darwin-arm64"
to   = "https://everlock.s3.eu-central-1.amazonaws.com/dl/0.5.0/everlock-darwin-qwen3-arm64"
# …one block per published (variant, platform)

A browser and reqwest both follow a 302 transparently — on HEAD as well as GET — so the self-updater still reads the bucket's x-amz-meta-sha256 and Content-Disposition from the redirected response and works without a change. The blocks are mechanical, so they are generated at release time with the current version in each to.

Downloads (composed assets)

An [[asset]] serves a file at a URL with custom response headers. The body is the concatenation of one or more parts — file paths in the store — so a large download is assembled from stored pieces without holding the whole thing in memory.

[[asset]]
url    = "/downloads/tool.bin"
parts  = ["files/tool-v1.bin"]   # one or more store paths, concatenated in order
sha256 = "9aa4c9…"               # optional hex digest of the assembled body

[asset.headers]
content-type        = "application/octet-stream"
content-disposition = 'attachment; filename="tool.bin"'
cache-control       = "public, max-age=31536000, immutable"
FieldDescription
urlThe request path this asset answers
partsStore file paths, streamed and concatenated in order to form the body
sha256Optional hex digest of the assembled body (see below)
[asset.headers]Response headers applied verbatim (minus the reserved set)

How it is served

  • GET streams each part in order with bounded memory — roughly one part in flight — so a multi-gigabyte download costs tens of MB of RAM rather than its full size.
  • HEAD returns the same headers with no body and reads no part bytes; Content-Length is the sum of the parts' sizes (a cheap store lookup). A client learns the size and digest without downloading.
  • When sha256 is set it is emitted as both an ETag (so If-None-Match yields 304) and an X-Everlock-SHA256 header, letting a client compare a stored copy against the current bytes with a single HEAD.

Reserved headers

[asset.headers] are applied verbatim except for the headers the server computes itself: content-length, transfer-encoding, connection, keep-alive, and upgrade. Any other header — content-type, content-disposition, cache-control, … — is yours to set.

Directory listings

Every non-leaf path above the declared assets renders an auto-generated index of its immediate children. Assets at /downloads/a and /downloads/b make /downloads/ list a and b. Drop an _index.md at that directory to render prose above the listing.

Why compose from parts?

For a single file, parts is just its one store path. Multiple parts matter when a large blob is shared across downloads: each part is stored once in Git and reused, so many released binaries that share the same model chunks cost the store only the bytes that actually differ.

Choosing between them

Both can serve a download, so:

  • Redirect when the bytes live elsewhere (object storage, a CDN). The client fetches the target directly and that host owns bandwidth, range requests, and caching.
  • Composed asset when the bytes live in the site's own store and you want Everlock to serve them with a fixed filename, a HEAD-readable checksum, and on-the-fly assembly.
sites downloads redirects config