Upgraded LXC 151 from 1.157.1 to 1.157.2 (packages.matrix.org, Trixie), a
security release fixing 11 advisories (6 High / 3 Moderate / 2 Low; no CVE IDs
assigned). Applies to us: most High-severity issues need open federation (we
federate) and two call out untrusted local users.
Pure apt bump — no upgrade.md notes for v1.157.2, no schema migration,
Python/PostgreSQL minimums unchanged, homeserver.yaml preserved via
--force-confold. Clean restart (NRestarts=0), version endpoint reports 1.157.2,
no errors, federation healthy.
Note: 1.157.2 adds an OPTIONAL push_rules.limits config block (safe defaults)
for the push-rule-exhaustion advisory — captured for later tuning, not required.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Upgraded LXC 151 from 1.156.0 to 1.157.1 (packages.matrix.org, Trixie).
The host was found on 1.156.0 despite this README recording 1.155.0 — an
intermediate upgrade had gone unlogged. Corrected the infra and Tech Stack
tables and noted the drift so future upgrades verify with dpkg rather than
trusting the docs.
Not a security release (no CVEs in range; the last were fixed in 1.152.1),
but 1.157.0 fixes an application-service ephemeral-events regression shipped
in 1.156.0, which affects hookshot. No schema-version bump (94 -> 94) and the
three new background updates completed immediately. Our experimental_features
block (MatrixRTC/Element Call MSCs) is unaffected by 1.157.0's removal of
msc3861, which we do not use; it was preserved via --force-confold.
Also adds a Synapse upgrade runbook — the repo had no documented procedure or
automation for this at all, so the two prior upgrades were done out-of-band.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Companion to cinny's `concurrency: cancel-in-progress`. The poll loop latched
origin/lotus once at startup; with CI cancel-in-progress a superseded run's
status flips to error/failure, so polling the latched (now-cancelled) SHA would
abort and — with the flock skipping the newer push's deploy — strand the newest
commit undeployed (a deploy freeze, the exact class this script fought before).
- Re-resolve origin/lotus each poll iteration; retarget the CI gate to HEAD if
it advanced (fresh MAX_WAIT window).
- On a failure/error status, re-check HEAD before aborting — only a genuine
failure of the CURRENT HEAD aborts; a superseded/blip SHA is followed instead.
- Reset to the gated $COMMIT_SHA (not a bare origin/lotus that may have advanced
past the gate after the loop) so we build exactly what passed CI.
shellcheck clean; reviewed (SHIP).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the translation feature to the landing page (Newest July 2026
prose + comparison-table row) and the README custom-features table.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The production config.json (cp'd from cinny/config.json by deploy/lxc106-cinny.sh)
lost its "gifApiKey": "" placeholder, so lotus_deploy.sh's sed injection had no
field to fill -> the GIF composer button disappeared (it renders only when
gifApiKey is non-empty). Restore the placeholder so future deploys inject the key.
Also redact the real Giphy key that was committed in the README (it belongs only in
/etc/lotus-deploy.env on LXC 106). NOTE: the key remains in git history (commit
f3a7bcd) — it should be rotated.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- README Custom Features: 'Inline media embeds' row (16 providers, facade, CSP
note incl. the live LXC 106 frame-src allowlist vs the repo wildcard fallback).
- landing: add inline media embeds to the July 2026 feature list.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds Strict-Transport-Security (2y, includeSubDomains, preload) and a
Permissions-Policy that allows only the features the app uses (camera/mic/
display-capture for calls, geolocation for location share, autoplay/fullscreen/
encrypted-media) and denies the rest. Complements the existing X-Frame/CSP/
Referrer headers.
Apply: reload nginx on the LXC. TLS terminates upstream (listen 80), so verify
the header reaches the browser (front proxy must pass it through) — else set
HSTS at the TLS terminator. Verify a call + location share still work.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Shellcheck directives bind to the NEXT command; on the compound line
`set -a; source /etc/lotus-deploy.env; set +a` the existing
`# shellcheck disable=SC1091` bound to `set -a`, so the info-level SC1091
finding on the runtime-only env file still failed the lint workflow
(find -exec shellcheck exits non-zero on any finding). Split the line so the
directive sits directly above `source` (as `source=/dev/null`, the standard
idiom for host-only env files). Verified with CI's exact invocation:
`find . -name "*.sh" -exec shellcheck {} +` now exits 0 (shellcheck 0.9.0).
No runtime behavior change.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- landing: Threads row upgraded to ✓ (full side panel + unread chips); prose
sentence for the new batch (threads, KaTeX math, opt-in encrypted-search
index, session hardening, crypto diagnostics).
- README: two new rows in the Lotus Cinny custom-features table.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- README Custom Features table: add rows for the in-call soundboard (P5-15),
call quality controls, and room call-permissions (P5-31).
- landing: mention the soundboard, per-user quality controls, and
server-enforced room call-permissions in the feature blurb.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Update the client-comparison copy to reflect that calls run our self-built
Element Call fork and that the ML noise-suppression tier offers RNNoise, Speex,
DTLN, and DeepFilterNet 3.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extend voice-limit-guard to enforce a per-room publish-source policy
(io.lotus.room_quality allow_screenshare/allow_camera) for ALL Matrix clients,
alongside the existing participant limit.
- At token issue, re-sign the LiveKit JWT's canPublishSources to drop forbidden
sources (microphone always kept). Verifies our own secret signed the token
first and fails open on mismatch, so a secret drift can never mint a token the
SFU rejects. Limit check and source policy are independent (one's outage can't
skip the other).
- Live (mid-call) enforcement: a background reconcile loop calls LiveKit
UpdateParticipant to revoke a forbidden source from participants who joined
before the policy changed -- which unpublishes their in-progress
screenshare/camera server-side within ~3s and blocks re-publish. Only removes
sources (never grants), preserves other permission flags, fails open, and runs
as a daemon thread that cannot crash or block token issuance.
- Endpoint-specific room-id extraction (/get_token->room_id, /sfu/get->room) so
a client sending both keys can't get a different room's policy applied.
- Auto-deploy the guard on LXC 151 (py_compile-gated, backup + rollback).
- Unit tests: JWT re-sign/verify + tamper, secret-mismatch, source narrowing,
reconcile (never-grant / preserve-flags / disable-on-empty), fail-open.
Numeric bitrate/fps caps are NOT server-enforceable on an SFU (LiveKit forwards,
never transcodes) and remain a Lotus-client-cooperative setting; the
screenshare/camera permission is the hard cross-client lever.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The cinny/lotus-deploy.sh (hyphen) force-deploy variant was an untracked,
redundant duplicate of the CI-gated cinny/lotus_deploy.sh (underscore) added in
c13549f. It's been removed, so its install block here referenced a file that no
longer exists. The CI-gated lotus_deploy.sh is the single source of truth for
the webhook web deploy.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The live /usr/local/bin/lotus_deploy.sh (the `lotus-deploy` webhook target) was
never under version control and had rotted into two deploy-killing bugs that
froze chat.lotusguild.org on an old build:
1. CI gate: it waited on the WHOLE workflow run with a 15-min cap. Web CI shares
the single act_runner with the slow Tauri desktop builds, so a web run could
sit queued >15 min -> "result: timeout" -> deploy aborted. Now it gates only
on the "Build & Quality Checks" commit-status context (build + unit tests),
decoupled from "Trigger Desktop Build", and waits up to 45 min.
2. Dead element-call copy: `cp node_modules/@element-hq/element-call-embedded/...`
under `set -e` aborted every deploy after the widget was forked to
@lotusguild/element-call-embedded. The build already emits dist/public/
element-call; replaced the copy with a presence check.
Also: rsync now excludes config.json so the app deploy stops clobbering the
production runtime config (homeserver list / allowCustomHomeservers) that the
matrix repo owns. lxc106-cinny.sh now installs this script (syntax-checked).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Now that the client supports MSC3861 OIDC login, add mozilla.org to the
homeserverList and its origins to the CSP. mozilla delegates: homeserver ->
mozilla.modular.im, OIDC issuer -> chat.mozilla.org, identity -> vector.im.
- connect-src += mozilla.org mozilla.modular.im chat.mozilla.org vector.im
- img-src += mozilla.org mozilla.modular.im
Applied live to LXC 106 and synced here.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Federated matrix.org users load avatars/images from their own media endpoint
(matrix-client.matrix.org), which img-src still blocked — so every avatar
tripped a CSP violation. Add https://matrix.org + https://*.matrix.org to
img-src to match connect-src. (media-src already allows https: so video/audio
were fine.) Applied live to LXC 106 and synced here.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The chat.lotusguild.org nginx config (LXC 106) was edited directly on the box
and never tracked — which is how its CSP drifted (kept a dead Sentry URL and
blocked matrix.org logins). Snapshot it as cinny/nginx.conf (verbatim from prod,
incl. the corrected connect-src that now allows matrix.org/*.matrix.org) and
deploy it via lxc106-cinny.sh: back up the live file, swap, `nginx -t`, and
reload only on success (auto-restore the backup if validation fails, so a bad
config can't take the site down). TLS terminates at the NPM proxy, so this is a
plain HTTP server block with no secrets.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add matrix.org to homeserverList so federated friends with matrix.org accounts
can sign into chat.lotusguild.org. defaultHomeserver stays 0 (lotusguild), and
allowCustomHomeservers stays false — only the two listed servers are selectable,
so the client isn't opened up to arbitrary homeservers.
Deploys via lxc106-cinny.sh (cp -> /var/www/html/config.json); lotus-build.sh
preserves the live config across app rebuilds, so this is the authoritative copy.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tag the EC embed row and add a callout explaining the plan to fork
element-hq/element-call and self-build it for true ownership (decorations,
focus/screenshare, reconnect mic, theming, call-audio injection — all unfixable
against the prebuilt @element-hq/element-call-embedded bundle). Infra notes:
EC uses our LiveKit SFU (livekit/, LXC 151) + lk-jwt-service; a new build/deploy
pipeline will be needed. Full plan: LotusGuild/cinny → HANDOFF_ELEMENT_CALL_FORK.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- README: correct embedded Element Call version 0.19.3 -> 0.19.4 in the
Custom Features and Tech Stack tables
- landing/index.html: add a "Noise suppression" row to the Voice & Video
comparison table (Lotus = 3 tiers incl. on-device RNNoise ML) and note
the feature in the June 2026 narrative
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
99 curated APNG overlay frames stored in user Matrix profile (MSC4133),
visible to other Lotus Chat users in real time across timeline, members
list, and @mention autocomplete. Includes the Lotus Flower decoration.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add a fail-open Python sidecar (livekit/voice-limit-guard.py) that fronts
lk-jwt-service to enforce per-room voice participant caps for ALL Matrix
clients, not just Lotus Chat:
- lk-jwt-service moved to :8071 (systemd drop-in), guard owns :8070 so NPM's
existing /sfu/get + /get_token proxy targets are unchanged
- guard reads io.lotus.voice_limit.max_users (Synapse admin API, cached),
forwards to lk-jwt-service, and on an issued token decodes the LiveKit alias
+ requester, counts distinct Matrix users via LiveKit ListParticipants, and
returns 403 when the room is full (rejoins/extra devices allowed)
- any error fails open (returns upstream response) so calls never break
- systemd/voice-limit-guard.service; README documents ports, setup, revert
Also update landing page: voice limit is now server-enforced for all clients.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Feature description paragraph: added AFK auto-mute (1–30 min voice idle
timeout) and knock-to-join admin badge (live count on Members button)
- Comparison table: new AFK auto-mute row in Voice & Video section
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New table row for 5 animated CSS wallpapers (rain, stars, grid pulse,
aurora, fireflies). Feature blurb updated to mention the animated
backgrounds and the glassmorphism body-background fix.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds inline GIF preview and collapsible long messages rows to the
feature comparison table; extends the June 2026 feature list with all
five newly completed items (P3-5, P3-9, P5-19, P5-23, P5-26).
Includes pre-staged README additions for presence tracking, encrypted
search, privacy settings, draft persistence, and PiP persistence.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Update comparison table date to June 2026
- Add push-to-deafen (M key), night light filter, message length
counter, and TDS orange typing dots to also-available paragraph
- PTT row notes M = push-to-deafen
- Add Night Light row to UX & Extras comparison table
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
README.md:
- Replaced the stale 'Auto-revert spotlight on screenshare' entry
(that 600ms revert-to-grid code was removed — it caused fullscreen
to show avatars instead of the screenshare)
- Added accurate entries for all four features added this cycle:
Screenshare fullscreen, PiP screenshare focus, Screenshare audio
mute, Custom status message
landing/index.html:
- Updated Lotus Fork feature description paragraph to mention
screenshare fullscreen, screenshare audio mute, PTT, and custom
status messages
- Added PTT row to Voice & Video comparison table
- Updated Screenshare row for Lotus Chat to note fullscreen + audio mute
- Added 'Custom status message' row to UX & Extras section
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
LXC 139 NPM proxy host 49 now proxies both /sfu/get and /get_token
to lk-jwt-service (port 8070). Note that re-saving via NPM UI will
overwrite the conf and require re-adding the location blocks.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Document the new member list presence indicators and per-member device
sessions panel with per-device SAS verification in both the landing
page feature list and the README custom features table.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The runner intermittently times out (5m) downloading the gitleaks binary
from GitHub. Add --retry 3 --retry-delay 5 --max-time 120 so transient
network blips don't fail the job.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add per-message read receipts comparison row (8-col, including new official
Cinny column from dc8f588). Update Lotus Chat feature description to include
per-message read receipt avatars and chat wallpaper in calls.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add chat.lotusguild.org as the featured Cinny fork column and cinny.in
as a second comparison column. Adds official Cinny card in Other
Clients section and updates table colspan to 8.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>