Skip to content

Releases

Release notes for tagged versions of Artist Alley, newest first. Entries are ported from the upstream CHANGELOG.md; see Installing for how to run each release.

Versioning follows the milestone model: v0.1.0 is the first tagged release, v1.0.0 marks out-of-beta. See ADR 0057 for the v0.1 baseline.

VersionReleasedTag
v0.10.2 GitHub
v0.10.1 GitHub
v0.10.0 GitHub
v0.9.1 GitHub
v0.9.0 GitHub
v0.8.0 GitHub
v0.7.0 GitHub
v0.6.0 GitHub
v0.5.2 GitHub
v0.5.1 GitHub
v0.5.0 GitHub
v0.4.0 GitHub
v0.3.1 GitHub
v0.3.0 GitHub
v0.2.0 GitHub
v0.1.2 GitHub
v0.1.1 GitHub
v0.1.0 GitHub

Generated from the GitHub releases API, refreshed every six hours. Notes for each version follow below.

Released 2026-08-18. Seed coverage for mature content, and a cover editor that uses its room.

The sample library can finally show the mature-content controls working. Those controls shipped in v0.10.0 — an artist marks a work, each account opts in or out, the instance has a master switch, and work you have not opted into is simply absent rather than blurred-and-teasing. But nothing in the sample library was ever marked, so on a fresh install the whole system was invisible. Twelve public-domain classical works are now labelled — the kind of fine art a museum genuinely flags — and the labelling is a required part of the test fixtures, so it cannot quietly disappear again.

The collection cover editor spends the space it was given. Choosing a cover used to mean peering at one clipped row of pictures inside a dialog that left half its height empty; now the picker fills the room, and the crop area grows once a picture is chosen.

Released 2026-08-18. The listening release: two days of real use, and everything it turned up.

Nothing in this release came from a plan. It came from working in the app and writing down what got in the way — thirty fixes and refinements across search, browsing, collections and accessibility.

Search stops guessing at what you meant. Typing no longer re-runs the search under you: suggestions appear as you type, results change when you press Enter. A suggestion never offers a word that finds nothing, because suggestions are now drawn from the same rule the search itself runs. Advanced search dropped its developer vocabulary and copes with real catalogues — a field with thousands of values becomes a type-to-filter box rather than an endless wall of chips.

Browsing keeps up. Endless scrolling now loads far enough ahead that fast scrolling never lands on blank space — the trigger had been watching the wrong thing entirely, so its head start never applied. Grid tiles ask for a picture sized to the tile instead of stretching the smallest one. The sort control gained a type filter that looks inside posts, so a post carrying an ebook answers the ebook filter even when its cover is a painting; a pack whose contents are all one kind wears that kind’s icon.

Visitors can browse public work. Marking a post public had never actually worked — the option was there, the server refused it. Now it works, instances that allow anonymous browsing serve public work to visitors with every privacy rule verified on that path, and signed-in members see public work in their own feed instead of only their organisation’s.

Collections hold posts. Loose files stay in your own space until you make them into a post. Collection covers grew up: one cover for the collection card, a different one for the featured strip, each positioned by dragging a crop box with zoom so an off-centre subject can be framed — and the picture can come from the collection, from your files, or from an upload you do right there. Editing it all happens in one dialog with pages, not a window on top of a window.

Every menu works from the keyboard. Several menus, including sign-out, could not be reached by keyboard at all. They can now, and a test walks the page to keep it that way. Spatial tools that genuinely need room say so on small screens instead of cramming.

Released 2026-08-16. The browse experience release: search sealed, the wall rebuilt, every view given its own feel.

The browse wall no longer improvises. The masonry view computes every tile’s placement deliberately — no more growing gaps, no losing your place when more work loads in, no reshuffling under your cursor. Featured collections ride a wide slider at the top at a fixed, designed size, and operators can place a full-width promo band in the feed, aimed at an audience of their choosing.

Every view mode has its own identity now. Grid is a visual wall that shows details when you hover — the artist, the work’s title, what kind of asset it is. Thumbnails are a working surface with visible controls. List is for metadata, with resizable columns. The feed is for reading. Each is tuned as its own thing rather than one layout stretched four ways.

Mature content is a choice at every level. Artists mark a work with one checkbox at upload. Every account chooses whether to see marked work; the operator chooses whether the instance allows it at all. The rule follows the work everywhere it echoes — previews, collection covers, counts, featuring — and being an administrator is deliberately not the same thing as opting in.

