• v3.9.1 97e88ae2a0

    v3.9.1
    Some checks failed
    CI / Backend lint (ruff) (push) Successful in 58s
    CI / Docker image build (push) Successful in 1m9s
    CI / Frontend tests, audit, and build (push) Successful in 1m54s
    CI / Bot tests and audit (push) Successful in 2m11s
    Release / Create Forgejo release (push) Failing after 39s
    Release / Build and push versioned images (push) Successful in 1m20s
    CI / Backend migration, tests, and audit (push) Successful in 5m10s
    Stable

    claude-bot released this 2026-07-19 01:02:04 +00:00 | 2960 commits to main since this release

    Game-Aware Systems polish: round-trip your stat blocks, and fix them in review.

    Fixed

    • [webapp] Stat blocks survive export/import — a campaign's structured stat
      blocks were silently dropped when the campaign was exported and re-imported;
      they now round-trip intact (and bundles from before v3.9.0 still import
      cleanly). (#214)

    Added

    • [webapp] Edit stats during draft review — when reviewing a generated or
      converted stat block, a GM can now correct individual stat values inline
      (schema-validated) before approving, instead of only approving as-is or
      re-running the LLM. (#213)
    Downloads
  • v3.9.0 861e70a056

    v3.9.0
    Some checks failed
    CI / Docker image build (push) Successful in 42s
    CI / Backend lint (ruff) (push) Successful in 49s
    CI / Frontend tests, audit, and build (push) Successful in 2m11s
    CI / Bot tests and audit (push) Successful in 2m12s
    Release / Create Forgejo release (push) Failing after 18s
    Release / Build and push versioned images (push) Successful in 25s
    CI / Backend migration, tests, and audit (push) Successful in 4m58s
    Stable

    claude-bot released this 2026-07-18 19:41:35 +00:00 | 2963 commits to main since this release

    Game-Aware Systems: Quest Board now understands your game system.

    Campaigns can link to a first-class registry of TTRPG systems instead of only
    free text — unlocking richer AI context, versioned schema-validated stat blocks,
    a typed stat-block editor, schema-targeted generation, and an opt-in wizard to
    backfill structured stats from existing entries. Everything is opt-in and
    reversible: free-text campaigns behave exactly as before. Foundation for the
    upcoming FoundryVTT integration. Ships four Alembic migrations. No API contract
    change — BOT_CONTRACT_VERSION stays 1.

    Added

    • [webapp] Game system registry — link a campaign to Dungeons & Dragons 5th
      Edition, Pathfinder 2e, or a system-agnostic "Generic" (or keep free text). A
      registry selector on the create and settings forms, plus a one-click "this
      looks like Pathfinder 2e — link it?" nudge for campaigns whose free text
      matches a known system. Linking never discards your free-text value. (#133, #135)
    • [webapp] System-aware AI — for a linked campaign, session summaries, name
      suggestions, and lore extraction now get real system-specific context (e.g.
      Pathfinder's ancestry/heritage/class vs. D&D's classes and ability scores)
      instead of a bare system name. Free-text campaigns produce byte-for-byte
      identical prompts. (#137)
    • [webapp] Structured, schema-validated stat blocks — versioned per-system
      stat schemas (D&D 5e and PF2e ship v1 schemas for NPCs and creatures) and a
      validated stat envelope on wiki entries, with a typed stat-block editor
      (grouped, per-field-type inputs) on NPC/creature articles and an infobox
      projection. Validation is server-authoritative; stat blocks are GM-only by
      default and snapshotted into version history. (#139, #140)
    • [webapp] Schema-targeted stat generation — the one-click "Generate stat
      block" now produces schema-valid structured stats when a system is linked
      (validating with one retry, and falling back to the free-form generator
      otherwise). (#142)
    • [webapp] Stat conversion wizard — a GM-driven, reviewed, append-only
      wizard that maps an existing NPC/creature's free-form text into a structured
      stat block via the LLM (map, not invent — with per-field confidence and
      source), driven from a per-campaign "review all" queue. Your original prose
      and notes are never rewritten. (#145)
    Downloads
  • v3.8.0 1ca68d2885

    v3.8.0
    All checks were successful
    CI / Docker image build (push) Successful in 11s
    Release / Create Forgejo release (push) Successful in 13s
    Release / Build and push versioned images (push) Successful in 24s
    CI / Backend lint (ruff) (push) Successful in 3m9s
    CI / Frontend tests, audit, and build (push) Successful in 3m52s
    CI / Bot tests and audit (push) Successful in 6m20s
    CI / Backend migration, tests, and audit (push) Successful in 8m16s
    Stable

    claude-bot released this 2026-07-18 09:11:29 +00:00 | 2982 commits to main since this release

    Privacy & data lifecycle: you control what's kept, and for how long.

    Configurable retention, per-player erasure, account deletion, and a completed
    audit log — the data-lifecycle groundwork a privacy-respecting (and hostable)
    deployment needs. Ships four Alembic migrations. No API contract change —
    BOT_CONTRACT_VERSION stays 1.

    Added

    • [webapp] Configurable data retention — instance-wide defaults plus
      per-campaign overrides for how long raw audio and transcripts are kept. The
      recommended posture is transcript-only: raw voice recordings are deleted right
      after they're transcribed, and never-approved sessions can no longer hoard
      audio forever. Transcripts can optionally expire after N months (clearing the
      text + search index; summaries and wiki entries are untouched). (#119)
    • [webapp] Per-player erasure — a GM or admin can scrub a departed player's
      contributions from a campaign: their transcript lines become [removed] (the
      timeline stays readable and their words become unsearchable), their voice
      recordings and attributed quotes are deleted, and affected sessions show an
      erasure notice. (#118)
    • [webapp] Account deletion — self-service (Profile → Delete account) and
      admin-initiated. Your memberships and personal data are removed; authored
      content is anonymized to "Deleted user" so campaigns stay intact. You're
      blocked (with guidance) if you're the sole GM of a campaign, and prompted to
      export your data first. Deletion is local-only — signing in again starts a
      fresh, empty account. (#117)
    • [webapp] Audit log — the admin audit log now covers destructive and
      administrative actions with campaign scoping and target identification, a new
      filterable Audit log admin view (by actor, event, campaign, date), and
      automatic pruning after a configurable window. (#120)
    Downloads
  • v3.7.0 8ca61c8df8

    v3.7.0
    All checks were successful
    CI / Docker image build (push) Successful in 42s
    CI / Backend lint (ruff) (push) Successful in 50s
    Release / Create Forgejo release (push) Successful in 23s
    Release / Build and push versioned images (push) Successful in 30s
    CI / Frontend tests, audit, and build (push) Successful in 1m44s
    CI / Bot tests and audit (push) Successful in 2m2s
    CI / Backend migration, tests, and audit (push) Successful in 9m22s
    Stable

    claude-bot released this 2026-07-18 05:05:36 +00:00 | 2997 commits to main since this release

    Table Tools: projecting the recording → recap → wiki pipeline onto new
    player-facing surfaces.

    Loot & XP tracking, a player-visible quest log, a session quote board, attendance
    auto-fill from recordings, LLM session-title suggestions, one-click NPC/creature
    flesh-out, and a "Previously on…" pre-session recap. Ships five Alembic
    migrations. No API contract change — BOT_CONTRACT_VERSION stays 1 (every bot
    change this release was purely additive).

    Added

    • [webapp] Party loot ledger + XP & gold tracking — track who's carrying
      what, party XP (pooled or per-member), and a running gold ledger, per campaign
      and per session. Optional "players can add entries" setting; loot can be
      transferred between members and the party pool; everything round-trips through
      campaign export/import. (#112)
    • [webapp] Player-visible quest log — GM plot threads gained a status
      (rumored/active/completed/failed/abandoned), a player-visibility flag, and a
      player-facing summary, so a curated "Quests" view appears on the campaign page
      and via a new /quests bot command — while GM notes stay private. (#115)
    • [webapp] Quote board & session highlights — memorable quotes and key
      moments are extracted from each recording's diarized transcript (hallucinated
      quotes that don't match the transcript are dropped), reviewed by the GM, and
      published to a per-session Highlights panel and a campaign-wide quote board.
      The bot can echo the top quote to Discord on summary approval. (#116)
    • [webapp/bot] Attendance auto-fill from recordings — after a session is
      processed, Quest Board proposes attendance from who was in voice (spoke vs.
      present-but-silent), which the GM confirms in one click; unlinked speakers are
      surfaced, never auto-applied. A propose / auto_apply / off campaign setting;
      manually-set attendance is never overwritten. (#114)
    • [webapp] Thematic session-title suggestions — after each transcript
      approval, Quest Board pre-generates a few on-theme next-session titles in the
      background, offered as instant one-click chips when scheduling (no LLM wait).
      GM-only manual regenerate. (#23)
    • [webapp] One-click "Flesh out" NPC/creature entries — "Generate backstory"
      and "Generate stat block" actions on NPC/creature wiki articles, produced as
      reviewable drafts on the existing LLM draft rail. Append-only (never overwrites
      GM prose), stats are generated coherently from the backstory, and generated
      stat rows are hidden from players by default until the GM opts them in. (#130)
    • [webapp/bot] "Previously on…" pre-session recap — the final pre-session
      Discord reminder now carries a recap: the last approved session's summary plus
      a few open player-visible quests. Campaign toggle (default on); skipped
      automatically until a session has been approved. (#110)
    Downloads
  • v3.6.1 2a404adcea

    v3.6.1
    All checks were successful
    Release / Create Forgejo release (push) Successful in 21s
    CI / Docker image build (push) Successful in 38s
    CI / Backend lint (ruff) (push) Successful in 40s
    Release / Build and push versioned images (push) Successful in 27s
    CI / Bot tests and audit (push) Successful in 1m52s
    CI / Frontend tests, audit, and build (push) Successful in 4m3s
    CI / Backend migration, tests, and audit (push) Successful in 7m5s
    Stable

    rbrooks released this 2026-07-17 22:40:29 +00:00 | 3022 commits to main since this release

    Patch: make the calendar feed reachable behind nginx.

    Fixed

    • [ops] The iCal calendar feed (#107) is now proxied to the backend. The
      feed lives at the app root (/calendar/feed/{token}.ics), but nginx only
      proxied /api, /auth, /public, and /media — so the feed URL fell
      through to the SPA catch-all and returned the app HTML instead of the
      calendar. Added a location /calendar/ proxy block. (Caught on the dev
      deploy before v3.6.0 reached production.)
    Downloads
  • v3.6.0 314ffbc80d

    v3.6.0
    Some checks failed
    CI / Docker image build (push) Successful in 18s
    Release / Create Forgejo release (push) Successful in 21s
    CI / Backend lint (ruff) (push) Successful in 2m23s
    CI / Frontend tests, audit, and build (push) Successful in 2m43s
    Release / Build and push versioned images (push) Successful in 4m9s
    CI / Bot tests and audit (push) Successful in 7m45s
    CI / Backend migration, tests, and audit (push) Has been cancelled
    Stable

    rbrooks released this 2026-07-17 22:29:59 +00:00 | 3023 commits to main since this release

    Scheduling: timezones, recurrence, availability & calendar sync.

    Campaign-anchored timezone correctness, recurring session series, standing
    player availability with quorum-based at-risk warnings, a subscribable iCal
    feed, and emailed calendar invites. No API contract change
    (BOT_CONTRACT_VERSION stays 1). Ships four Alembic migrations.

    Added

    • [webapp] Emailed calendar invites — opt in (Profile → "Email me calendar
      invites") to receive a real calendar invite by email when a session is
      confirmed. It adds straight to Gmail, Apple Calendar, or Outlook, updates in
      place when the session is rescheduled, and is removed if it's cancelled — no
      Google sign-in or setup required. (#189)
    • [webapp] Subscribable calendar feed — each user can generate a personal
      iCal feed URL (Profile → Calendar subscription) and subscribe to it in Google
      Calendar, Apple Calendar, or Outlook to see all their confirmed sessions,
      updated automatically when a session is rescheduled or cancelled. (#107)
    • [webapp+bot] Standing availability, absences, and session-at-risk warnings —
      players can set recurring weekly availability (in their own timezone) and mark
      date-range absences on their profile; when a GM proposes times, the voting grid
      and create form flag who is unavailable. Campaigns can set a minimum-players
      quorum, and when a confirmed session is likely to fall below it (from absences
      or explicit "no" votes) the GM gets a one-time Discord warning and the session
      is flagged in the web app. (#104)
    • [webapp] Recurring session series — GMs can set a game to repeat (weekly,
      every other week, or monthly on the same weekday) at a fixed campaign-time,
      and Quest Board auto-creates the sessions a few weeks ahead. Times stay put
      across daylight-saving changes. Individual occurrences can be rescheduled,
      cancelled, or detached without affecting the rest, and editing the series can
      either apply to just future sessions or also update upcoming unmodified ones.
      Reminders work exactly as they do for one-off sessions. (#98)

    Fixed

    • [webapp] Session times are now anchored to the campaign's timezone — the
      scheduler previously read the naive picker value in the browser's zone, so a
      GM scheduling "7:00 PM" from a different timezone than the campaign stored (and
      everyone saw) the wrong instant. Scheduling inputs now convert from campaign
      time to UTC correctly (DST-aware), every displayed time carries an explicit
      zone label, and the session detail page and voting grid add a "your time" line
      when your zone differs from the campaign's. Milestone dates are treated as
      floating calendar dates so they never shift a day across zones. Campaign
      settings offer the full IANA timezone list. Backend and bot were already
      correct (UTC storage; Discord dynamic timestamps). (#95)
    Downloads
  • v3.5.0 2ea6f26531

    v3.5.0
    Some checks failed
    Release / Build and push versioned images (push) Failing after 24s
    Release / Create Forgejo release (push) Successful in 25s
    CI / Docker image build (push) Successful in 30s
    CI / Backend lint (ruff) (push) Successful in 55s
    CI / Frontend tests, audit, and build (push) Successful in 1m43s
    CI / Bot tests and audit (push) Successful in 2m22s
    CI / Backend migration, tests, and audit (push) Successful in 4m4s
    Stable

    rbrooks released this 2026-07-17 15:24:21 +00:00 | 3042 commits to main since this release

    Frontend platform & PWA.

    Modernises the SPA foundation: a shared API client with session-expiry
    handling, route-level code splitting, real ESLint enforcement, and installable
    PWA scaffolding. Frontend suite grew 69 → 106 tests. No API contract change.

    Added

    • [webapp] Quest Board is installable — a web manifest, icons (including a
      maskable one) and a service worker mean you can add it to a phone home screen
      and open it as a standalone app. The app shell and every route chunk are
      precached, so a refresh with no signal renders the real UI instead of the
      browser's offline error. Authenticated API responses are deliberately never
      cached: they always go to the network, so nothing stale is ever shown as
      current. New deploys activate immediately rather than leaving anyone on a
      stale bundle. (#108)

    Changed

    • [webapp] First visit now follows your system light/dark setting instead of
      always starting dark, and the theme is applied before first paint, so
      light-mode users no longer get a dark flash on every load. An explicit choice
      via the toggle still wins and persists; until you make one, the app keeps
      following the OS. (#108)
    • [webapp] Pages now load on demand — routes are code-split, cutting the
      initial JavaScript download by 64% (686 kB → 244 kB; 172 kB → 78 kB
      gzipped). Opening the dashboard no longer downloads the admin panel and the
      entire markdown toolchain first: the wiki's 169 kB markdown renderer is
      fetched only when you actually open a wiki article. (#105)

    Fixed

    • [webapp] An expired session now sends you to the login page — every
      src/api/* module runs through a shared client that handles 401 centrally.
      Previously auth was only checked once at mount, so when the 8h session expired
      mid-use every request failed while the app carried on rendering a dead page.
      The client also aborts in-flight requests on navigation (a slow response from
      a route you already left can no longer resolve late and overwrite fresher
      state) and de-duplicates identical concurrent GETs behind a short TTL cache,
      so a dashboard with N campaigns no longer issues N uncached requests per
      mount. (#103)
    • [frontend] ESLint now actually enforces the React hooks rules — the config
      had registered a no-op stub for eslint-plugin-react-hooks, so
      exhaustive-deps had never linted anything. Wiring up the real plugin
      surfaced five genuine findings, including a recording-dashboard effect that
      would have rebuilt its live-status EventSource on every render. (#21)
    • [deps] Renovate no longer decouples pydantic from pydantic-core — the
      compiled bot/requirements.txt lockfile is now managed by Renovate's
      pip-compile manager (which regenerates the lock) instead of
      pip_requirements (which edits pins in place, one package per PR). pydantic
      pins pydantic-core to an exact version, so in-place bumps broke every
      pydantic update with ResolutionImpossible. Lock regenerated to a consistent
      pair (pydantic 2.13.4 / pydantic-core 2.46.4), which also picked up a
      missing pyjwt pin required by redis. (#178)
    Downloads
  • v3.4.1 b5b53ff478

    v3.4.1
    Some checks failed
    Release / Build and push versioned images (push) Failing after 9s
    Release / Create Forgejo release (push) Successful in 14s
    CI / Backend lint (ruff) (push) Successful in 1m58s
    CI / Frontend tests, audit, and build (push) Successful in 2m7s
    CI / Docker image build (push) Successful in 3m43s
    CI / Bot tests and audit (push) Successful in 4m17s
    CI / Backend migration, tests, and audit (push) Successful in 6m6s
    Stable

    rbrooks released this 2026-07-16 18:27:12 +00:00 | 3054 commits to main since this release

    Patch: deploy healthcheck fix.

    Fixed

    • [ops] Frontend healthcheck probes 127.0.0.1 instead of localhost — the
      nginx:alpine image maps localhost to IPv6 ::1 only, but nginx binds IPv4
      0.0.0.0:80, so the #84 wget --spider http://localhost/ healthcheck got
      connection-refused and flapped the container unhealthy even though nginx
      served fine. (backend/bot use Debian images where localhost resolves to
      127.0.0.1, so they were unaffected.)
    Downloads
  • v3.4.0 2b6a8ff354

    v3.4.0
    Some checks failed
    CI / Docker image build (push) Successful in 13s
    Release / Create Forgejo release (push) Successful in 18s
    CI / Backend lint (ruff) (push) Successful in 36s
    Release / Build and push versioned images (push) Failing after 9s
    CI / Bot tests and audit (push) Successful in 1m46s
    CI / Backend migration, tests, and audit (push) Failing after 2m23s
    CI / Frontend tests, audit, and build (push) Successful in 3m40s
    Stable

    rbrooks released this 2026-07-16 06:08:49 +00:00 | 3056 commits to main since this release

    Reliability, operations & self-hosting.

    All 14 milestone issues. Makes failures visible and recoverable and smooths
    deploy/upgrade for self-hosters. Backend and bot suites green (backend 395,
    bot 186).

    Added

    • [webapp+bot] At-least-once bot event delivery — backend→bot session events
      now flow over a durable Redis Stream (qb:bot:events) with a consumer group
      and per-event event_id idempotency, replacing fire-and-forget pub/sub that
      silently dropped events while the bot was down and could double-post on the
      HTTP fast path. (#81)
    • [webapp] Automatic ordered migrations on deploy — a one-shot migrate
      service runs alembic upgrade head before backend/worker/beat start; fresh
      installs self-provision and app services never boot against an old schema. (#89)
    • [webapp+bot] Version handshake — GET /api/bot/meta plus a bot startup
      check refuse to run on a contract-version mismatch and warn on drift. (#93)
    • [webapp] VAD silence-trim before transcription (opt-in, Admin → Bot
      Settings) cuts Whisper time/cost by transcribing only speech spans, with exact
      session-relative timestamp offsets. (#101)
    • [webapp] Pagination (limit/offset + X-Total-Count header) on list
      endpoints, backward compatible. (#99)
    • [webapp] Background-job failure counters (backup_failed_total,
      celery_task_failed_total, bot_event_delivery_failed_total), example
      Prometheus alert rules, and an optional Sentry hook. (#86)
    • [ops] Container hardening — worker/beat/frontend healthchecks, memory
      limits, and Redis AOF persistence. (#84)
    • [ci] Versioned Docker images published to the Forgejo container registry
      on tag. (#91)
    • [ops] Disaster-recovery docs — restore runbook, off-host backup copies,
      and media-volume backup. (#80)

    Changed

    • [bot] Recording streams to disk instead of buffering whole sessions in RAM
      — memory is now bounded (was ~20 GB for a 5-person/6-hour session), and audio
      survives a crash. (#82)
    • [webapp] Backend hot-path performance — module-level Redis connection
      pools, SSE releases its pooled DB session, N+1 vote/NPC queries replaced with
      grouped aggregates, and a sessions (status, confirmed_time) composite
      index. (#96)
    • [webapp+bot] Pinned Python base image to 3.12 to match CI and avoid the
      3.13+ stdlib audioop removal that discord.py voice needs. (#87)
    • [webapp] Tree-wide ruff format applied and enforced as a CI gate. (#20)

    Fixed

    • [webapp] Celery event-loop crashes — every task now uses a per-call
      NullPool session (task_session()), fixing intermittent "Future attached to a
      different loop" failures in recap-email and vote auto-close. (#129)
    Downloads
  • v3.3.0 aa3b4299db

    v3.3.0
    All checks were successful
    CI / Frontend tests, audit, and build (push) Successful in 1m18s
    CI / Bot tests and audit (push) Successful in 2m2s
    Release / Create Forgejo release (push) Successful in 1m55s
    CI / Backend lint (ruff) (push) Successful in 2m17s
    CI / Docker image build (push) Successful in 2m48s
    CI / Backend migration, tests, and audit (push) Successful in 3m31s
    Stable

    claude-bot released this 2026-07-15 04:38:26 +00:00 | 3093 commits to main since this release

    Hardening: bugs & security.

    Correctness and security fixes from the July 2026 full-project review. All 13
    milestone issues; backend and bot test suites green.

    Security

    • [webapp] Discord webhook SSRF allowlist — discord_webhook_url (campaign
      and admin-fallback) is validated with real URL parsing against a Discord host
      allowlist (discord.com, discordapp.com, ptb.discord.com,
      canary.discord.com; scheme https; path /api/webhooks/) at write time,
      and re-checked immediately before every server-side POST so legacy rows are
      neutralised — a non-Discord URL is logged and skipped, never fetched. Closes a
      server-side request forgery vector against the deployment's internal network.
    • [webapp+bot] Recording authorization — /record start|stop now require the
      invoker to hold Discord Manage Server or be the campaign's verified-linked GM
      (fails closed on lookup error); the audio-upload endpoint verifies the
      session's campaign belongs to the supplied guild_id (404 on mismatch, no
      task queued), preventing cross-guild audio attachment. New
      GET /api/bot/guilds/{guild_id}/gms supports the bot-side check.
    • [webapp] Reject placeholder/weak secrets at startup — SECRET_KEY (rejects
      the .env.example placeholder, requires ≥ 32 chars), DATABASE_URL /
      DATABASE_MIGRATE_URL (reject changeme/changeme_migrate passwords, parsed
      not substring-matched), and bot_api_key (rejects placeholders / < 16 chars
      when set) fail fast with an actionable message.
    • [webapp] DML-only app DB role — the app now connects as a non-superuser
      questboard role (DML only); POSTGRES_USER becomes a dedicated superuser
      questboard_admin used only for break-glass; pg_dump backups run as the
      schema-owning questboard_migrate role. Breaking for existing installs —
      see the "Existing Installs" runbook in docs/OPERATIONS.md. Requires
      POSTGRES_USER=questboard_admin and a new POSTGRES_APP_PASSWORD in .env.
    • [webapp] Recap-email HTML escaping — GM- and LLM-supplied values
      (session_title, campaign_name, summary) are HTML-escaped in recap
      emails, and CR/LF are stripped from the subject (header-injection guard).
    • [webapp] Stop echoing raw LLM errors — the /ask endpoint returns a
      generic detail and logs the real exception server-side.
    • [bot] HTTP server binds loopback by default — HTTP_HOST defaults to
      127.0.0.1 (compose overrides to 0.0.0.0 for the internal network); the
      aiohttp request-body cap is now pinned explicitly.

    Bug fixes

    • [bot] /record start guard leak — a bad session UUID (or the user not
      being in voice) no longer strands the guild in the "starting" set, which had
      permanently locked out recording until a bot restart.
    • [bot] Audio cleanup no longer deletes queued recordings — the audio_temp
      sweep runs once per process (not on every gateway reconnect) and skips any
      session directory the bot has marked as handed off to the backend, so
      recordings awaiting or undergoing processing survive reconnects and restarts.
    • [webapp] Duplicate reminder delivery removed — the legacy ETA-scheduled
      reminder path is retired; the poll_session_reminders Beat task (deduped by
      session_reminders_sent rows) is the sole delivery mechanism, so a rescheduled
      session is reminded exactly once per offset. celery_task_ids is no longer
      written.
    • [webapp] Deterministic lore-match chunk index — replaced PYTHONHASHSEED-
      salted builtin hash() with a SHA-1 digest, so lore consolidation survives a
      worker restart mid-pipeline instead of failing with a consolidation timeout.
    • [bot] Discord embed size budget — a shared fit_embed helper keeps the
      whole embed (title + description + fields + footer) under Discord's 6000-char
      total, so /recap and summary embeds no longer fail outright on long content.
    • [webapp] Public analytics share page — the frontend now proxies /public/
      to the backend (nginx + Vite dev), so analytics share links load instead of
      returning the SPA HTML.

    Docs

    • Corrected the recording architecture (per-speaker WAV + /audio pipeline, no
      longer "not yet implemented"), the DB-role model, frontend stack versions, and
      Python base-image version across CLAUDE.md, webapp/CLAUDE.md,
      bot/CLAUDE.md, ARCHITECTURE.md, docs/API.md, and docs/DEVELOPMENT.md.
    Downloads