v0.12 - Hollow Shop, New Design, Albums, Media Viewer & UnifiedPush (BREAKING for all older versions)

BREAKING CHANGE: 0.12 cannot talk to 0.11 or anything older. Everything it sends is now signed by the device that sent it and anything unsigned is refused, so messages, calls, friend requests and servers all fail between versions. Everyone needs to update together. Your identity, friends, servers and history carry over, and Hollow asks you once to confirm your recovery phrase, then stops keeping a copy of it. Invite and meeting links made before 0.12 no longer work, so ask for a new one. A meeting room made before 0.12 has to be made again. If you run your own relay, update it before anyone on it updates the app, since 0.12 cannot sign in to an older relay.

SECURITY

- Important security fixes

HOLLOW SHOP

- The Hollow Shop is open, with avatars, banners, frames and bundles made by independent artists
- Buy opens the piece on the artist's own Ko-fi, and Hollow takes no cut
- The files are yours to keep, with no DRM
- Try any piece on your own profile card before you buy it
- The code from your order mail puts a supporter badge on your profile without the shop learning who you are
- The Shop is on desktop and on the Android app from our website, but not on iOS or in app store builds

PRIVACY & PROTECTION

- App Lock now works on every platform, at launch and whenever you step away
- A duress code typed at the lock quietly erases your data instead of unlocking
- You can destroy your identity on all your devices at once, even the ones that are offline
- Files, images and voice messages are now encrypted on disk too, not only your messages

DESIGN

- Every screen on desktop and phone is redesigned in one shared style, with Onest as the new font
- Menus and dialogs are solid instead of blurred glass
- Motion is calmer, and switching conversations or tabs is now instant
- The animated background is now off by default, with a switch in Appearance

HOME

- Home is now an inbox of your conversations, with filters for unread messages and mentions
- Friend requests and anything else waiting on you sit at the top of Home
- A side panel on Home shows news, your relay and who is in a voice room
- The phone's Chats tab opens on the same inbox

CHAT

- Send up to ten files together as an album, shown as one mosaic
- Images, GIFs and videos open in a new viewer where you can zoom and step through everything shared in the conversation
- The chat is redesigned, with names in each person's own color and one picker for emoji, GIFs and stickers
- Compact message display is a new option in Appearance
- The typing indicator floats above the composer instead of pushing the messages up
- Message previews show what was sent instead of raw codes like [file:...]
- A failed send puts your text back in the composer

CALLS & VOICE

- Direct message calls, voice rooms and meetings share one call screen, with camera and screen share always in reach
- An outgoing call shows Calling with a Cancel button while it rings
- Phones get the same call screen, which you can minimize and reopen with a tap
- Direct messages now show call lines such as "Voice call, 4 minutes" and "Missed call"
- Fixed Disconnect in the dock leaving a meeting half open

YOUR DEVICES

- Reading a conversation on one device marks it read on the others, and your own messages no longer count as unread
- Catch-up now checks the last 30 days for gaps, so a device that was offline no longer loses older messages for good
- A direct message you send now reaches your offline devices too, without waking your phone

NOTIFICATIONS

- A new Notifications page in Settings shows whether Hollow is allowed to notify you and can send a test
- Muting a direct message now stops it waking your phone
- macOS notifications now reach Notification Center, grouped by conversation with an inline Reply
- Android phones can be woken through a UnifiedPush app such as ntfy instead of Google

SETTINGS & FRIENDS

- Settings and server settings now take the main window on desktop, so the dock and a call stay in reach
- Settings search now finds single settings
- The Friends Manager is rebuilt around Friends, Requests and Add friend tabs, and removing a friend now asks first

PROFILES

- The profile popup, game card and Welcome screen are redesigned
- The showcase is edited in place on your profile and can hold one wide artwork across both boards

DESKTOP

- Full screen now works on Windows, and F11 toggles it
- A video no longer restarts when it goes full screen
- The dock carries your call controls on every screen, and in Dock mode the title bar folds into the header

FIXES

- A dialog now shows its error in place, so you can try again without losing what you typed
- Fixed device linking hanging on "Sending your data" when something went wrong

SELF-HOSTING

- A self-hosted relay can now wake Android phones through UnifiedPush, with no Google account
- Up to five of your devices can share one access key on a self-hosted relay
- The self-hosting guide now covers running the relay without Docker

v0.11.1 - Linux Call Audio, Self-Hosted Relays, Personal Emotes & Relay Restarts

LINUX

- Calls carry audio again, in direct messages and in voice channels
- Fixed pressing play on a received video killing the app
- Fixed the Flatpak refusing to start after a profile was erased or the app was killed
- Closing the terminal Hollow was started from no longer leaves a window that does nothing
- Picking a file now falls back to a system dialog when the desktop portal does not answer, instead of failing silently

SELF-HOSTING

- Setting up your own relay is now one settings file, and one guide covers every way to get a certificate
- TURN now works on a self-hosted relay instead of pointing at the official one
- A renewed certificate is picked up without restarting the relay
- Every invite carries the relay it was made on, and opening one from another relay asks first rather than switching on its own
- Settings marks a relay without TURN, and a call that cannot find a relayed path says so instead of ending in silence
- The maintenance banner for the official relay no longer shows to people running their own

RELAY

- Messages waiting for somebody who was offline now survive a relay restart, so an update no longer drops them
- A phone keeps its push notifications across a relay restart too
- Restarting a relay is now immediate instead of taking a minute and a half

EMOTES

- Fixed a new custom emote not saving from the desktop picker unless you pressed Enter
- Your personal emotes now follow you to your other devices

FRIENDS

- Fixed a removed friend being added back by an accept that arrived late

SERVERS & CHANNELS

- Voice channels now offer visibility and temporary access in the mobile server settings
- Who can post is no longer offered on voice channels, where it never did anything

v0.11 - Call Resilience, Offline Friend Requests, Offline Server Joins, Signed Server Operations & Linux Auto-Updates (BREAKING for calls and servers)

BREAKING CHANGE: 0.11 cannot share a server, a one-to-one call, or a Twitch-gated join with 0.10.1 or older. Every change to a server is signed now and an unsigned one is refused, so members on different versions stop agreeing on the server. Call setup is encrypted now and a call signal in the clear is refused, so a call between versions fails outright. Direct messages, files, server voice channels and screen shares still work, but everyone in a server should update together.

SECURITY

- Every change to a server is now signed, so nobody can forge one as the owner
- One-to-one call setup is encrypted now, so the relay never sees the key to your call
- Fixed an inline image being able to write a file outside its own folder
- A signed device list is accepted only for a device named inside it
- Profile updates verify the profile signature before reading a device list
- Stored channel history is now served only to people allowed to see that channel
- Ban, private and member cap checks now apply to the person, not one of their devices
- The exemption that auto-downloads voice messages is now capped by size and checked by type
- Backup vault shards each carry their own integrity hash
- Images are now checked against their declared size before anything is decoded
- A timestamp from another peer is clamped, so nobody can freeze a field with a future date
- The updater now trusts a signed version list and a hash per download, not the download host
- Only a strictly newer version counts as an update, so nothing can walk you backwards
- Transfer IDs are restricted to known characters, because an id names a file on disk
- On Android, the identity key and database stay out of OS cloud backups and device transfers
- The relay gained buffer caps, brute-force protection on link codes, a push budget and tighter checks
- Dependencies moved up, including OpenMLS 0.9 and the SQLCipher database engine, past a known vulnerability
- Identity secrets are wiped from memory when dropped, and a dependency audit runs on every build

CALLS & VOICE

- A call no longer ends because the connection stuttered for a couple of seconds
- A lapse now holds the call open for 45 seconds and steps the video down
- Cameras now carry a bitrate cap, which is what made calls collapse on a weak connection
- Losing the relay no longer ends a call, since the call has its own connection
- Recovery rebuilds the call with the same call and key, instead of restarting the old connection
- The relay retries every second while a call is live instead of backing off
- Voice channels now recover from a dropped connection the way DM calls do
- Fixed a reconnecting member being able to send in a voice channel but never receive
- A voice channel member whose connection does not return is redialled instead of left there silent
- Fixed a DM call forgetting your camera when both sides recovered at once
- Fixed deafen and per-peer volume being forgotten whenever a call connection was rebuilt
- Fixed the intermittent call that sits on "Connecting..." and never finishes
- Fixed two people pressing Call at the same moment rejecting each other as busy
- The connection quality flair now shows on voice channel participant rows, not only on camera tiles
- Fixed the voice panel header reading "Voice Connected" while the relay was down
- Fixed the join chime firing for people who never left

FRIENDS

- A friend request now reaches somebody who has never been online at the same time
- Fixed a returning device turning an accepted friend back into an incoming request
- A decline now reaches a requester who was offline and stays declined on both sides
- Fixed an accept overwriting a decline that had already happened
- An incoming request shows the sender's name and avatar instead of a raw identity string
- A declined request offers Add Friend again
- An outgoing request says it will be delivered when the recipient is next online

SERVERS, CHANNELS & JOINING