Teams and tags became ways to read the feed. A rail above browsing filters the feed in place by team, tag follows work the same way, and the rail is yours to curate.

Selection works like a desktop. Drag a box around tiles, shift-click a range, and act on all of it — in every view, including inside collections.

Search stopped leaking what it hides. A work you are not cleared to see no longer answers text queries, suggestions, similarity matches, or counts through its withheld title. The entire family of side channels was closed — including one that mainstream search engines still document as a known limitation.

Released 2026-08-12. A security patch, and nothing else.

A YAML parser bundled deep inside the 3D preview tooling had a flaw that let a malformed document burn CPU. Nothing in the product fed it untrusted input, so there was no way to reach it — but the vulnerable copy was inside the published image, and anyone scanning that image would see it. It is now the fixed version.

No functional changes.

Released 2026-08-11. Permissions became one rule, deleting became reversible, and the surfaces that were only half there got finished.

Being allowed to change something no longer implies being allowed to see it. A team lead can correct a title without being cleared for the artwork behind it. In the same pass, editing and deleting a file gained the ownership check they had been missing entirely — which is also what made team-scoped content management possible, so a studio lead can manage their team’s work without administrator rights.

Deleting is reversible, and visible. Every account has a trash page listing what it deleted and how long is left to recover it. Deleting anything offers Undo. If someone else removed your work, you can ask for it back — and only the person who deleted it, or an administrator, can decide.

The feed is a real feed. Feed view now shows who made each post, the image at its own shape rather than cropped square, and like, comment and share where you would expect them. Reacting works from the feed, and the count moves when you press it.

Operators choose which browse layouts their install offers. Grid, masonry, thumbnail, list and feed were shown to everyone, always. An operator can now pick — and anyone already using a layout that gets turned off is moved to one that works, keeping their old choice in case it comes back.

The control bar comes back when you reach for it. The layout and sort controls slide away as you scroll and used to return only when you scrolled back up. Moving the pointer toward them brings them back.

You can save someone else’s post to your own collection. Collections could already hold other people’s files; posts were the missing half. What lands in your collection is a reference to their post, not a copy, and it changes nothing about who can see it.

Studios have a home page, and you can follow them. Plus a page per metadata field for operators, an edit page for files, the interface language applying the moment you sign in, and one keystroke meaning one action across the viewer.

Underneath, the image pipeline stopped running out of memory — measured rather than guessed at, with the identical workload going from being killed at its ceiling to finishing with room to spare at no cost in speed.

Released 2026-08-03. Operator configuration — the admin config spine: an operator can now shape metadata, wording, and email without forking or restarting.

  • Controlled vocabularies are editable, and they can grow. The options behind a select or hierarchical field are editable in place, and two fields — Keywords and Country — are now open vocabularies: a term that does not exist yet is minted the moment you type it, and keywords are also learned straight from the metadata inside uploaded files. New terms reconcile behind the scenes rather than adding an upload-time decision.

  • A field can be a hierarchy, with a tree editor. country ships with 24 nested regions, and the nested terms of any hierarchical field are now editable through a dedicated tree editor rather than a flat list.

  • Rich-text fields render as formatted text. rich_text is a first-class field type, sanitised on the way in and on the way out, so a formatted description survives a round trip without becoming an attack surface.

  • Any wording the interface ships with can now be changed without forking. Admin → Content → Site text lets an operator override the copy the interface ships with; the override applies on this instance and any instance sharing the database, with no restart.

  • The emails this instance sends can be rewritten without forking. Admin → Content → Email templates lists every transactional email with its shipped subject and body, an editor, the exact fields each email exposes, a sandboxed live preview, and Revert.

  • Field administration is a grantable capability. fields.admin now exists as a real capability and is granted to the built-in Admin role, so an operator can delegate creating, editing, and deleting field definitions without handing over the whole install.

  • Operators can set their own instance logo, and profiling can be turned on when something needs investigating (AA_PPROF_ADDR).

  • SSO provider credentials are no longer readable. The admin auth endpoint used to return each provider’s whole configuration blob — including the OAuth client secret, the LDAP bind password, and the SAML private key — to any capability that could read system config. Those three are now write-only, and the config shape is a closed, typed, per-kind schema rather than a free-form map a future credential could hide in. The AI provider record was closed the same way.
  • Internal release numbers no longer show up in the interface. The muted “Phase 1.X” markers and coming-soon labels that leaked internal identifiers have been replaced with plain language.

  • The browse feed’s “Team” and “Trending” buttons are gone, folded into the filter.

  • Re-seeding an instance no longer serves stale data until a restart. A seed run now broadcasts a cache flush every running instance honours, so a reseed is visible immediately.

  • Plus a long tail of correctness fixes: dates no longer land a day early, out-of-range field values are rejected instead of silently stored, an upload no longer reports success when the server refused its metadata, portrait photos and videos stop being laid out as landscape, hierarchical and yes/no fields work end to end, masonry respects each tile’s aspect ratio, nginx stops routing to a dead container after a recreate, and 3D models render with their textures (GLB, FBX, and the seed catalogue’s missing maps).

