Skip to content
- ADR 0001 — Hono as the HTTP routerWhy Cusp routes every request through one Hono app inside a single Worker: admin API, headless REST, public render, and a static-assets fall-through→
- ADR 0003 — Auth behind a thin interfaceAuth is reached only through a thin, swappable interface in src/shared/auth/. This tombstone points to ADR 0009, which now carries the substance.→
- ADR 0004 — Admin SPA in React, built by AstroWhy the Cusp admin is a React SPA built by Astro and served as its own static bundle over the ASSETS binding, kept entirely off the Worker bundle→
- ADR 0005/0006 — ULID IDs and Unix-epoch timestampsCusp uses ULID primary keys and INTEGER Unix-epoch-second timestamps to make creation-ordered listings and site-wide time-travel queries cheap→
- ADR 0007 — The versioned-write helper is the only mutation pathEvery mutation of a versioned entity in Cusp goes through versionedWrite(), enforced by a custom ESLint rule and a runtime symbol guard→
- ADR 0008 — Migration runner on first requestCusp applies embedded migrations on the first request after a deploy — idempotent, row-lock coordinated, and recovering automatically from divergent schema state.→
- ADR 0009 — Hand-rolled auth behind the Auth interfaceCusp ships its own Argon2id auth behind a thin, swappable Auth interface: D1 sessions in an HttpOnly cookie, sliding expiry, and rate-limited login.→
- ADR 0010 — Raw D1 prepared statements, not an ORMWhy Cusp accesses D1 through raw prepared statements behind a chunked-write, versioned-write repository wrapper rather than an ORM→
- ADR 0011 — Render adapter and publish-time renderCusp renders pages to R2 at publish time through a stable render adapter; the first-party theme is TypeScript template functions and the contract stays framework-agnostic→
- ADR 0012 — Surrogate-key cache and global cache epochHow Cusp purges cached pages by named surrogate keys and uses a global cache epoch to invalidate the whole cache across colos on a zoneless deploy→
- ADR 0014 — DocumentSession Durable Object lifecycleHow Cusp's per-document Durable Object holds, sequences, hibernates, flushes to D1, and rehydrates collaborative editing state with no CRDT→
- ADR 0015 — Draft and published body coexistenceHow Cusp keeps a document's live body and its in-progress draft in parallel columns, so editing a published page never disturbs the live version and preview shows the draft→
- ADR 0016 — Preview-token signingDomain-locked, single-use HS256 preview tokens for sharing unpublished Cusp content, with a reserved comment-author claim for plugins→
- ADR 0017 — UnpublishDocument workflowUnpublishing a Cusp document 404s the page synchronously, then runs the UnpublishDocument workflow to re-render listings and home, regenerate sitemap and feeds, and purge the cache→
- ADR 0018 — Block model schema and wire protocolHow Cusp models documents: an eleven-type block union, Portable Text inside text fields, per-block schema versioning, a shallow-merge update protocol, and namespaced block types→
- ADR 0019 — Op-protocol additions for the block editorSplit, merge, and transform-type as first-class collaborative operations, plus Cusp's pinned awareness, acknowledgement, and conflict-resolution rules.→
- ADR 0020 — Collections and field-definitions data layerCollections and field definitions form Cusp's dynamic content model — two versioned D1 tables behind one repository pair, with per-field version history→
- ADR 0021 — Schema cache shape and invalidationCusp's compiled content-type schemas live in a KV cache with an ID-keyed record and slug pointer, rebuilt by a repository post-commit hook and self-healing on stale reads→
- ADR 0022 — Document per-field data shapeCusp stores per-field document values in a single JSON column with R2 spillover and versions them in the document's own snapshot, not a normalised value table→
- ADR 0023 — Headless API tokens and dynamic REST shapeBearer cusp_pk tokens with scopes authenticate a REST surface generated from collections and field definitions, documented at request time by /api/v1/_meta→
- ADR 0024 — Field-type migration workflowThe MigrateField workflow changes a field's type on a populated collection in resumable batches, with a dry-run preview and per-document version history.→
- ADR 0025 — Canonical example siteThe Royal Society of Pheasant Patissiers is Cusp's single canonical example site — a discovery aid, demo, and living integration test kept in lockstep with the code→
- ADR 0026 — Admin sessions on api_tokensAdmin sessions and headless API tokens share one table, one middleware, and one verification path; a session is a session-kind token in an HttpOnly cookie→
- ADR 0028 — Theme package format, signing, and installHow Cusp packages, signs, verifies, and installs themes: canonical tarballs in R2, a bundled Ed25519 key registry, and a binding-less loader sandbox→
- ADR 0029 — Collection and document slug patternsCollection and field slugs are snake_case identifiers used in SQL, scopes, and codegen; document slugs are kebab-case URL segments, and the divergence is intentional→
- ADR 0030 — Pre-install public route redirectA fresh Cusp deployment redirects every public GET to /setup until install completes, so the deploy-URL editor lands in the first-run wizard→
- ADR 0031 — Theme-author local install pathpnpm theme:dev uploads canonical tarball bytes to a temporary R2 staging key over a dev-only admin endpoint, reusing the install workflow and verifier unchanged→
- ADR 0032 — Design-token overlay and render-time resolutionCusp stores token overrides as typed settings in a core and a theme-scoped namespace, then resolves them at render into an inline CSS-variable block so the theme stylesheet stays immutably cached→
- ADR 0033 — Customise live-preview transportCusp's customise live preview stores per-actor draft theme tokens in KV, references them with a customise-scoped preview token, and overlays them at render→
- ADR 0034 — Theme marketplace catalogue (superseded)The superseded plan for a hosted theme and plugin catalogue. Superseded by ADR 0044: no marketplace in v1; community packages install by URL.→
- ADR 0035 — Public base URL is a settingCusp's canonical public origin is a versioned setting captured by the first-run wizard and editable in admin settings, not a deploy-time Wrangler variable→
- ADR 0036 — Plugin manifest and capability modelCusp plugins declare a JSON-Schema-validated manifest of capabilities; the host maps each declaration to a scoped binding and grants nothing more→
- ADR 0037 — Plugin storage scopingHow Cusp scopes per-plugin KV, D1, and R2 storage at the binding layer over one shared database, bucket, and namespace, enforced by host-built wrappers→
- ADR 0038 — Plugin hook systemCusp plugins subscribe to a fixed hook vocabulary with deterministic ordering, host-enforced per-call timeouts, and per-subscriber error isolation→
- ADR 0039 — Iframe trust resolution for plugin block renderersPlugin block renderers run server-side in per-plugin sandboxes and emit only sanitised HTML, keeping a plugin's blast radius inside its declared capabilities→
- ADR 0040 — Pruning policies for versioned entitiesCusp's PrunePolicies workflow caps version history per entity type with hard deletes and R2 cleanup, scheduled daily via a self-sleeping workflow→
- ADR 0041 — Site-wide restore workflowHow Cusp's RestoreVersion workflow rolls the whole site back to a timestamp by forward-minting new versions, preserving insert-only history→
- ADR 0042/0043 — Backup and import enginesCusp's ExportBackup writes a verifiable gzipped tarball to R2; ImportContent restores it into a fresh deployment with manifest and per-table integrity checks→
- ADR 0044 — No hosted plugin or theme marketplaceCusp ships no hosted catalogue. First-party packages are bundled in the worker; everything else installs by pasting a signed-tarball URL, with the admin as the trust gate→
- ADR 0045/0046 — Search in core via D1 FTS5Cusp ships keyword search in core on a D1 FTS5 table, with index writes inlined as retryable publish and unpublish workflow steps→
- ADR 0048 — Images in coreCusp handles images in core with a media table, content-addressable R2 storage, and dedup-by-hash — no plugin required for basic image authoring→
- ADR 0049 — Image transformations URL contractHow Cusp delegates image resizing to Cloudflare Image Transformations at the edge — unsigned /cdn-cgi/image URLs, a single enablement setting, and a clean fallback to originals→
- ADR 0050 — Image block and media field wire shapeThe wire shape for the core/image block and the media field on data_json: pick a library row, optionally override the alt text per instance→
- ADR 0051 — SweepMedia workflowSweepMedia reaps soft-deleted media past a 30-day window, but only after a reference scan and a content-hash refcount confirm the bytes are safe to delete→
- ADR 0053 — Headless API explorerCusp's built-in /api/v1/_explorer browses the read-only headless API with the token in the Authorization header — safe by default, with an optional strictly read-only public token for live showcases→
- ADR 0054 — Almanac heritage theme and rich listingsAlmanac is Cusp's bespoke heritage first-party theme for the example site, and the listing render path now threads per-item data so themes can show ranks, rosettes, and recipe meta on index pages→
- ADR 0055 — Site-wide chrome drains every prerenderNavigation, menu, and site-title changes drain the entire R2 prerender prefix and bump the cache epoch, fixing the bug where two pages in a section showed different sidebar menus→
- ADR 0056 — Themed 404 fallback via the page template→
- ADR 0057 — Atomic cursor advance closes the field-migration replay windowThe MigrateField workflow commits each document's conversion and its resume cursor in one D1 batch, so an at-least-once Workflows replay can never re-feed an already-converted value through the conversion rule.→
- ADR 0058 — Security audit remediationDecisions taken while remediating a multi-agent security audit — plugin D1 sandbox hardening, document-ownership enforcement, headless session-token rejection, search-index scope, takedown cache invalidation — and the items deliberately deferred.→
- ADR 0059 — Plugin runtime deferred to v1.x→
- ADR 0060 — The homepage document lives at one URLA Page set as the Cusp homepage is canonical at /: its own permalink 301s there, and the sitemap and RSS feed list it exactly once.→
- ADR 0061 — Theme fallback is observableWhen the Cusp render path falls back to the bundled default theme, it warns and records a self-healing KV flag surfaced on the admin Health and Themes pages.→
- ADR 0062 — Session expiry slides on the bearer-cookie pathBearer-format session cookies now extend their 30-day expiry on use, closing the drift between the documented sliding window and the ADR 0026 api_tokens session path.→