- Joining a server whose members are all offline now works, with a pending tile meanwhile
- The pending tile offers Discard, Copy invite and Request again
- The answer is written back, so a member returning later cannot admit or refuse you twice
- A parked join sets up your encryption too, so the server is readable at your next launch
- A join into an empty server room now parks after three seconds instead of fifteen
- A member still waiting for encryption setup no longer misses what is sent meanwhile
- Fixed a returning server owner silently missing messages after sleeping through a key change
- Joining a busy server costs far less traffic, because one member serves it instead of all
- Fixed a deleted server staying in the list forever for some members
- Fixed public channel captions, edits, deletes, reactions and link previews not arriving after catch-up
- Fixed opening a channel before joining its room using up that connection's one catch-up
- Channel messages are now kept forever by default instead of being pruned after a year
- Files keep the one-year default, and the owner can still set a window

FILES & ATTACHMENTS

- A file that is not on your machine now says why instead of a dead Download button
- The card says whether the request is in flight, the holder is offline, or the file is gone
- A file removed by the server's retention policy reads as removed
- A request now survives a reconnect and asks the next holder as people appear
- A holder that no longer has a file now answers instead of staying silent
- A claim that a file expired is checked against your own retention setting first
- The hover bar, right-click menu and mobile sheet offer the same action the card does
- A queued request can be stopped, and a refused one can be tried again
- Fixed channel file retention never running at all, so the setting now does what it says
- GIFs, stickers and custom emotes sent while you were away now arrive once a holder appears

TWITCH VERIFICATION

- Twitch verification for joining a server is now a credential checked offline against your identity
- The server owner contacts nobody and learns only the channel, your follow step and your subscription
- A credential covers 90 days and is then renewed the same way it was issued
- A Twitch-gated server can now be joined while its members are offline, like any other server
- The minimum follow time is now a picker of ten steps rather than a free number
- The Twitch chip on a profile now comes from a verified credential, not a typed field

PROFILES

- Avatars are stored at 512 pixels and banners at up to 1200x480, both up to 2 MB
- A person's banner is now 2.5:1 rather than 3:1, and server banners keep their own 3:1
- Avatar frames can now be a square of up to 512 pixels instead of exactly 128
- Every frame that already exists stays valid
- An animated frame that passes through untouched is now checked and re-encoded when it cannot pass
- Somebody still on 0.10.1 may not receive an animation authored at the new ceilings

RELAY

- The 10 GB per day limit per address is gone, because it counted the wrong traffic
- TURN now carries Hollow clients to each other and nothing else, instead of relaying for anyone
- The relay shares its line fairly while it is full, rather than counting anybody's bytes
- The bandwidth meter is gone from the relay cards, since there is no budget to report

LINUX

- Hollow updates itself on Linux now, on both the tarball and the Flatpak install
- A tarball update swaps the folder and restores the previous build if the new one fails
- A Flatpak update is installed on the host, so it works from inside the sandbox
- The Flatpak comes from our own signed repository, so flatpak update and software centres see releases
- Every download is checked against the signed version list before it is installed
- Updating to 0.11 itself is still a manual download on Linux, since 0.10.1 shipped without it
- The update card in Settings says "Installing" and "Restart now," which is what happens

INTERFACE & MOBILE

- Fixed background motion stuttering, which the idle CPU work in 0.10.1 introduced
- Fixed push notification setup being able to report a working mobile connection as failed

TESTING

- The build now runs the app's interface tests, which it never did before
- The tests wait for conditions instead of sleeping, and can now drive iPhone simulators like a desktop window

v0.10.1 - Right-Click Menus, Chat Scrollbar, Unread Line, Avatar Frames & Performance