Released 2026-07-28. Browse correctness, visibility security, and a real seed catalogue.

Five separate leaks, found in one week, all the same underlying mistake: a read path that wrote out the “who may see this” rule itself instead of asking the one component that owns it. Each copy was correct when written; the shared rule moved and the copy didn’t. None was caught by a test.

  • Private posts were readable by anyone signed in. Adding a visibility=private filter to the post list returned other people’s private posts — title and body — while opening the same post directly correctly refused. No special role was needed. The list and the single-post view now run the same rule, so they cannot disagree again, and a test enumerates the visibility tiers from the database itself so a tier added later is covered automatically.
  • One collection route had no permission check at all, returning a collection’s name, description and full member list to any signed-in caller.
  • A tag filter exposed unpublished work. On an install with public browsing enabled, adding a tag filter returned draft and archived assets that the unfiltered browse correctly hid.
  • Search was broken for every signed-in user — an internal error on every query, because the search still asked for a column that had been removed.
  • Session IP addresses became a separately granted permission, matching how the audit log already treated them.
  • The server image is half the size: 3.64 GB → 1.82 GB. Blender is no longer packaged — it was roughly a third of the image, plus the ten X libraries it loaded at startup, and nothing in the product invoked it any more: every 3D format in the reference catalogue already rendered through the three.js worker. Formats with no three.js loader (.blend, .usd*, .abc, .x3d) get no generated thumbnail for now — the file still uploads, downloads and serves normally — and regain one when the Blender converter ships as an optional plugin. Nothing to do on upgrade; no configuration changed. arm64 deployments are unaffected: they never had Blender.

Cards render correctly end to end. Tiles follow their image’s true proportions instead of being squared off; the masonry wall stops reshuffling tiles you are already looking at each time more results load; every asset type now fades up from a blur instead of flashing blank, including audio, 3D, video, fonts and ebooks, which previously had no placeholder at all; thin audio tiles keep their controls inside the tile, with the rest of the detail moved to a tooltip that follows the cursor; and cards stop downloading images larger than the space they are drawn in.

Assets with no preview picture — text files, documents, or a preview that simply failed — get a designed tile stating the file’s format and kind, rather than an anonymous “image missing” glyph.

Form controls drew their border in the same colour as a divider rule, measuring well below the WCAG 2.2 contrast floor for a control boundary in both themes. They now clear it. Strengthening the resting border would have made the focus indicator invisible on 122 of those controls, so focus moved to a standard 2px ring.

The bundled demo library nearly doubled, from 1,007 to 1,946 assets, and every studio in it now has real work to show — two had none at all, while one held nearly half of everything. Provenance is recorded per record so any item can be traced to its source and re-fetched.

