DagNats dashboard reachable through the app origin. A reverse proxy mounts the DagNats console (:8090, not Cloudflare-tunneled) under /dagnats/ with path rewriting, so the dashboard loads without extra tunnel/infra config. The user-menu "DagNats" link now points to /dagnats/.
Stronger static analysis..golangci.yml now enables dupl, goconst, revive, tagliatelle, modernize, nolintlint (plus the existing staticcheck, errcheck, ineffassign, govet, gocritic, gosec, noctx, gocyclo, lll, funlen, mnd). gofumpt is configured as a formatter (not a linter); stylecheck is bundled into staticcheck in golangci-lint v2, so it is no longer a separate entry. Pin golangci-lint v2.12.2+.
Fixed
Theme toggle showed both moon and sun.iconify-icon is a custom element whose host stylesheet overrode the [data-theme] CSS rule. theme.js now has syncIcons() that explicitly hides the inactive icon (CSS polarity also corrected: light → sun, dark → moon).
Navbar did not highlight the active section.Navbar now takes an active param (todos/whiteboard) and applies btn-active via templ.Classes(... map[string]bool{...}).
Whiteboard was completely dead (WB_DOC_ID missing).whiteboard.js loaded as a plain external <script>, so it executed before the inline <script> that sets window.WB_DOC_ID from <main data-doc-id>. The guard bailed out of the whole IIFE, killing drawing, the color picker wiring, the online counter, and remote cursors. whiteboard.js is now defer-loaded so it runs after the DOM assignment. Added cursor-pointer to the color input.
make ci-local then ask before push. Documented in AGENTS.md: run the local gate first; the agent asks (via ask_user_question) before pushing to master rather than auto-pushing. A pi-yaml-hookspre-push hook mirrors this (runs make ci-local, then confirm).
Changed
Intentional API/UI wire contracts (clientID, simulatedLLM JSON tags bound by Datastar signals) keep //nolint:tagliatelle with a reason instead of being renamed.