RIGHT-CLICK MENUS (issue #61)

- Right-click works across the desktop app now: messages, channels, categories, the empty space in the channel sidebar, people, server icons, folders and Home. Messages used to jump straight to Message Proof, and nearly everything else lived in Server Settings
- The message menu carries reactions, reply, copy, download, pin, edit and delete, with Message Proof as one row among them, on all seven chat surfaces
- Right-clicking a person opens the same menu wherever they appear: the member list, a name in chat, a voice participant, DM tiles, the friends bar and the home dashboard. Left click still opens the profile card, so Profile is the menu's first row rather than a replacement for it
- Moderation rows are hidden when you cannot use them instead of shown greyed out. A menu should not offer an action that is going to be refused
- Right-clicking a voice participant keeps that person's volume slider and adds everything else around it
- Every menu has a keyboard route, so none of them are mouse-only
- Channel menus cover rename, visibility, who can post, temporary access and delete, and "Create channel here" now places the channel inside the category you opened it from
- Changing someone's role on mobile asks for confirmation, matching desktop

CHAT, SCROLLBAR & PANELS (issue #54)

- The chat feed has a scrollbar. Draggable thumb, and a jump to the top or the bottom from either end
- A line marks where you left off. It stays put while you read instead of sliding away as messages are marked seen, it never appears above your own message, and the rail marks its position so you can jump straight to it even when it is far off screen
- Marking a conversation read from outside it no longer moves that line. Dismissing messages is not the same as going to read them
- Scrollbars everywhere else moved into a reserved gutter instead of painting over the rows they belong to
- Side panels resize by dragging their seam, with double-click to reset and arrow keys to nudge, and "Side panel size" in Accessibility zooms their contents. Widths, zoom, folded sections and the profile card style all survive a restart
- Member list sections fold, keeping their divider and their full count
- DM search. Ctrl+K in a DM had been a silent no-op, and the search itself was built and never connected to anything, so DMs now carry the same search bar channels have
- Profile cards follow the row they belong to when the window changes size, and Escape closes them
- Fixed four dark notches at the corners of the chat, where the resizable panels left a 6px seam that painted nothing next to the header and composer bars
- Fixed the chat scrollbar stopping 22px above the bottom of its own track while pinned to the newest message, so it advertised room that was not there
- Fixed sticker packs saying "Downloading..." forever instead of showing the real transfer state
- Fixed the guest banner showing the wallpaper through it

AVATARS & PROFILES

- Avatar frames: decoration drawn over your avatar, Steam style, so hats, ears and wings all work. They cost the layout nothing, and they are off on voice and call surfaces, where a frame sits exactly where the speaking ring goes
- Animated avatars and banners no longer travel with your profile to everyone who syncs with you. The still image still does, so everybody sees a face, and the animation is fetched only when something actually shows it. Before this, every reconnect re-sent megabytes nobody had asked to see. Animated avatars you already have move over on their own at the next launch
- Fixed animated APNG avatars arriving frozen. Steam serves animated frames as APNG, and Hollow was deciding whether an image moves by looking at its filename instead of the file, so an APNG went down the still path and was flattened without any complaint. The same bug was flattening animated WebP images sent as files
- Avatars are stored at a larger size, because the profile card paints them big enough that the old one was being enlarged on the surface that shows an avatar largest
- Better quality per byte on avatars, with noticeably cleaner edges on line art at 15%-30% fewer bytes
- Fixed saving your profile appearing to wipe your banner. Nothing was ever lost, the preview just sat on its placeholder while the image decoded again

PROFILES ON THIS DEVICE (issue #47)

- Erasing the active profile used to strand you. The restart drops you on the welcome screen, which knew nothing about profiles, so the only way forward was a new identity inside the folder you had just emptied. The welcome screen now names the profile you are setting up and lists the others you can switch to
- Erasing a password-protected profile asked for nothing at all, which meant anyone at an unlocked Hollow could wipe it without knowing its password. It asks now, and a wrong password is refused in the field instead of closing the dialog behind a message
- A restored backup lands in the profile you are standing in. That is intended, so the welcome screen names the destination folder before you choose anything

PERFORMANCE

- Idle CPU went from 10% to roughly 1%-2% (tested on Intel i7-13620H [10c16t]). The cause was a bug in tickers (5%) and a decorative progress bar (2.5%), running an animation that was restarted before it could ever finish and therefore asked for a new frame at every screen refresh, forever. On a 240Hz monitor that is 240 frames a second spent on an app doing nothing. Other animations with their tickers were fixed too.
- Fixed all of that burn continuing at full speed while the window sat behind another application
- Windows and Linux go back to the renderer they used before v0.10 (Skia). The one v0.10 shipped (Impeller) sizes its video memory by window area rather than by what the app draws, therefore consuming more RAM/VRAM (and simply because they don't have direct Vulkan rendering yet). macOS stays on the new renderer (direct Metal rendering), iOS and Android are unaffected
- Preparing an avatar frame went from 12.7 seconds to 188 milliseconds. The slowest encoder setting turned out to be 74x to 87x slower for 2%-14% percent fewer bytes, and it scored slightly worse on quality while doing it
- Fixed a still image being encoded as a one-frame animation, which made it take twice as long to produce exactly the same file

v0.10 - Screen Share Forwarding, Mobile Audio Devices, Interface Sounds & Flutter 3.47

NOTE: This release raises the minimum operating system on two platforms, which the Flutter 3.47 upgrade requires: macOS 12 (was 10.15) and iOS 15 (was 13). Windows, Linux and Android are unchanged. Everything else stays compatible with 0.9.4, screen shares included.

SCREEN SHARING

- A screen share no longer costs you one encoded copy per viewer. Your machine sends one copy to a forwarder, which fans the already-encrypted packets out to everyone watching. The forwarder holds no key, never decodes a frame and never re-encodes one, so what leaves it is the same ciphertext you sent
- Viewers who can reach you directly still do. Only the ones who cannot, usually behind a strict router, need a forwarder, and Hollow prefers another viewer's machine over ours: one person with a good route serves the rest. If that machine leaves, refuses, or runs out of budget, the affected viewers fall back to our forwarder and then to the old direct path. Nobody loses the picture, it just costs more
- With "Always relay calls" on, you never touch another member's machine in either role, watching or forwarding. That is the whole point of the setting, and it is now enforced on both sides rather than trusted to one
- The fixed limit of 15 viewers becomes a number that depends on the routes in the room instead of a hard stop
- A share now sizes itself to each viewer's screen rather than sending everyone the source resolution. A 4K share into a room of 1080p displays costs roughly a quarter of the bandwidth and encoding it used to, and the quality label shows what you are actually receiving, live
- The share sends two quality layers, so a viewer on a weak connection drops to the lower one instead of stuttering while everyone else stays sharp
- Fixed a 10 to 15 second black screen for both viewers whenever a share handed over to a promoted forwarder
- Fixed live quality changes being rejected on Windows, which had been true since those settings existed. Where the engine still refuses, the share reconnects with the new setting instead of reporting a change that never happened
- A call that ends up routed through our relay when both sides could have connected directly now retries for the direct route once the connection settles, instead of paying for the relay all session
- A dead share connection is now noticed in seconds instead of waiting out a timeout

VOICE & CALLS

- Fixed connected headphones being ignored on mobile. "Speaker on" was a hard route override, which outranks a headset, so plugging in wired headphones mid-call moved the sound to the phone's loudspeaker and the microphone to the phone's own mic, with nothing in the interface able to undo it. "Speaker on" now means the loudest sensible route, which is the headset whenever one is attached
- Mobile gains a real audio device picker, in both DM calls and voice channels. The speaker button turns into a device button once a headset is attached, a long press always opens the list, and the icon shows where the audio actually is. The current route is read from the system rather than from our own last write, since the phone re-routes on its own
- Fixed the screen blanking at every passing object during a call on headphones. Proximity blanking now checks that the audio is really on the earpiece
- Call recording (issue #53) writes one mixed track instead of two. Most players only play the first track, which meant your own microphone was inaudible in every recording. A recording indicator now shows for everyone in the call or voice channel while one is running
- The microphone test in Settings (issue #40) records your raw microphone, renders that take through the real capture chain offline, and offers Play processed and Play raw side by side, so you can hear what noise suppression and enhancement do to your voice instead of guessing
- Fixed yourself being listed twice in a mobile voice channel, and in conferences, where the second copy of you even carried a Kick button

INTERFACE SOUNDS (issue #55)

- Hollow has sounds now: joining and leaving a voice channel, yours and other people's, someone starting or stopping a screen share, your own mute, deafen and camera toggles, and message notifications. Toggle and volume live in Settings > Audio, on desktop and mobile
- Pressing Call rings a ringback until the other side picks up. Only the receiving end heard anything before
- Cues fire on real changes only, so joining a busy channel does not replay everyone's arrival, and being deafened silences other people's cues while keeping your own
- Fixed call and voice channel cues being silent on iPhone, where only the message sound was ever audible. They play through the system audio player now, which cannot disturb a live call's microphone

INTERFACE & DESKTOP

- Fixed the Classic layout not surviving a restart (issue #58). The setting was read before the database finished opening and lost that race every time, so it quietly fell back to Dock. The toggle is a Dock and Classic picker now, and Classic regained Browse public channels, Conferences and Help, which had no entry point there at all
- Fixed Flatpak not launching (issue #59). The app gave up when it could not register with the session bus, which the package had never asked permission for
- Fixed the window close button doing nothing on Hyprland and sway. Those compositors have no minimize, so Hollow now checks whether the minimize took effect and quits on a second press if it did not
- Fixed the in-app updater failing to extract an update on Windows (issue #52), which affected every version up to 0.9.4
- Fixed switching profiles locking you out of your own encryption keys (issue #47), which showed up as garbled voice audio afterwards
- Settings labels are sentence case throughout. We had been shipping both "Toggle Mute" and "Toggle deafen", and "Dark Mode" beside "Dynamic mode". The README, privacy policy and terms got a writing pass at the same time

PLATFORM

- Upgraded to Flutter 3.47. Desktop renders through Impeller instead of Skia, which also removes the shader warm-up we used to run at startup to hide first-frame stutter
- macOS now needs 12 or newer, and iOS 15 or newer, as the new toolchain requires
- Fixed iPhone crashing while Hollow was suspended in the background. Every connection and every channel open was creating a fresh database handle on the networking thread, and iOS kills an app suspended while it holds that lock. Those reads are answered on the existing connection now

RELAY

- The relay no longer announces that you left a room while you are demonstrably still connected on a newer socket, which happened during quick reconnects and dropped you out of other people's member lists

v0.9.4 - Screen Share Watching, Voice Hotkeys, Link Previews, Channel Access & Portable Mode

NOTE: Hollow Share (the path for files over 34 MB) now negotiates its own direct connection, using a wire format older builds cannot read. Sharing with someone who has not updated will not connect. There is no relay fallback for Share by design, so failing outright is the correct outcome rather than quietly routing your file through our server. Everything else stays compatible.

SCREEN SHARING (issue #38)

- Screen shares are opt-in now. Nothing streams until a viewer presses Watch, instead of every share pushing video to everyone in the channel the moment it starts
- Voice channels get a Watch banner that collapses into a chip you can bring back. DM calls show an unwatched share as the person's avatar and a Watch button rather than a blank rectangle
- Both gain a grid view of every source at once, your own share included, with tap to fullscreen and a small preview of your own share while you are focused on someone else
- A new share never hijacks what you are looking at. Badges tell you it exists and leave the choice to you

WAYLAND WINDOW SHARING (issue #30)

- Wayland can share individual windows now, which 0.9 left as a follow-up. Your desktop asks once which window you mean, and re-sharing the same one reuses that permission with no second prompt
- X11 is unchanged and still enumerates windows itself

VOICE, CALLS & SHORTCUTS

- Push to talk, mute and deafen have global hotkeys that work while Hollow is in the background on Windows and X11, and in-app everywhere else
- Wayland gets genuine global shortcuts through the desktop portal (KDE 5.25 and newer, GNOME 48 and newer), hold to talk included. Where the portal is missing, Hollow falls back to in-app shortcuts instead of pretending
- Every shortcut is rebindable in place in Settings, not only the voice ones. Defaults are never written to disk, so a binding you never touched follows the app if we change it
- Fixed a stored keybind Hollow could not parse killing that one action silently. It now falls back to the default and records why
- Fixed push to talk cutting off mid-sentence when a modifier key changed while you were still holding the trigger
- A DM call and a server voice channel can no longer run at once (issue #49). Starting or answering a call leaves the channel, and both the ringing card and the call buttons tell you before it happens

LINK PREVIEWS (issue #45)

- Fixed the long-standing "link pasted, no preview". The compose box waits 600ms before fetching, so sending quickly used to lose the card entirely. It now attaches afterwards, as its own signed update
- Cards rebuilt around large image, video, music and article layouts, chosen by what the site declares about itself
- A direct mp4 or webm plays inline when you tap it. Receiving a card never makes your client fetch anything, so opening a chat does not tell a website you were there
- Previews now ride sync, so someone who joins later or a device you just linked gets the card too. Before this they reached only whoever was online at the moment it attached
- A tall poster no longer swallows the message. Media is contained rather than stretched to the source shape
- A card that arrives late does not mark the message as edited
- X and TikTok are read through their own public endpoints straight from your client, with no Hollow-operated proxy in between
- There is a switch to turn previews off entirely

SERVERS & CHANNELS (issue #32)

- Channels can be gated on labels: pick which labels get in, and holders of any of them can see or post alongside Admins and the Owner. This is enforced by encryption rather than hidden in the interface, so someone without the label holds no key to that channel's messages or its voice audio
- Temporary access grants (15 minutes, 1 hour, 24 hours, or until revoked) that expire on their own and drop the person out of voice when they lapse
- A label that carries access can never be self-assigned, checked both when it is set and again when the change arrives, so an edited client cannot work around it
- Bulk-apply access across a whole category, plus a searchable member picker shared by the label and grant dialogs
- Member actions moved onto the profile card (issue #48): Message for friends, and for staff a Manage Member dialog covering roles, labels and temporary access, reachable from wherever you clicked the person

PUBLIC CHANNELS (issues #42, #44)

- Guests see real file cards now instead of a bare filename. Images load near the viewport, everything else on demand, and file serving checks access rather than answering anyone who asks
- Voice channels can no longer be published. A published one used to appear in the browser and then vanish
- Fixed mentions-only notifications firing on everything (issue #42). The "replies to you" test could never be false, so every message counted as a mention
- Channel settings toggles no longer flip back for a moment while the change is saving

STICKERS & GIFS (issue #36)

- One sticker or GIF per message, matching how everyone else does it. The picker stays open, so a vertical stack is just repeated clicks. Inline emotes are still uncapped
- Sticker packs are usable at last: create an empty one, add to it from the sticker menu, save a KLIPY sticker in a tap, and export or import a pack as a file
- A pack travels as a file, never a link. Hollow has nowhere to host bytes, so a link would mean either serving strangers from your own machine or putting a central server in the middle
- Import trusts nothing in the file: every image is re-hashed and re-decoded, and dimensions come from the decoded picture rather than what the manifest claims
- Fixed a hairline gap between tiled stickers that showed at some zoom levels and not others

FILES & STORAGE (issue #41)

- Portable mode: drop a portable.txt file next to the executable, or use the separate portable download, and everything lives in hollow_data beside the app instead of in your user folder: identity, database and downloaded files
- Profile switcher (issue #47): keep separate data folders and switch between them in Settings, with rename and erase. Useful for a second identity, or for testing
- Auto-download gains an Off setting and per-conversation overrides, so you can leave it off in general and on for one person
- Senders now check your preference before pushing bytes you would only throw away, instead of sending them and having you discard them at the door
- Voice messages are exempt from the size gate, so a voice note always arrives
- Images carry a small blurred placeholder and videos a poster frame, so a file you have not downloaded still looks like something
- Fixed manual download of a file over 34 MB failing after a restart

PRIVACY & SECURITY (issue #46)

- Closed seven authorization gaps on the relay found by a code audit. None of them touched encryption: message contents, key material and who sent what were never at risk, because every forwarding path already stamped the routing header with the authenticated sender
- Removed an endpoint that handed valid TURN credentials to anyone who asked, which made our relay bandwidth farmable by strangers
- Removed a broadcast opcode that forwarded a frame to a whole room with no membership check at all, and gated its sibling on membership
- Room probing and peer discovery now answer only for rooms you have actually joined. DM room codes are derived from the two people's identities, so answering for any code turned a pair of identities into an "are these two talking" lookup
- Any one member could previously wipe a room's shared catch-up buffer. Clearing is now non-destructive and frames simply age out on the normal sweep
- The offline message buffer evicts fairly under pressure: whoever occupies the most slots loses their oldest frame, so a flood can only displace its own traffic. Deliberately not a rate limit, which would drop legitimate bursts (one channel post is one frame per offline member)
- Hollow Share runs on its own direct connection and refuses relayed routes outright. It used to reuse whatever connection you already had with that person, so with "Always relay calls" on, every byte of a large file went through our relay. The Share dashboard already promised direct transfer, and now that promise is true

DESKTOP

- The Windows tray icon is always present now, not only after you close to tray (issue #50). Right-click gives mute, deafen, leave voice, settings and quit; the tooltip mirrors your connection state, and the icon carries a red dot while anything is unread. macOS and Linux tray behaviour is unchanged
- Fixed AltGr firing shortcuts instead of typing on AZERTY layouts (issue #43). Windows reports AltGr as Ctrl and Alt together, so @, euro and brackets were being swallowed app-wide
- A default ringtone now ships with the app (contributed by [Rong-Yao](https://github.com/Rong-Yao) in issue #39), so an unset ringtone is never silent
- The microphone test in Settings was rebuilt on the call's own capture path (issue #40). It uses the constraints a real call uses, shows a live meter and plays you back through your chosen output, and works on PipeWire systems where the tool it used to rely on does not exist
- Voice messages on Linux now record through PulseAudio directly, for the same reason

INTERFACE

- Fixed proportions falling apart at high interface scale (issues #20, #37). Zooming in shrinks the logical screen, so every fixed size grows as a share of it: at 200% the server banner took nearly a third of the channel column, and voice participant rows were the smallest text in the app while sitting next to member rows half again their size
- The Home dashboard's side columns were clipped with no way to scroll them. They scroll now, and a narrow window drops the network column instead of squeezing everything
- Swept overflow out of the user bar, stat bars and dialogs at large OS text sizes, which the desktop build passes through unclamped
- Fixed the speaking indicator never lighting for yourself (issue #37). Your microphone level was being read from somewhere that does not report one, so it was always zero. It is measured in the audio pipeline itself now, right after noise suppression
- Video calls show speaking on the camera tiles, and the sidebar cue is an outline around the avatar instead of a dot beside it
- Fixed clicking in a zoomed chat jumping the view, and an edge drag that kept scrolling after you let go (issue #35)
- Saved messages toggles off like the buttons beside it, instead of reading as a dead press
- The System Status card on Home expands on tap like the banner does, so a long notice is readable in a narrow column

RELAY

- The relay's public port went from 400 Mbps to 1 Gbps, at no cost, as part of a change to our host's product range

v0.9 - GIFs, Stickers, Server Banners & Voice Encryption Fix (BREAKING for voice channels)

BREAKING CHANGE: Server voice channels are NOT compatible between 0.9 and 0.8.5 or older. Encryption in voice channels was never actually engaged on older builds (issue #27), and fixing it changes when keys are applied. Everyone in a voice channel needs to be on 0.9. Messages, DM calls and everything else are unaffected.

GIFS (issue #26)

- New GIF picker in the message box: Popular, search, and your own Favourites and Recent. Favourites sort into lists you name yourself
- Picking a GIF re-encodes it locally and sends it as encrypted bytes like any other attachment, so whoever receives it never makes a request to KLIPY or anyone else to display it
- Search runs through a Hollow proxy that keeps no logs: KLIPY sees one server and a random id per request, never you
- Optional own-key mode (Settings > Network): paste your own KLIPY API key and the app talks to KLIPY directly, for your own rate limit and zero dependency on our server. This is not a privacy win and the setting says so plainly, since KLIPY then sees your IP address and every search you make under one stable key
- In own-key mode the app only loads media from an allowlist of hosts you control, and anything it refuses is remembered and offered in Settings with an Allow button, so a CDN move never needs an app update
- Content rating filter (G / PG / PG-13 / R, default PG-13). Servers not marked NSFW cap results at PG-13
- GIFs autoplay in the grid while visible, behind a toggle that is on by default. The GIF search cache has its own 200 MB limit, separate from the emote and sticker cap

STICKERS (issue #29)

- Sticker packs on your servers (covered by the existing Manage Emotes permission) plus a personal vault that works in every chat, DMs included
- Search KLIPY's sticker catalog from the same picker. Transparency is preserved end to end, so a cut-out sticker still reads as a cut-out instead of arriving on a white box
- Stickers sent next to each other tile into a gapless mosaic, whether that is several in one message or several messages in a row from the same person
- A sticker is identified by its contents rather than its name, so two stickers can share a label and the pack is what groups them. There is no naming prompt on upload

SERVERS

- Server banners (issue #25): a wide image across the top of the channel list, animated GIF or WebP supported. Owners and Admins set it in Server Settings, on desktop and mobile
- Animated server icons: the icon in your server strip can move now. The still frame stays in the server state and the animation replicates separately, so someone on an older client still sees a correct static icon
- Banners, icons, emotes, stickers and GIFs now share one store underneath, addressed by content. Image bytes never ride the relay's message path, and members pull only what they are missing
- Hardening: image data another client sends that we never asked for is now refused outright instead of being cached

VOICE & CALLS

- Fixed garbage or one-way audio in server voice channels (issue #27). Encryption in voice channels was never engaging: starting a screen share flipped it on for the sharer alone, and the next key change left them encrypting while everyone else had no way to decrypt, so one side heard noise and the other heard silence. Voice encryption now engages for every participant from the moment they join
- Added a self-healing ladder behind it. If a participant's keys go stale the app re-applies them, then re-sends the current key, then rebuilds the group's encryption, instead of leaving the channel broken until everyone reconnects
- Fixed a case where an encryption update that removed your own device left you unable to send or receive in that server until a restart
- Fixed deafen leaving some people in a group call still audible: one failing volume write used to abort the whole loop partway through
- Fixed a crash when leaving a voice channel while it was still connecting
- Screen shares that are stopped and restarted now re-encrypt cleanly instead of coming back silent
- Fixed the app dying on Linux the moment the screen share picker opened in a Wayland session (issue #30). Wayland hands out no window list at all, so the picker now offers whole screens only and your desktop asks which one to share. X11 sessions are unchanged and still list individual windows. Wayland window picker is a follow-up to do

PRIVACY

- New "Always relay calls" toggle (Settings > Security), off by default. On a direct connection the other people in a call learn your IP address, because encryption protects the contents of a call and not the network path. Turning this on forces every real-time connection through the relay, so participants only ever see the relay's address
- The toggle now also applies to a voice channel you are already in. It used to be read once when you joined, so everyone who joined afterwards was still handed direct connections

INTERFACE

- Fixed dead clicks and off-screen tooltips at interface scales below 100% (issue #20). The bottom dock and the right end of the friends bar stopped responding to the mouse, and the dead strip grew the further you zoomed out
- Fixed the Browse / Share / Archive / Conferences tabs getting stuck (issue #28): a conference could not be closed, and clicking a server selected it underneath while the conference dashboard stayed on top. All four buttons now toggle, so pressing the lit one takes you back out
- Fixed the connection indicator disagreeing with itself (issue #23). The dock said Online while the same account's server header said Connecting forever, and the channel header said Offline whenever nobody else happened to be around. Both bars now read from one source, sync progress can refine that reading but never contradict it, and an empty room says "Only you" instead of "Offline". Offline now genuinely means your own connection is down
- Fixed the members panel button doing nothing at higher interface scales. The panel stays available at every width the desktop layout runs at, and remembers whether you had it open
- Tooltips now measure themselves instead of estimating, so they sit correctly at large text sizes
- Horizontal strips that a plain wheel mouse could not reach (GIF favourite lists, Server Settings tabs, the server strip in the dock, the emoji picker and friends manager tabs) now show arrows and pan on the wheel whenever they overflow
- A GIF or sticker sent with text now renders at full size with the text as a caption underneath, instead of shrinking the image down to the height of the line

STORAGE

- Files & Storage gains an asset cache section with its own cap (default 512 MB, desktop and mobile) and a clear-unreferenced action. Clearing never drops a sticker or emote your own sets or your servers still reference

PERFORMANCE

- Emote and game searches are much faster. Images are no longer downloaded inline with the results: a cold FrankerFaceZ search took 3 to 6 seconds before it returned anything and now takes about half a second, with the curated set appearing instantly
- Fixed website lookups (emote and game search) sometimes waiting out their full timeout without ever being sent, when the database was busy at the same time

v0.8.5 - BREAKING CHANGES: security patches, bug fixes, accessibility improvements

NOTE: Previous clients are NOT compatible with the new 0.8.5 because of breaking changes in how encryption and signatures are handled. Please make sure to update your client to the latest version!

SECURITY

- Important security patches and bug fixes

ACCESSIBILITY

- Added in-app font size and layout scale adjustments

v0.8.1 - Noise Suppression, Voice Chain Completion & Screen Share Quality

NOISE SUPPRESSION

- New noise suppression for your microphone (Settings > Audio): a neural network strips keyboard clatter, fans, and room noise while keeping your voice natural. Runs fully on-device on every platform, and if the engine can't run for any reason the classic suppressor re-arms automatically so a call never sits unprotected
- Desktop gets an Engine selector: RNNoise (default, ultra-light) or DeepFilterNet3 (heavier, deeper cleanup), switchable live mid-call without reconnecting

VOICE QUALITY

- Voice Enhancement's Dynamic mode now lifts quiet speech: soft talkers and word tails get a speech-only boost (up to 8 dB) while the noise floor between words is pushed further down. The boost keys on actual speech, so fans, tones, and steady noise get zero lift
- Both enhancement modes gain a de-esser that tames harsh "s" sounds without dulling the voice
- Voice in calls now streams at triple the audio bitrate (96 kbps, up from 32), audibly cleaner and fuller
- Android and Linux mics had been running a reduced enhancement path since the chain shipped; they now get the full studio EQ, de-esser, and limiter like Windows
- Music or video sound from a screen share can no longer re-calibrate your mic's auto-level and bury your voice: the auto-level now freezes while you're muted or while share audio is playing

SCREEN SHARE

- Desktop screen shares now ride a custom-patched WebRTC engine that knows it's encoding a screen instead of a webcam: shared text stays sharp instead of turning to mush
- New content profiles in the share dialog: Sharp text (holds resolution for reading) or Smooth motion (holds framerate for video and games)
- Fixed share quality settings silently never applying on Windows and Linux (bitrate, framerate, and resolution caps were dropped by the engine), and fixed the resolution preset being ignored entirely: receivers were getting native resolution no matter what you picked
- Resolution presets are now limited to what your connected displays can actually produce
- Share audio gets a volume slider on every call surface, auto-ducks while someone speaks so voices stay on top, and deafen now silences it too
- Fixed Android freezing with an "app not responding" dialog when stopping a screen share

CALLS

- Hanging up no longer briefly freezes the app: audio teardown was blocking the interface thread on every platform
- iOS: your speaker choice now sticks. Turning the camera on or off, or an incoming screen share, no longer flips the call back to the earpiece
- Android: the microphone now survives backgrounding the app during calls and screen shares, and muting or unmuting no longer freezes the interface for seconds
- Call setup problems now leave a trace in the diagnostic log instead of failing with zero evidence

SERVERS & ROLES

- Fixed server settings changed by Admins reverting: once the Owner had ever written a setting, rename, role, or nickname, no one else could durably change it, even with full permission. The latest authorized write now wins everywhere
- Fixed mobile's role "Reset to defaults" silently stripping Admin permissions, and added the missing Manage Emotes toggle to the mobile role editor
- A friend request sent to someone's temporary nickname could queue forever if they use multiple devices; it now arrives immediately
- Channel file downloads now reroute to any online member who holds the file when the original sender is offline, and files no longer silently skip some single-device members
- Fixed the Twitch integration toggle not saving when switched off on mobile

INTERFACE & FEEDBACK

- No more lying toasts: friend requests, nicknames, message send/edit/delete/pin, reactions, and channel setting toggles now show an error and roll back when they fail, instead of claiming success on a dead connection
- Slow operations now show busy indicators: archive loading, backup export and restore, sharing a file, and the security actions
- Avatar, banner, and server icon updates preview instantly while processing, and Save waits for processing to finish: an early Save used to silently drop your new image, and the first server-icon upload used to appear to do nothing
- Uploading a custom emote now opens the naming dialog instantly with a live preview
- Mobile: profile sheets with long showcases no longer trap you inside, and the game card's close button is always reachable
- Phones and tablets now always get the mobile interface (tablets and landscape phones used to cross into the desktop layout), and mobile is locked to portrait

NETWORK & STABILITY

- Fixed a rarer class of frozen connections: a wedged link could hang all networking forever, including the watchdog that was supposed to catch it. Sends now time out and trigger a clean reconnect
- Privacy: the WebRTC engine's debug logger was writing relay frame contents to the Android system log in release builds; logging is now capped
- New quiet performance sentinels record anomalies (interface stalls, audio gaps, engine backlogs) in the diagnostic log, so bug reports can pinpoint causes much faster

v0.8 - Offline Delivery, Custom Emotes, Conferences, Mobile Screen Share & Moderation

OFFLINE DELIVERY

- Messages sent while you're offline now arrive when you come back: the relay temporarily holds encrypted DMs and channel messages (it cannot read them) and replays them on reconnect, so the sender no longer has to be online at the same time as you
- DM offline delivery is on by default with a 3-day window, adjustable (1 / 3 / 7 days) in the new Offline Delivery settings card; small images are included
- Server channels get the same catch-up, on by default and controllable per server by Owners and Admins in a new Offline Catch-Up section

CUSTOM EMOTES & EMOJI

- Custom emotes: upload still or animated emotes to your servers (up to 50, with a new Manage Emotes permission) or keep a personal set that works in every chat; use them in messages and reactions
- Emote images sync between members privately and efficiently: recipients never contact any outside website to display an emote
- FrankerFaceZ integration for building your emote set, opening to a curated selection of ~110 popular emotes
- Redesigned emoji experience: a unified picker with 1,907 searchable emojis, recents, and Server / Mine / FFZ tabs on desktop and mobile, and typing ':' now offers emote and emoji autocomplete in every composer
- Emotes render as actual images inside the message box as you type, and notifications display emotes properly too: in-app banners show the real image, system and push notifications show :emote-name: instead of raw code
- Fixed emoji showing as empty boxes on Windows and Linux by bundling a color emoji font

CONFERENCES

- New Conferences: Zoom-style meetings you host and join by link, no server or friend request needed. A waiting room lets the host admit or decline each participant before they can enter
- Admission is enforced by the encryption itself: being let in is what grants you the meeting's keys, kicking someone rotates them, and every meeting starts with fresh keys so past attendees can't decrypt the next one
- Meeting chat is ephemeral by design: messages live only in memory during the call and are never written to disk
- Join via hollow://conference links or shareable web links (the meeting id stays out of server logs), with invite cards in chat. Mobile gets a first version of the conference screen

SAVED MESSAGES, BLOCKING & REPORTING

- Saved Messages: a private space to message yourself, with everything DMs support — file storage, search, archive export, and sync across your linked devices
- User blocking: blocked people can't send you friend requests, DMs, files, or calls — and blocking follows the person, so a blocked user's second device can't slip through. Their server messages are hidden (unblocking restores the history) and their activity never triggers unread badges or notifications. Manage the list in Settings > Security
- Reporting: report a user for spam, harassment, illegal content, or impersonation straight from their profile. Reports are fully anonymous — the relay keeps only per-target category counts, and who reported whom is never stored or logged

MODERATION

- Moderators can now mute members, for a set duration or permanently. Muted members see a "You are muted" banner with the remaining time, and the Members tab shows who's muted. A mute can't be bypassed by editing old messages or adding reactions — it's enforced everywhere, including encrypted channels
- Per-channel slow mode: set a minimum interval between messages (moderators and up are exempt), with a live cooldown countdown on the message box
- Media-only channels: only images, GIFs, and videos (with optional captions) can be posted
- All three rules are enforced on both the sending and the receiving side, so a modified client can't bypass them. Works identically on desktop and mobile

PROFILES & SHOWCASE BOARDS

- Showcase boards: curate your profile with blocks — text, Now Playing, Favorite Game, Game Shelf, and artwork/GIFs — which sync to other members like your avatar does, integrity-checked and with no outside connections on their end
- Game blocks are powered by a game database: a reception strip (Metacritic score, Steam review verdict, time to beat), genre and mode tags, credits, system requirements, and clickable store links, with an accent color picked up from the game's cover art
- Redesigned profile card with a cleaner layout, consistent between the quick popup and the full profile view on desktop and mobile; tapping someone in channel chat now shows their roles and labels
- Your board is safe around older app versions: a friend on an old client updating their own profile can no longer wipe your showcase
- Fixed animated GIFs fast-forwarding to catch up after being paused off-screen

SCREEN SHARE

- Phones can now share their screen — with device audio — into DM calls and voice channels, on both Android and iOS, with a pre-share sheet and an audio toggle. Your mic stays live over the shared sound (on Android 7-9 the audio toggle is shown as unavailable, since capturing device audio needs Android 10+)
- Android and iOS can now also hear a desktop's shared screen audio, at full music quality
- Linux gets screen-share audio in both directions: share your screen with system audio and hear others' shares. Sharing a single window captures only that app's sound, and whole-screen shares exclude Hollow's own audio so the call never echoes back
- Windows: sharing a specific window now sends only that app's audio instead of your whole system's sound, and entire-screen shares keep the sound Hollow itself plays (like a video opened in chat) while dropping the call voices so nothing echoes
- Smoother share audio for viewers: a small buffer absorbs bursty delivery from mobile senders, removing periodic micro-gaps in the sound

VOICE & CALLS

- Fixed joining a voice channel with a dead microphone (no one could hear you until someone toggled a camera) when either side uses more than one linked device: connection setup now elects exactly one leader, and a doubled join announcement can no longer create duplicate broken connections
- Fixed the microphone always sounding too quiet in calls and distorting when boosted: the engine's built-in auto-gain was fighting the Voice Enhancement feature and cancelling out every boost
- New Voice Enhancement chain: a studio-style EQ, compressor, and limiter on your mic, toggleable live mid-call, plus a Dynamic auto-level mode (on by default) that converges any microphone — quiet or hot — to a calibrated, consistent loudness
- Calls are audible out of the box: the default mic gain is doubled behind a soft limiter, and the gain slider is rescaled so the new default reads as 100%
- Changing your mic, camera, or speaker in settings now applies live to calls and voice channels you're already in — no reconnect needed (camera switching excluded on Linux for stability)
- Mobile DM calls get a camera flip button (reliable on phones with more than two cameras), and your own preview now mirrors only for the front camera
- Voice channel participants who use multiple devices now show their real name, avatar, and your nickname for them everywhere — sidebar, video tiles, picture-in-picture, and mobile — instead of a fallback avatar and a raw device id
- iOS: the loudspeaker toggle now actually switches to the speaker (and survives turning the camera on), and calls mix with other apps' audio instead of being interrupted by it

MESSAGES & CHAT

- Fixed permanent message loss: sending two identical messages in the same instant used to silently drop one, and messages arriving in a narrow window around a reconnect could be skipped forever — sync now overlaps a lookback window so nothing falls through the cracks
- Fixed conversations appearing in a different order on different machines when someone's clock was a few seconds off: messages now use a shared logical clock, so a reply can never sort above the message it answers
- Fixed an open chat going stale (typing indicator animating but new messages never appearing until reopen) and live channel messages dying after a connection drop
- Fixed ghost unread badges that only cleared by sending a message, stale badges reappearing on other channels of the same server, the mention counter always showing zero, and messages staying unread when you read them right after refocusing the window
- Smoother chat: new messages slide in without the whole list blinking or jumping, and if you've scrolled up to read, the view stays frozen with an unread pill instead of shifting under you
- Mobile chat now matches desktop: a "Replying to" bar above the composer, animated typing dots, and the same date separators and message grouping
- Sending files, images, and voice messages on mobile now shows the message bubble instantly with a progress indicator instead of waiting for the upload

FRIENDS & DIRECT MESSAGES

- Fixed direct messages that could silently never arrive when you and the recipient shared more than one room: messages now always take a dedicated, deterministic route
- Fixed friend requests that wouldn't go through until the sender restarted the app — they now deliver as soon as the two clients learn about each other
- Rejecting a friend request now fully cancels any request you had queued to that person, so a rejection can't silently turn into a friendship later; two people requesting each other at the same time now become friends automatically

MULTI-DEVICE

- A full audit fixed a batch of cases where encrypted-group recovery, friend requests, and vault storage could silently fail to reach people who use multiple devices
- Leaving a server now fully takes effect on all your linked devices — previously a leftover copy could resurrect the server after a restart
- Fixed late joiners of a voice channel losing their data channel (screen-share audio, file transfers) to viewers with multiple devices
- Server permission checks now respect custom role overrides everywhere, not just the default role powers
- iOS: tapping a DM push notification right after a cold app start now opens the correct conversation instead of an empty thread

LINKS & INVITES

- hollow:// links now open the app directly on all platforms — even from a cold start or with the app hidden in the tray — and take you straight to the right dialog
- Server invites now copy a shareable web link that opens the app if you have it or offers the download if you don't, and the invite id never appears in server logs. Web links paste correctly into every "Join a Server" input, and both link forms render the same Join card in chat

NETWORK & RELAY

- The relay now works over IPv6 as well as IPv4, including call connectivity on IPv6-only networks
- Added a fair-use daily relay data budget (10 GB per connection per day) to protect the shared relay, with a clear "bandwidth limit" notice instead of silent failure and a usage meter on the Home screen and mobile Settings showing usage and reset time
- Fixed the daily data meter jumping by megabytes on every restart: profile announcements no longer re-send full avatar and banner images to everyone on each reconnect — images transfer only when someone actually needs an updated copy
- Missing-file re-downloads are now scoped to the conversation you have open, ask a single source, and stop endlessly retrying files that no longer exist; moving your data folder no longer makes existing files show up as "missing"
- Big servers now use far less relay bandwidth: group-encryption updates go out as a single broadcast instead of one copy per member, and routine server updates travel peer-to-peer when possible
- Fixed "zombie connections" where the app looked connected but received nothing until restart: the dead link is now detected within about a minute and reconnects automatically
- Voice/video connection credentials now travel over the app's authenticated encrypted connection instead of a separate web endpoint

NOTIFICATIONS

- In-app notification cards no longer pile up and replay old messages: opening a conversation dismisses its pending notification, and exactly one surface shows per message — a system toast when the app is hidden, an in-app card when you're focused elsewhere
- Fixed a stuck notification group header on Android that could linger after dismissing DM notifications
- Privacy: decrypted message content and device-link pairing codes are no longer written to diagnostic logs

PERFORMANCE & STABILITY

- Full-stack performance pass: chat lists, calls, and video tiles do far less unnecessary work, and sending GIFs or images and background vault work no longer stall the networking engine
- Linux: fixed random crashes during calls (a memory bug in the video-call plumbing, fixed for all platforms), crashes when toggling the camera mid-call, empty mic/speaker pickers on PipeWire systems, and the annotation overlay rendering as a black screen
- Calls and screen shares now fully release their resources on every hang-up path, fixing gradual memory growth across long sessions
- Fixed a "Node is not running" crash during startup, a crash when someone on a call or transfer dropped their connection, and several potential crashes from screens acting after they were already closed
- Archive viewer: "jump to date" now actually works, the search field no longer collapses when the match counter appears, and imported channels show the server's name instead of a raw id
- Hollow Share: downloads of hidden files now stay hidden in your file list, and your daily seeding budget is no longer wasted on chunks another relay was already handling
- Vault downloads that hit a temporary hiccup now retry automatically instead of silently stalling

PLATFORM, PRIVACY & LEGAL

- New system status banner: maintenance windows, outages, and announcements now appear in the app with severity colors and a live countdown, delivered from the website so it still shows even when the relay itself is down
- Windows: the app now bundles the Microsoft VC++ runtime, so it launches on fresh Windows installs instead of failing with "VCRUNTIME140.dll was not found"
- "Verify a Proof" is now available in mobile Settings > Security, and all "account" wording is renamed to "identity" to match how Hollow actually works
- Updated the Privacy Policy and Terms to accurately describe everything shipped recently: offline message buffering, the relay fair-use limit, push notifications, anonymous reports, and local-only blocking; game-showcase searches are proxied so your search text stays out of web server logs

v0.7.1 - Screen Share Audio on Mac, Accessibility & Data Channel Fixes

SCREEN SHARE & RECORDING

- Screen-share audio now works on macOS (13.0 or later), sending crystal-clear system audio to everyone in the call over the same data channel Windows uses. Below macOS 13.0 the audio toggle stays locked with a note, since Apple exposes no system-audio capture API there
- The sender no longer hears the call echoed back into their own share: Hollow now excludes its own output (the other people's voices) from the captured audio
- Call recording on macOS now produces valid, playable MP4s. A bad audio frame used to cascade into a broken file with no recoverable video; the recorder now guards every track so one rejected frame can't corrupt the whole recording
- The record button is now correctly disabled on macOS below 13.0 (where the native recorder doesn't exist) with a tooltip, instead of looking clickable and failing

MULTI-DEVICE

- Fixed data channels (screen-share audio, file transfers, vault shards, Hollow Share) never opening between two people who each use more than one device. The connection now agrees on a single identity to break the call-setup tie, and matches replies by connection instead of by device id, so the channel opens reliably

ACCESSIBILITY

- Screen reader support (VoiceOver, TalkBack): every interactive control now announces its purpose, so the app is fully navigable by voice. A built-in check keeps it that way as the app grows
- Full keyboard navigation: every button, toggle and control is reachable by Tab and arrow keys and activates with Enter or Space, with a clear focus ring that stays visible on any background
- Larger Text: the interface now holds up at the full range of the operating system's text-size setting, up to 2x, without clipping or overflowing
- Reduce Motion: a new Auto / On / Off control that combines with your OS setting, plus a Reduce Transparency option that drops dialog blur and makes panels opaque
- Improved contrast on timestamps, links, mentions, counters and status text to meet accessibility standards, with dedicated darker variants for the light theme
- Differentiate Without Color: presence is now shown by shape (filled dot for online, hollow ring for offline) as well as color

PLATFORM & ENGINE

- Upgraded the underlying WebRTC engine to a current stock build for better stability across all platforms, with no change to how anything behaves

v0.7 - Multi-Device Fixes, Channel Encryption Hardening & Storage Manager

CHANNEL ENCRYPTION

- Restricted channels are now encrypted under their own per-channel MLS subgroup instead of the server-wide group, so channel visibility is cryptographically enforced: a member who can't see a channel never receives a decryptable copy, even with a modified client
- This now covers voice too: a restricted voice channel derives its SFrame media key from the channel's own subgroup, so a non-qualifying member can't derive the key and is rejected from joining. Demoting someone mid-call re-keys the remaining participants and drops the demoted member
- Channel visibility and posting-access changes now take effect immediately in the UI on both desktop and mobile, and anyone viewing a channel that becomes hidden is moved out of it automatically

MULTI-DEVICE

- Fixed one-directional DMs between two fresh friends: a race between the friend-request handshake and key exchange could leave one side unable to send. Both sides now re-key promptly instead of waiting on the recovery sweep
- Fixed remove-then-re-add of a friend (while both online) silently auto-accepting with no consent prompt
- Server channel chat now shows a sender's real name, avatar and verified signature across all of their devices, instead of a raw device id with a generic avatar. Older messages stored before this fix self-heal when a verified copy syncs in
- Multi-device push notifications now reach a fully-quit phone: the wake-and-fetch node connects as the correct device, so a buffered message is delivered and decrypted rather than lost
- Reset Device List is now a real propagating revocation: every other device is tombstoned in one step, your friends drop them, and each removed device wipes itself

VOICE & CALLS

- Fixed quiet voice calls on every platform: a native makeup-gain stage with a soft limiter now runs after WebRTC's automatic gain control, and the mic-gain slider finally affects your outgoing audio (it was previously a no-op on the send side). Range is 34%-200%, applies live mid-call
- Earpiece proximity (screen blanks when held to your ear) now works for any active call from any screen, not just while the call sheet is open

STORAGE

- New "Files & Storage" settings category with a storage dashboard: total usage, a segmented Downloads / Vault cache / Held shards bar, a per-conversation breakdown with inline clear, and a cleanup menu
- The downloaded-files cache cap and vault cache cap are now actually enforced (they were no-op sliders before). Clearing file bytes keeps the message so it stays re-downloadable
- Files larger than 34 MB now prompt a "Send as Share" confirmation instead of silently auto-converting or rejecting. Hollow Share now works in DMs too
- Fixed a sender-side disk leak that left a duplicate encrypted copy of every relayed file on the server

NOTIFICATIONS

- Desktop: native OS toasts now fire whenever the window is unfocused (not only when minimized to tray), with rich Windows Action Center toasts (avatar, sender, message line, inline Reply). In-app notification cards show whenever the window is visible
- Mobile: a real OS notification is posted when the app is backgrounded but still connected; in-app banners now appear only while you're inside a different chat
- Added @mention autocomplete to the mobile channel composer

INTERFACE

- Redesigned the desktop Settings panel: a searchable side rail of ten focused categories with a card-based layout, replacing the cramped five-tab dialog. Settings now auto-save on change. Mirrored the same split on mobile
- Connection status now reflects the real relay WebSocket state instead of just "node started", and greys out when the relay stops responding
- NSFW servers: an is-NSFW server setting with a "proceed at your own risk" consent gate on join, plus an NSFW badge in the chat header
- Channel and DM header polish: accurate online/offline and Encrypted status for multi-device members, NSFW badges, and cleaner DM header naming

PRIVACY & ENGINE

- Removed debugging logs from the relay (were left during initial experimenting) that could fingerprint who talks to whom: every line printing a peer id, room, push target, channel, server or token was removed, leaving only aggregate counts
- Server-group MLS recovery hardening: the server owner is now the preferred coordinator for member changes, and CRDT operations are mirrored in plaintext alongside MLS so an out-of-sync member can't permanently lose server metadata such as a newly created channel

EDIT:

- Fixed the Flatpak build crashing on launch by bundling the missing libsecret library into the sandbox.

v0.6 - Multi-Device Sync, Code Signing & Push Notifications

MULTI-DEVICE SYNC

- Link a new device to your identity with a 6-character code. The new device pulls your full identity and encrypted database from an online one, no QR codes
- Your friends see you as ONE online identity across all your devices, not several strangers (presence, profiles, typing, DMs all collapse device to person)
- DMs sync across your devices: messages you send from one device mirror to your others, and a friend will re-serve messages you sent from a device that was offline (sibling backfill)
- Servers and channels are now fully multi-device: each device holds its own MLS encryption leaf, so channel messages and typing reach every one of your devices
- Server lifecycle converges across your devices and offline members: create, delete (tombstone-based), kick, ban, roles, pins, layout and settings all reconcile on reconnect
- Manual sync escape hatch: a "Sync from this device" button per device under Settings > Security > Your Devices
- "Your Stats" card on Home (Friends/Servers/DM messages/Devices) to eyeball-compare sync state across devices

DEVICE REVOCATION

- Revoke a lost or compromised device from any device you control (Settings > Security > Your Devices)
- A revoked device wipes its local data and returns to Welcome the moment it learns it was revoked
- Revocation is enforced cryptographically: the revoker drops its encryption session to the dead device, and your friends stop sending to it

PUSH NOTIFICATIONS (ANDROID & iOS)

- Direct-message push notifications with the decrypted message content in the banner
- Server channel push notifications, filtered by your per-server/per-channel notification preferences (mute, mentions-only, all)
- Captioned image DMs delivered while offline, with signatures preserved
- Grouped, per-sender notification banners with mention awareness ([@everyone](https://youtu.be/dQw4w9WgXcQ) / [@you](https://youtu.be/uOzPqiRpumc) / replies)
- iOS: rich banners (sender name + avatar) and on-device decryption even when the app is force-killed, via a Notification Service Extension that fetches and decrypts without ever putting your message content in the push itself (no metadata leak to Apple/Google)

PLATFORM & ENGINE

- macOS: native traffic-light window controls and a startup-flash fix
- Automated multi-node test harness for future development: spins up N real nodes in one process through an in-process relay, verifying the distributed-logic core (DMs, server joins, MLS formation, channel decrypt, device revocation, calls, file transfer, voice channels) on every push, in CI. Easily expandable, really useful for debugging, fixing bugs, and implementing new features
- Windows code-signing and Inno Setup installer pipeline
- In-app Help resource center
- Microsecond message ordering to fix same-millisecond message interleaving
- Storage hygiene: removed startup VACUUM/shard-probe contention and stderr noise
- Server access controls, chat profile popups, busy-call toast, and Hollow Share STUN-only warning

v0.5 - macOS Release, Cross-Platform Auto-Updater & Mobile Port

NATIVE macOS RELEASE
- First fully signed and notarized macOS build (Developer ID + Hardened Runtime, stapled)
- Universal binary: runs natively on both Apple Silicon and Intel Macs
- Proper app identity: "Hollow" name and the real Hollow icon throughout the Dock, menu bar, and Launchpad
- Native window behavior: closing the window keeps Hollow running in the Dock with the active dot (the macOS-native idiom); click the Dock icon to reopen — no more odd minimize-to-taskbar
- Requires macOS 14.2+ (full feature set including screen-share system audio)

CROSS-PLATFORM AUTO-UPDATER
- The in-app updater now works on macOS, not just Windows
- macOS updates swap the .app bundle in place (ditto-based), preserving the code signature, then relaunch automatically
- Per-platform release manifest: each OS downloads the correct build
- Quarantine handling so updated builds launch without friction

EXPERIMENTAL MOBILE SUPPORT (ANDROID & iOS)
- Full mobile port with every feature ported from the desktop version
- Universal APK for Android (7.0 to 16); iOS needs a proper App Store/TestFlight release

OVERALL IMPROVEMENTS
- DM call voice activity detection with animated speaking border
- Mic gain slider in audio settings; mid-call changes apply live
- Offline peer profile fetching via relay proxy
- Temporary nicknames for friend requests (relay-scoped, ephemeral)

PLATFORM & ENGINE
- Flutter 3.44 upgrade
- MLS secret tree persistence and recovery-sync fixes
- Olm key exchange glare resolution, voice channel plaintext fallback, edit-sync and peer-liveness fixes

v0.4.2 - Identity Protection Patch, Linux/Android Support (Experimental)

IDENTITY PROTECTION REDESIGN
- Replace raw DPAPI blob storage with Windows Credential Manager (CredWriteW/CredReadW) as primary, DPAPI blob as fallback — dual-write on store, auto-migration on retrieve
- Remove silent auto-encryption: plaintext identities are never automatically encrypted by DPAPI. All protection is now explicit opt-in from Settings → Security
- New "Ask for password on launch" toggle: when password is set, toggling this off caches the password-derived key in OS keychain (flags=0x03) — identity file stays encrypted but the app opens silently on the same device
- Password removal now writes plaintext instead of silently transitioning to keychain-only encryption
- Change password preserves the launch toggle setting and updates keychain if in silent mode
- Backup import no longer auto-protects restored identities
- Device Protection section in Settings for standalone OS keychain encryption (no password)
- Updated security descriptions to clarify that password protects both identity and app access

TESTING & CI
- 46 new unit tests for CRDT operations, server state, identity, and platform keystore
- Windows Credential Manager round-trip and dual-storage tests

EXPERIMENTAL LINUX SUPPORT
- Flatpak package for all Linux distros (28 MB, Freedesktop 24.08 runtime)
- Window close minimizes to taskbar — app stays running in background
- Taskbar right-click Quit for clean shutdown
- XDG desktop integration (app icon + launcher entry auto-installed)
- Core features working: messaging, servers, file transfers, screen share
- Known limitations: mic test in Settings unavailable, voice calls untested on real hardware

Install: flatpak install --user hollow-0.4.2-linux-x86_64.flatpak
Run: flatpak run com.anonlisten.Hollow

EXPERIMENTAL MOBILE SUPPORT
- Universal APK for Android (versions from 7.0 to 16)
- iOS should work too but needs a proper App Store release

v0.4.1 - Public Channels, Identity Protection, Native Screen Sharing & Bug Fixes

IDENTITY AT-REST PROTECTION
- Two-layer encryption for identity.key: optional app password (Argon2id + AES-256-GCM) and automatic OS keychain binding (DPAPI on Windows, Keychain on macOS)
- Full-screen lock dialog on launch with retry loop, recovery via 24-word mnemonic
- HKEYV1 file format with backward-compatible plaintext auto-detection
- Settings → Security tab with App Lock section

PUBLIC CHANNELS
- Per-channel public flag (globe icon in channel settings, MANAGE_CHANNELS permission)
- Guest sync protocol: non-members can browse public channels read-only
- Paginated message history serving (50 per batch, latest first)
- Sender profiles with 64×64 WebP avatar thumbnails for guest viewers

PUBLIC CHANNEL BROWSER
- Globe icon in bottom bar toggles a first-class browsing panel (Share/Archive pattern)
- Saved servers persist to SQLCipher with configurable fetch modes (real-time, on-launch, manual, periodic)
- Accordion sidebar with tree-style channel indentation and SelectionShimmer
- Real-time streaming via SendToRoom broadcasts to guest WS room members
- Inline search, message proof dialog, right-click context menus

RELAY HARDENING
- Guest connection mode: invisible to members, max 3 rooms, 10 binary/min, no SendDirect, 30-min idle timeout
- Per-IP rate limits: max 34 connections/IP, 10 new/min/IP (in-memory, never logged)

NATIVE SCREEN SHARE
- Bypass libwebrtc's desktop capturer which ignores all resolution constraints
- Windows: Graphics Capture API + D3D11 native capture with bilinear downscale to target resolution
- macOS: ScreenCaptureKit with GPU-accelerated downscale, window capture support
- Thread-safe stop + always-scale path to fix GPU row pitch padding corruption

OLM KEY EXCHANGE & VOICE FIXES
- Fix dual KeyRequest glare: higher peer ID yields to prevent both sides creating outbound Olm sessions (MAC tag mismatch)
- Voice channel join/leave now always sends plaintext alongside MLS, surviving stale epochs

EDIT & SYNC FIXES
- Edited messages properly stamp edited_at during sync batch insert
- DM edits while peer is offline update the pending_messages queue in-place
- Pending messages preserved across WS disconnects (no more message loss during brief reconnections)
- Silence false edit rejections when the original message hasn't synced yet

PEER LIVENESS
- 60-second timer checks offline friends against the relay via check_peers command
- Re-joins DM/inbox rooms if relay confirms a friend is actually connected

v0.4.0 - Native Capture, Mobile Port & Optimization

ANDROID MOBILE PORT (In progress)
- Full custom mobile UI with 4-tab navigation (Chats/Friends/Archive/Settings)
- Mobile chat with profile sheets, voice messages, file sharing, link previews
- Emoji picker, channel search, server settings with permissions, unread badges
- Mobile design polish: ambient background, nav glow, shimmer line, dark splash screen
- App icons for Android
- Long-press message actions with quick reactions, inline edit, delete confirmation
- Channel management, posting/read permissions gating, sync status indicator
- Battery optimization exemption + WiFi lock for stable connections
- Text scaling clamped 0.8–1.3x

macOS DESKTOP PORT (In progress of Release)
- Full macOS desktop support (contributed by [DrFaust555](https://github.com/DrFaust555))
- VP8 codec workarounds, CoreAudio device handling
- Process Tap for system audio capture
- ScreenCaptureKit-based native screen share

SCREEN SHARE AUDIO (Windows)
- Out-of-process WASAPI capture with Opus encoding over WebRTC data channels
- Per-window audio capture on Windows 10 2004+ (process-specific via --pid)
- Separate capture/render executables to avoid ADM audio looping
- Cross-platform receiver (waveOut/AudioQueue/PulseAudio)

NATIVE SCREEN/CALL RECORDING
- Windows: Graphics Capture API + Media Foundation encoder (H.264+AAC MP4)
- macOS: ScreenCaptureKit + AVAssetWriter
- System audio + mic, no ffmpeg dependency for recording
- Screen-wide annotation overlay (draw during calls or whenever needed)
- Record voice/video calls locally
- Call UI sizing fixes

OPTIMIZED FFMPEG
- Custom minimal build: 164 MB → 5.9 MB
- GitHub Actions build workflow for reproducible cross-compilation
- Still used for voice message playback, but recording is fully native now

MLS ENCRYPTION FIXES
- Auto-recovery now works for any peer, including the owner losing their group
- Coordinator election excludes the sender (prevents recovery deadlock)

CLEANUP
- Vendored forked flutter_webrtc into the repo
- Replaced discontinued flutter_markdown
- Rust license compliance audit
- Chat edit scroll fix

v0.3.1 - Self-hosting & Performance (again)

RUST BACKEND PERFORMANCE (8-Phase Audit)
- WAL mode + PRAGMA tuning (synchronous=NORMAL, 8 MB cache, temp_store=MEMORY)
- One-time FTS5 rebuild (was rebuilding full-text index on every DB open)
- prepare_cached for 48 SQL statements across messages.rs + content_store.rs
- Pre-computed db_path/db_passphrase at event loop start, passed to all handlers (eliminated ~100 redundant identity loads)
- MLS state persist debounced to 2s dirty-flag timer (was serializing entire OpenMLS storage on every encrypt AND decrypt)
- Olm split: per-message ratchet persist vs full account pickle only on session lifecycle
- Skipped op_log in ServerState serialization (#[serde(skip_serializing)] on up to 1000 CrdtOps, 60-80% less JSON per CRDT mutation)
- Lazy envelope_json: moved serialization into Olm fallback branches (MLS success path skips entirely)
- Boxed fat MessageEnvelope variants (~405 -> ~136 bytes per enum, wire-compatible)
- Transaction-wrapped sync batch inserts (10-50x faster)
- CrdtStore flush batching
- Cached PeerId derivation in signature verification
- Zero-copy compute_delta for CRDT sync
- Batch file metadata queries (single IN clause instead of N queries)
- Cached peer_id on NativeKeypair struct (computed once at construction)
- All 14 crdt.rs FFI functions use STORE singleton instead of re-opening DB
- CACHED_PEER_ID OnceLock for role/permission queries (eliminates 7 identity loads + 7 DB opens per server switch)
- Serialize-once broadcast: send_raw_to_peer() for pre-serialized bytes across 8 broadcast loops
- Single prepare_upload() closure: eliminates redundant Reed-Solomon encoding (~340ms + ~70 MB per vault upload)
- std::mem::take for file buffers: zero-copy move instead of 34 MB clone
- Vault-only AES skip: generates key+nonce without encrypting when vault-only mode (6+ members, non-image)
- tokio::fs for 6 critical std::fs::read/write sites in file_handler.rs (prevents event loop stalls on 34 MB files)
- In-memory shard streaming: shards stream from Cursor instead of disk (~44 MB disk round-trip eliminated per vault upload)
- StateVector pre-computation: sv_cache built once per server before peer loops (20 peers x 5 servers = 100 computations -> 5)
- sign() returns [u8;64] instead of heap Vec<u8>
- Boxed fat NodeCommand variants (SendFile, VaultUploadFile)
- Voice rate-limit map eviction (>10 min idle, >16 entries)
- Mention parsing early exit when no @ present
- Combined count_unread_dm/channel into a single COALESCE query

DART UI REBUILD OPTIMIZATION
- Surgical .select() additions across 18 files to eliminate unnecessary provider rebuilds
- HollowAvatar watches only its own peerId in the avatar cache (was rebuilding ALL avatars on any load)
- ChannelMessageBubble watches only its sender's profile/nickname
- Unread and notification providers use .select() with instance methods for per-channel/server granularity
- ValueKeys added to unplaced channel tiles and member panel items
- RepaintBoundary wrapping for 3 CustomPaints (status_dot pulse, tree connector, crop overlay)
- WAL checkpoint before backup export (prevents data loss from unflushed WAL writes)

SELF-HOSTING SUPPORT
- Relay domain is now fully configurable (was hardcoded to relay.anonlisten.com)
- Rust FFI set_relay_url() passes domain through spawn_node() to ws_client and signaling
- All STUN/TURN/signaling URLs derive from the configured domain
- Welcome dialog has an Advanced section for first-launch relay config
- Settings System tab has a selectable relay list with Add/Remove and Apply & Restart
- ConnectionProgress shows "Custom Network" indicator when on a non-default relay
- Dockerfile + docker-compose.yml for one-command relay deployment with certbot + coturn
- .env.example and turnserver.conf.example templates for easy setup
- Full relay README with build, run, Docker, architecture, and security docs

CLEANUP
- Removed dead KickBot widget, legacy Rust relay, old loadtest dirs, duplicate root logos
- Removed dead CRDT relay_url code from swarm.rs
- Consolidated relay into main repo (hollow-relay archived)
- Rotated TURN secret on VPS, replaced with placeholder in repo