Public profiles, one viewing experience everywhere assets are shown, and a faster 3D preview pipeline.

  • Public profile pages. Every user now has a profile page — reachable by username or by a stable ref — showing their display name, avatar, and the assets, posts and collections a viewer is allowed to see. It reuses the same visibility rules as the rest of the site: anonymous visitors see only public work, and only when public mode is on, and an owner can opt out of anonymous exposure. This also cleared the last of the dead author and similar-asset links (#478).
  • Shared view controls everywhere. The browse view switcher (grid, masonry, thumbnail, list) and sort direction now appear on the profile and post-by-asset pages too, not just the main browse — one consistent control bar wherever assets are shown (#511).
  • Faster 3D previews, and multi-file models fixed. Open-format 3D previews (glTF/GLB, FBX, OBJ) now render through a headless three.js worker instead of Blender — much faster, and arm64 deployments get 3D previews for the first time (the Blender path was amd64-only). A multi-file glTF model — the model file plus its external data and textures — now renders correctly where it used to fail silently. Blender stays as an automatic fallback (#497, #498, #507, #508, #486).

Under the hood: a large CI-reliability and test-isolation hardening pass. Not user-facing, but it is why these shipped green.

Read-only viewers see the whole catalogue. The public demo login used to hit blank “Preview unavailable” tiles on anything above the lowest tier; now it sees every tier of content.

  • A read-only content capability (#474). A new content.read.all grant lets a role read asset content at every sensitivity tier — and nothing else. It opens no admin surfaces and permits no writes, so the public demo viewer can browse the full catalogue without being an administrator. Granting it to a role is a deploy-side step (ADR 0060).

Promoted all of dev since v0.5.0 — a patch version number, a substantial release. Two demo-surfaced fixes, a visibility-consolidation batch, and the accumulated foundation work.

  • Shareable, reloadable asset pages. Assets now have a real /assets/[id] page, so a link to an asset opens, reloads and shares correctly. Before this, clicking an asset inside a collection dead-ended on a “Not found” page — the tile linked to a route that never existed (#475). A build-time link-integrity check now guards against dead internal links (ADR 0068).
  • 3D previews work on published builds again. Turntable thumbnails for 3D models (glTF / OBJ / FBX and more) had silently stopped generating on released images — the published image shipped without the renderer, so every 3D asset showed no preview (#470). Fixed for amd64, with a build-and-render smoke so it can’t regress unnoticed.
  • Audit-log retention and export. The audit log now has a retention policy — configurable per event category (a 7-year default, with shorter or longer holds per category), a legal-hold flag that exempts individual events from purge, and a nightly enforcement pass. A GDPR erasure request anonymises a user across the log — the events are kept, the person is replaced by a deleted-user placeholder — so the trail survives without the personal data. The whole log can be exported as CSV or NDJSON over a date range, streamed so exports of millions of rows don’t exhaust memory; IP addresses are withheld from the export for callers who can’t see them in the live view.
  • Scheduled actions. Operators can now schedule a change to run at a future time — change an asset’s sensitivity, soft-delete, change state, or notify — and cancel it before it fires. Each action executes atomically with its audit entry, so it either fully happens and is logged or fully does not; a failure is recorded rather than half-applied. This is the generic engine (ADR 0020); the asset-gating features that use it — blur, reveal, timed embargo lift — land in later sprints.

Fixes: content-visibility hardening — soft-deleted collections no longer appear to signed-in non-owners, and the IIIF image path enforces the same visibility rule as the browse grid (#451, #460), plus audit and admin-gating cleanups (#458, #431).

Public mode: content is now reachable without an account, on an operator’s terms. The visibility model gained a single enforcement point, sensitivity moved to the content plane, and opening the surface surfaced and closed three pre-existing access holes in the foundation beneath it.

  • Public browsing is an operator choice, off by default. Anonymous access had no switch — any instance served its public content to the internet whether the operator wanted it or not. There is now a setting, enforced at the API rather than by hiding pages: turning it off means anonymous requests are refused, not merely unlinked. A fresh install starts private, and first-boot, login and SSO all keep working with it off.
  • One place decides visibility. A public tier for collections and posts, and a single visibility predicate every read path splices in (ADR 0063). Anonymous callers see published, public, ready content only. Browsing without an account now works — GET /assets, /assets/{id}, /collections, /collections/{id} and public image bytes all serve anonymous requests; every write path still requires authentication.
  • Sensitivity moved to the content plane. Byte-streaming previously checked only that a caller was signed in, so any authenticated account could download draft or restricted material. Sensitivity now gates content: team needs membership, restricted/embargo are owner-and-admin only, across originals, derivatives, HLS segments and archive entries. Listing is deliberately unchanged — restricted assets stay visible as locked items rather than vanishing (ADR 0064, following ADR 0020). Denials return 404, not 403, so a response cannot confirm a hidden asset exists.
  • A logged-out visitor has something to look at. Curated content can be featured for a public audience and the front page renders it. Featuring is now a placement, not a flag — the same collection can be featured publicly and internally at once, each with its own order, and an asset can be featured without wrapping it in a collection. It never widens access: a featured item renders only if the viewer could already see it.
  • Audit-log IP addresses are gated behind their own capability. Seeing what happened and seeing from where are now separate grants: system.audit.read returns the log without IPs, and a dedicated system.audit.pii.read is required to see them. The address is withheld at the API, not merely hidden in the UI.

Three pre-existing holes closed while opening the surface: the two asset and collection detail endpoints checked only that some caller was signed in, so any account could read another user’s private item by id; the collection list applied no visibility rule at all; and collection-contents enumeration was unchecked. All now run the same visibility decision.

Operator visibility: the async pipeline and the storage layer are now observable and manageable from the admin surface.

  • Jobs admin. The whole async pipeline (derivatives, previews, AI tagging, federation outbox) previously could only be inspected with psql. New surfaces — queue (by status/type with age and priority), workers (lease state, stale-lease flag), live, failed (with last_error), kinds (per-type concurrency) and schedules — read-gated on system.jobs.read so a read-only operator can watch without holding system.admin. Requeue, cancel and concurrency edits require system.admin; a currently-running job is never touched by either.
  • Storage admin. Usage (deduplicated bytes on disk, originals vs derivatives, broken down by content type and backend) and variants (per-family inventory), read-gated on the new system.storage.read.
  • Storage integrity sweeps. orphan_scan reconciles the object store against the database in both directions; checksum_verify re-hashes stored bytes against the content-addressed key. Both run as batched, resumable job kinds and report into an admin surface. Findings are advisory — no destructive cleanup ships in this release.
  • About reports the real version, read from a new anonymous GET /build-info endpoint instead of a hard-coded placeholder; the displayed licence was corrected to AGPL-3.0-only.
  • Help is visible to read-only operators — documentation, shortcuts, about, release notes and support are explicit public admin tiles, identical on desktop and mobile (ADR 0061).

Infrastructure: storage backends gained an ordered, cursor-resumable List (ADR 0062); Dependabot grouped per ecosystem so routine bumps stay auto-mergeable; a pre-checkout stale-.git-lock sweep fixed intermittent self-hosted checkout failures.

Admin read-cap UI + foundation cleanup.

  • Admin UI for read-cap holders. The frontend half of v0.3.0’s read capabilities: the admin menu and route guard now gate per tile on the capability each surface actually enforces, so a read-only role (without system.admin) sees and can browse the sections its capabilities permit. The backend still enforces every write.

Infrastructure: repo-wide gofmt normalisation behind a gofmt -l CI gate; a make release target codifying release prep (version bump, OpenAPI regen, drift check, promotion PR) without tagging; Dependabot github-actions group split; the steel secondary token wired into the Alert info tone.

Derivatives, read-only admin, responsive UI.

  • Media derivatives generated on seed/upload. aa seed and the upload path now produce col / hires / screen thumbnails plus sprites.jpg video hover-scrub sheets — the browse grid renders real thumbnails instead of 404ing, and videos get a slideshow preview.
  • Read-only admin access. A role can hold *.read admin capabilities and browse the admin surface without the system.admin superuser cap — six previously superuser-only surfaces (activities, featured, license, metadata-extraction, federation, requests) now render read-only.
  • Responsive + accessible UI. Browse and navbar are fluid from a 390px phone to a 3840px / 32:9 ultrawide — an auto-fill grid where size is the lever and column count is the outcome (no breakpoint cliffs), an Instagram-style single-column feed view, hide-on-scroll chrome, and WCAG 2.2 AA target sizing on coarse pointers. Desktop layout unchanged.
  • Featured content curation is seeded, so the admin Featured rail and the public collections featured tab both show content on a fresh seed.
  • Operator-bug fixes. PATCH /admin/system/site now merges instead of blanking omitted fields (updating base_url used to wipe the site name); unroutable file extensions no longer mint guaranteed-terminal preview jobs.

Infrastructure: a CI/nightly stability arc (per-run compose isolation + resource caps, five stacked shared-daemon/host causes fixed) left the federation nightly green for the first time since 2026-06-21.

Admin surface unlock + public demo.

  • Admin tiles unlocked (Tier 1–2). The admin surface is now fully navigable: audit-log viewer (/admin/audit), per-user active sessions plus capability grants/revokes, resource requests, trash with soft-delete restore across assets/posts/collections, system log, and an API explorer served from the Go binary (/api/v1/openapi.json, replacing the external-spec fetch).
  • AA_DEMO_MODE. Env-gated demo mode — a demo/demo credential hint and fill button on the sign-in screen, plus a read-only banner when signed in as the demo user. Off by default; zero footprint on real installs.
  • Public read-only demo at demo.artist-alley.org — runs the release image behind a write-blocking nginx edge, seeded from the Layer-A dataset, and auto-redeploys on each release.

Patch release: brand palette, job/queue fixes, dependency majors.

  • Burnt/Steel repalette (AA-verified) with the finalised chevron brand mark, the configured site name honoured throughout, and a favicon viewBox fix so the tab icon renders.
  • Per-type job concurrency caps are now applied in the single-process worker pool (#278).
  • Saved-search hot loop fixed — the notify coordinator now grid-aligns reschedules instead of spinning (#292).
  • Dependency majorspdfjs-dist v6, three.js r185, dead model-viewer removed, pins moved off latest; supply-chain forks retargeted from mscrnt/* to Artist-Alley-Org (#286).
  • API docs gained a usable getting-started and clean error documentation, and dropped internal phase codes.

Patch release. Fixes the background-job processing outage from v0.1.0 plus release-pipeline and dependency hygiene. Docker-only, multi-arch (amd64 + arm64), Sigstore-signed.

  • Media processing restored — the in-process worker pool never claimed jobs on a fresh install, so thumbnails, previews, transcripts, and search embeddings never generated. Fixed. (#279)
  • Release image publishing fixed — the org rename left the container-image owner with capitals, which is an invalid lowercase-only OCI tag; edge and release image builds failed. Corrected. (#280)
  • Dependency security cleanup — bumped every open advisory in the shipped artifact (golang.org/x/net, DOMPurify) and the optional CLIP sidecar (torch, Pillow, python-multipart), clearing all open Dependabot alerts. (#281, #283, #284)

The first-ever public release — the transition from pre-tag development to a versioned baseline (RS-derived code removed, AGPL-3.0 relicense, core feature set in place).

Pulled from the roadmap’s Shipped foundation set:

  • Single-binary deploy. One Go server with the SvelteKit SPA embedded via go:embed; Postgres + a storage volume (filesystem or any S3-compatible bucket — AWS / R2 / B2 / MinIO). Goose migrations run on boot.
  • Identity & auth. Sessions, scoped API tokens, roles & capabilities, password policy, and an SSO provider-config UI (LDAP / SAML / OAuth enforcement lands with Phase 1.18).
  • Upload → posts → collections. Drag-anywhere upload with a background queue, per-row tags + per-asset metadata, three post-composition modes, and separate cover thumbnails. Posts wrap assets; collections wrap posts; full-text search spans all of it.
  • Admin-extensible metadata (Phase 1.9). Operators define typed custom fields per asset-type and per collection, with per-field capability gates and audit history (ADR 0012).
  • Browse & review. Grid / masonry / thumbnail / list feeds with a sortable spreadsheet view; a post detail modal with multi-asset scroller, comments, likes, and a dedicated review canvas (zoom / pan / tile).
  • Universal asset viewer (Phase 1.18). One Svelte shell hosts per-kind bodies — image, video, audio, PDF, font, 3D — over a shared anchor model, with universal pan/zoom, fullscreen, and jump-to-frame.
  • Format coverage. Images (PNG / JPEG / WebP + HDR / EXR / Radiance), HLS video with frame-accurate scrubbing, audio waveforms, multi-page PDF, font specimens, and native 3D viewers (glTF / GLB / OBJ / FBX / .mview) with Blender-rendered turntables for heavy formats.
  • Federation v1 — ArchivePub (Phase 1.22). The reference implementation of ArchivePub, the walled-garden federation protocol built on the ActivityPub data model: per-actor inbox/outbox, Ed25519 signed envelopes, share-list access control, a delivery worker, and an admin queue. Encrypted-federation arc complete; spec at v1.0-rc1. The first federated DAM, open-source or commercial (ADR 0043).
  • Admin & account shells. A 13-section capability-gated admin menu with a Scalar-embedded API explorer and real config surfaces (site, SMTP, auth, AI providers, appearance); an account shell with profile, theme + language preferences, and API-token management.
  • Theme & i18n. M3-shaped light + dark palettes with admin-configurable font slots; per-user language preference with English shipped and Spanish + French stubs in the picker.

AGPL-3.0-only, dual-licensed with a separate commercial license — the relicense from BSD-3 shipped ahead of the tag (ADR 0016).