:::tip GitHub Releases
All production release binaries (Windows Desktop installer and Android APK), asset checksums, and version tag comparisons are published on GitHub Releases.
:::
Features
- Send one share encoding to every viewer who can take it
- Add a shared encoder that one share can send to every viewer
- Measure the share encoder instead of trusting its flag
- Copy a picture from a message or its preview
Bug fixes
- Share one encoding with every viewer and let channel names repeat
- Keep the call dock and its popovers clear of a shared screen
- Let channel names repeat and lift the layout caps
Other changes
- Point at the backlogged lower-quality share layer
- Describe one share encoder for every viewer
- Describe the measured share encoder and the hidden preview
- Stop drawing your own share while the window is hidden
- Document repeated channel names, layout bounds, the 409 mapping and copy image
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop | Built here |
| Android | Built here |
Features
- Page the pinned list and walk older history in search
- Search walks older history on the device in bounded batches
- Page the pinned panel with infinite scroll and a load-more button
- Page the pinned list with a keyset cursor
- Open earlier versions of an edited message from its marker
- Keep sealed prior versions on edit and serve GET /messages/:id/edits
- Add message_edits for sealed prior versions of an edited message
- Inject remote input on Linux X11 and macOS, and tell the viewer when it cannot
- Validate remote input events in the agent, with a pure key and scaling table
- Report real presence socket counts beside distinct accounts on the health page
- Key presence per socket so an account goes offline with its last device
- Followed-threads entries in the drawer and on Friends
- Keep the followed-threads list fresh and scope its unread count
- Follow toggle, thread files and the followed-threads screen
- Let the outbox send files into a thread
- Follow toggle, followed-threads list and resume marking in the thread store
- Manage categories from the drawer and create channels into one
- Category create, rename and delete calls, and categoryId on create channel
- Unread badge on a followed thread's replies chip
- Thread composer files, unread chip badge and followed threads
- Track followed threads and send files into a thread
- Wake thread followers and respect an unfollow
- Follow threads, per-thread read markers and the followed list
- Thread follow state, followed threads and the thread.follow event
- Add thread follows with a per-thread read marker
- Join a share to watch it and keep the stage pin for the call
- Add pure stage rules for the hero, the pin and share joining
- Keep the stage pin for the session of a call
- Fold a blocked person's messages in shared servers
- Skip pushes from somebody the recipient blocked
- Share the username filter across instances over the event bus
- Reorder channels and categories from the drawer
- Open the create-channel sheet on a chosen kind
- Let a list row carry a labelled long-press
- Create a poll from the attachment sheet
- Keep folded categories per account and server across launches
- Rearrange a server's channels optimistically with rollback
- Send a poll as a sealed message with its settings beside it
- Port the channel layout rules and step moves
- Share system audio on Linux through PipeWire
Bug fixes
- Android composer schedule button alignment, sealed edit history, and paged pins
- Align schedule message button with send button in composer
- Check the cached block list before a cold-process push
- Let the second smoke account speak again before it replies in a thread
- Tie a stage pin's clearing to the call it was set in
- Open a folded blocked run when a jump targets a message inside it
- Drop a malformed username event instead of throwing on it
- Stop offering Forward on a poll
- Say why a poll cannot be sent yet
- Put the vote comment back on votePoll
- Show only a joined share in picture-in-picture
Other changes
- Record phase 52, the message finished and the machine hardened
- Document paged pins and the on-device search walk
- Document edit history across chat-service, schema, protocol, shared types and features
- Restore smoke labels
- Fix smoke history name clash
- Smoke edit history, its privacy and its removal with the message
- Document input backends, agent-side validation and platform support
- Smoke three devices of one account stay online until the last closes
- Record the followed-thread entries, step rule pin and server smoke
- Say why Web has no picture-in-picture, document the server smoke
- Add a smoke for categories and the channel layout endpoint
- Pin the step rule to the drawn order on both clients
- Document the followed-threads entries and live refresh
- Note the cached block list in cold-process pushes
- Record the live migration and smoke run
- Record the gap closures for blocked-run jumps, stage pins and Android categories and threads
- Document following threads, the followed list and thread files
- Word the Android picture-in-picture trigger accurately
- Android has picture-in-picture while minimised
- Document category management
- Track the phase 51, blocking and call-stage follow-ups
- Document followed threads, the read marker and thread files
- Document Android watching, share placeholders and the call-long stage pin
- Note the shared username filter, blocked-run folding and poll forwarding
- Document folding a blocked person in shared servers and the cached block list
- Document that a poll cannot be forwarded
- Document the username filter shared over the event bus
- Mark Android poll creation and channel reordering in the feature matrix
- Document the channel list, rearranging it, and creating a poll
- Document Linux share system audio through PipeWire
- Document the software encoder budget and joined-only share encoding
- Hold a share on a software encoder to 30 fps and 720p
- Encode a share only for peers who joined the stream
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop | Built here |
| Android | Built here |
Bug fixes
- Fix release image builds and Wayland screen share portal chooser
- Pull base images from mirror.gcr.io instead of ECR Public
- Use the portal's chooser for screen share on Wayland
Other changes
- Document Wayland portal capture and PiP frame gating
- Stop encoding PiP frames while no overlay is open
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop | Built here |
| Android | Built here |
⚠ Breaking changes
- Final stable release v1.0.0 - The complete 1,000-commit cycle
Features
- Show the share encoder in the connection sheet
- Show share encoder and sent frame rate in the connection panel
- Draw uncategorized channels under Text and Voice headings
- Create text and voice channels straight into a category
- Scheduled sends and reminders with WorkManager, a when-sheet and a scheduled list
- Draw channels grouped under collapsible categories
- Open a thread as its own screen from the chip or the long-press sheet
- Group channels under collapsible categories with drag and keyboard reorder
- Render poll cards, vote and close, and preview polls locally
- Scheduling rules for sends and reminders, with unit tests
- Poll composer, live poll card and vote/close actions
- Send later from the composer, remind-me on a message, and a scheduled list
- Thread side panel, reply-in-thread menu item and reply-count chip
- Draw spoilers and highlighted code blocks, and mask spoilers in previews
- Keep unsent composer drafts per conversation in the local cache
- Channel category CRUD and a channel-layout reorder endpoint
- Local scheduling rules, encrypted on-device store and clock for scheduled sends and reminders
- Announce channel list changes as server.channels.changed
- Parse ||spoilers|| and fence languages, and lex code for colour
- Wake thread participants, keep thread replies out of unread
- Thread replies, thread paging and the root reply summary
- Referee poll votes by index without reading the question
- Poll wire types, limits and durations
- Keep unsent composer drafts per channel across restarts
- Add thread root pointer and reply summary to messages
- Add message_polls and poll_votes for refereed polls
- Add channel categories and a channel position
- Hold the account master key server-side, and reset a vault nobody can open
- Open the account vault, and lock rather than fork
- Show the recovery code, and say plainly when a device is locked
- Open the account vault on every device, and never fork
- Collect objects the database has no reference to
- Wrap channel and moment keys for accounts, not machines
- Add the account vault schema and contracts
- One-line Linux installer that fetches the newest AppImage
- Start with the session on Linux through an XDG autostart entry
- The same animated boot screen, in this platform's idiom
- An animated boot screen, with a tip that waits its turn
- Offer custom roles in the @ menu
- Wake and tint for a role you hold
- Tint a message that addresses a role you hold
- Let a custom role be a mention target
- Add mention highlighting and addressed alert in MessageRow
- Wire MentionSuggestPopup into chat Composer
- Add WhatsApp-style MentionSuggestPopup and filter unit tests
- Add MentionQueryParser with unit tests
- Highlight @mentions in chat items and tint mentioned bubbles
- Integrate MentionSuggest in MessageComposer
- Add MentionSuggest popover component
- Add mentionQueryAt with check tests
- Let any member add someone to a direct message
- Add an append-only audit log for moderation actions
- Add a description column, editable and shown on the invite card
- Group the server rail into collapsible folders
- Android connection-panel parity, and a share-degraded warning
- Let a screen share capture below native resolution
- Promote Calls & Data to a rail destination
- Staff role badge and full-date divider in chat
- Port iMessage-style bubble arrival animation
- Top-level Workbench/Activities/Moments nav and UI fixes
- Polish workbench redesign with motion and Apple-style materials
- Overhaul channel sidebar with voice participant tree and user controls
- Redesign topbar navigation and server rail
- Add headphones icon and motion animation tokens
- Render 9:16 showcase video with baked poster frame 0
- Implement 9:16 hyperframes composition for betweenus
- Show the bandwidth estimate and the media path in the connection panel
- Run adverts out rather than sitting through them
- Play the real youtube.com, and only its sound
- A Dev channel that runs beside the installed app
- A maximum share resolution, 1080p by default
- Auto-hide fullscreen controls after 3s with a small toggle button
- A handle for the full-screen strip, not a mouse twitch
- Take the screen in full screen, and let the strip be pinned
- One strip for the full-screen share, docked or floating
- Count remote access in Calls & Data
- Add alpha tag with icon and disclaimer to listen together
- Add Linux AppImage build and self-updater support
- Add pnpm size, an artifact budget matrix
- Camera device picker, look controls, and settings parity
- Camera effects seam, filters and portrait blur with ML Kit
- Portrait blur, and a Look control on your own tile
- Let the phone choose its camera, and size its ceiling
- A seam between the camera and the sender, with filters on it
- Give the camera the treatment the mic and the share already had
- Move moments privacy to separate screen across platforms
- My moments, and a grid that reads newest first
- A moment's tally, and who it is shared with
- Reactions on a moment, and an audience its author chooses
- React and reply to a moment, and tag it in the conversation
- Answer a moment, and keep the tag when the moment is gone
- Add engineering badges, code health metrics, and interactive 16-theme showcase
- Expand Code Reference page and explorer to full viewport width
- Add interactive VS Code-style file tree to Code Reference explorer
- Add interactive code reference explorer and source documentation
- Replace 3D hero with dual Desktop and Android real app showcase
- Show the moment, not the face, in the tray rows
- Open the roll first, and post several moments at once
- One picker for photos and clips, several at a time
- A switcher for the three kinds, and a picker that opens whole
- Seal a moment before it is posted, and open it on the way in
- Seal statuses, and freeze the audience when they are posted
- Status tray, story player and composer
- Status tray, story viewer and composer
- Statuses that expire after a day, seen by friends
- Webhooks on the phone, and a body-carrying test that was wrong
- Webhooks on the server settings screen, badged in the channel
- Discord-shaped webhooks, and the exception they cost
- The cover band, and a profile screen behind the sheet
- A cover photo behind a name, and a profile worth opening
- Cover pictures on an account, and webhooks on a channel
- Make aria-modal true, and let the OS set the type size
- Point the layout the other way, and a place for the words
- One rule for a list with nothing in it
- Tell an account when its key exists on one machine only
- Cozy and compact, and a reason it is not a font size
- A shortcut sheet on
?, and Ctrl+F to search
- A notification goes away when you read it somewhere else
- Ask to drive a shared screen, and say no when asked
- A chair at Play Together, and no second copy of the rules
- Listen Together, in step and out loud
- A seat at Listen Together, without a second sound system
- Push to talk, held with a thumb
- A quick switcher, and one place that decides where a tap goes
- Search a conversation on the phone
- The rate-limit window slides
- The rotation grace moves to Redis, and a second instance becomes possible
- A socket that stops when the account does
- Something that actually deploys the images the pipeline pushes
- A secret can come from a file, and a signing secret can be rotated
- A backup that leaves the host
- A migration check that replays the whole history, and the one-off the rename needs
- Back leaves the call screen, and a dock stands in for it
- A shared screen goes out with its sound
- The conversation says when somebody joins
- Let a new member be added with the chat history, and hide sealed rows
- One-to-one calls on every client, and a header that shows the name
- Add PACKAGE_VERSION fallback in AdminHealthService for app version retrieval
- Enhance voice channel and share stage with fullscreen toggle and layout adjustments
- Show whether the TURN relay would actually carry a call
- Accept an operator's own TURN server, not only Cloudflare's
- Warn about failing echo cancellation during a call
- Report server health, storage and bandwidth to the admin panel
- Surface echo canceller failure in voice settings
- Three-level noise suppression and echo canceller health
- Admin server health and storage contract
- Pin a face to the call stage, and stop the stage moving on its own
- A call stage that holds still, and a pin for the face that matters
- Make connection error banners dismissable across all views
- Say what is holding a share's picture down
- Put a status dot on every face in a conversation
- Decide who may see when you were last here
- Last seen in the header, and a profile a double tap away
- Say who is here, when they were last here, and what they say
- Give an account an about line and a last-seen time
- Give the forward picker icons, faces and a limit
- Forward a message into another channel
- Carry a forwarded-from tag inside the message body
- Open the photo behind an avatar
- Add dedicated PermissionDetailScreen subpage for each permission
- Add hierarchical settings subsections and options subpages
- Fix icon colors and create dedicated permissions page
- Declining stops the ring on this account's other devices
- Update changelog for alpha release 0.0.1-alpha.18 with new features, bug fixes, and documentation improvements
- Upgrade 3D hero showcase with interactive subsystem inspector and vector icons
- Add interactive 3D logo showcase and spatial chips to landing page
- Draw a voice message as a voice message
- A microphone, one look, and two windows
- One look, and a window that keeps moving
- Hold the microphone where send used to be
- Give a message an expiry and one look
- Read the time off the server's clock
- Divide the message list by day
- Rebuild a dead call link instead of asking the user to rejoin
- Expand max zoom level to 3000% with dynamic stepping
- Register zoom controls in MDXComponents and linearize architecture diagram
- Add interactive zoom pan and fullscreen controls for Mermaid diagrams
- Draw release notes as markdown on the sheet and the screen
- Draw release notes as markdown rather than as their source
- Give adding a friend its own screen
- Add project code style configuration and permissions settings
- Adaptive shell for tablets and foldables
- Clear one conversation, from a three-dot menu in its header
- Blocking, clearing your own history, and a way back into a forgotten account
- Outgoing mail settings and a per-account password reset
- Forgotten passwords, admin-configured SMTP, and a Bloom-filtered username check
- Block a user, and clear your own history everywhere
- Blocks, password resets, SMTP settings and a cleared-chats marker
- Add dynamic wallpaper theming (Material You) toggle and system palette generator
- Add fluid slide & fade transitions and animated theme grid for themes screen
- Create dedicated theme pages and navigation across all platforms
- Add 16-theme suite, custom accents, system sync, and appearance settings
- Expand theme suite to 16 themes with category filtering
- Add theme suite with system sync and custom accents
- Enhance user and server settings UI with desktop header and close button
- Add betweenus skill configuration for agents and claude
- The web client gets a search box, not just a paste box
- Apps is a screen on the stage, not a popover
- One Apps button, and a fullscreen board
- The sidebar music and gamepad buttons open the options
- Ludo and Carrom, the second with real physics
- Play Together - a games panel on the voice stage
- Referee a game on /ws/call
- The Play Together contract and the rules of four games
- Pressing play on the page plays it for the call
- Press a video, the call watches it - no link, no button
- Press a video on YouTube and it plays, without the queue detour
- The Listen Together panel
- The Listen Together player, and the clock it runs on
- Listen Together, the shared transport on /ws/call
- Show the marks in the composer as they are typed
- Return makes a newline inside a list, quote or fence
- Carry a list on to its next item
- Render markdown in messages
- A markup parser, ported from android
- Draw bulleted and numbered lists in messages
- Bulleted and numbered lists
- Bubble-style message rows, matching the android layout
- Repaint a changed picture, name or server without a restart
- Repaint a changed picture or name where it already is
- Announce a changed profile or server, rather than let it go stale
- Draw several photos as one album, not several cards
- Draw several photos as one album, not several attachments
- Draw messages the way a phone messenger draws them
- Offer a way back down when the conversation is scrolled up
- Let the sheets take their colour from the scheme
- Put the call controls in a floating toolbar
- Repaint the entry, friends and settings screens
- Redraw the conversation
- Move the shell onto the scheme, and give it motion
- Rebuild the shared controls in the expressive language
- Give the client a Material 3 Expressive theme
- Seen-by faces on a message, and swipe a row to reply
- Draw who has seen a message, and reply on a double click
- Say who has read a message, derived from the read markers
- Hold a call when another one takes the audio, and say so
- Say when the connection is down, and stop retrying after 30s
- Ring somebody into the call from the call controls
- Add somebody to a call from inside the call
- A Calls & data screen, and a phone that reports what it moved
- A Calls & Data page, and per-link measurement to fill it
- Record what each link in a call moved, and add up a month of them
- Show a call log in settings, and count what a call moved
- Record a per-person call log in call-service
- Optimize full-screen views, settings, and voice for mobile viewports
- Convert right panels to mobile slide-over sheets
- Add mobile header and hamburger navigation toggle
- Offer a reload when a newer build is being served
- Create android-style workspace navigation drawer
- Check for, download and apply updates, per Windows flavor
- Add responsive hooks and breakpoint utilities
- Answer a ring without leaving the window
- Answer a ring from the lock screen
- Carry a ring to every device the person has
- Ring one person into a call
- Show how long the call has been running
- Input sensitivity, which was not blocked after all
- Tell the owner when somebody is on their machine
- Web push, so a closed tab is still reachable
- Safety numbers, so a lying key directory can be caught
- Implement file transfer functionality over data channel
- A share sheet hand-off now asks where it is going
- Print every command the deployment needs after the copy
- The installer copies the files and stops there
- Install a deployment without cloning the repository
- Paste a picture into the composer
- Send into BetweenUs from the system share sheet
- Audio devices follow whatever is plugged in
- A platform a release skips keeps the last one's artifacts
- A marker can name the platforms it is for
- Reconnect a dropped call, and end one that cannot be reconnected
- A notification read on one device takes itself down on the others
- The connection panel, ported from the desktop
- The green speaking ring lights for your own tile too
- Do not wake a phone for a message being read on another device
- A daily update check, and an install that reports what happened
- The auto update screen, and the prompt on launch
- Fetch, download and hand over a newer release
- The rules for which release a device should install
- Phase 13 hardening - Keystore session, private CA, crash reports, CI
- The remote clipboard, both directions
- A direct call rings, full-screen, with the app dead
- A call ducks for a prompt and holds for a phone call
- The member menu - message, add friend, mute, copy id
- A colon menu, the server's own emoji in the picker, and animated ones
- Bold, italic, strike, code and quotes in a message body
- Back out of a call and it keeps going in a floating window
- A call takes the whole screen
- Publish the service images for arm64 as well as amd64
- Let a caller ask for a channel key that is not the cached one
- Release through a PR, and undo a release that fails halfway
- Marker-driven releases to Docker Hub, with the clients attached
- Implement adaptive stage grid scaling, uniform video cards, and floating control dock
- Redesign call screen with WhatsApp-style adaptive layout, PiP self-view, and camera flip
- Draw the four new pushes, and undraw a deleted message
- Push for deletes, friends, servers and calls
- Use PushGate.shouldSuppress in PushService
- Add PushGate.shouldSuppress active channel check with unit tests
- Make message URLs clickable hyperlinks and render rich OpenGraph previews
- Add URL unfurling service and metadata API endpoint
- Add WhatsApp-style permission flow and top notification warning banner
- Remove overlay on image cards and save media as bu_
{date}
- Add permissions carousel screen with progress and allow-all button
- FCM push, so a swiped-away phone is reachable
- Hide server people/members list by default
- Send files in the background, and shrink a video first
- Crop and rotate before a picture is sent or stored
- Set an avatar and a server icon from the phone
- Manage a machine's access and read its audit trail
- Add and remove a server's own emoji
- Make and edit a server's own roles
- Sign in with a provider, and open invite links
- Accept a mobile redirect, bound to a challenge the app keeps
- Upload large attachments in parts
- Invites as links, previewed before they are accepted
- Show what an invite leads to before it is accepted
- Convert every sent photo to JPEG, HEIC included
- Decode HEIC in the client, and send every photo as JPEG
- One data path, and a dump before every migration
- The headers a browser needs to be told once
- A server's own emoji, animated ones included
- Type ":" and a name to reach an emoji
- What you can do about a person, from the list that names them
- A link, so anybody can be let in without being added
- One screen at a time - a new share replaces the one before it
- A key per machine, so a lost one can be revoked
- Invite management, and a line that was lying about the slug
- Microphone processing, a hi-fi mode, and where the call comes out
- Reconnect when the network comes back, not when the timer says
- A reaction says who left it, not just how many
- A list of servers this client has been on, and a contract check
- Tell a LAN it is a LAN - a manual bitrate, frame rate and codec
- An unread line that survives a restart, and a way to reach it
- The same two notes when somebody joins or leaves a call
- Two notes when somebody joins the call, two when they leave
- A cache on desktop and web, so opening the app is not a spinner
- Look at a photo before sending it, and show a video's first frame
- Look at a photo before sending it, and drop files anywhere
- Scroll back through history on desktop and web
- Replies, on all three clients
- A monitor plugged in mid-session is noticed
- The roles screen learns to draw a server's own roles
- Two ways to be driven, two targets
- A chord that arrives as a chord
- Add Firebase Crashlytics configuration to appInsightsSettings
- A blob that leaves when its message does
- An attachment row per upload, so a blob has an owner
- Roles a server can invent for itself
- A session that survives its two halves landing on different replicas
- A record of what was done, and a way past the first hundred rows
- Edit who is on a private channel
- Measure the call, and say when nobody can hear you
- Push to talk
- Turn one person down, or off, without touching the others
- Invites that expire, run out and can be taken back
- Sweep what nothing was sweeping, and stop scanning for agent tokens
- Rotate a channel's key when somebody loses access to it
- A channel can be set to mentions only
- The roster comes from the service that holds the sockets
- Send presence only to the people entitled to it
- Go idle on its own after ten minutes, and come back
- Rate limit login per account as well as per address
- Add emoji picker and quick camera button in composer, auto-hiding camera when keyboard is open
- Display You in accent color for current user in chat view, pinned and search panels
- Enhance chat screen with media viewer, video player and gallery storage
- Add storage write permissions and video/audio attachment support
- Implement WhatsApp-style media picker and attachment sheet
- Add media and camera permissions and FileProvider setup
- Keep channel keys, so cached history opens without the network
- Open on what the app already knows, not on a spinner
- Spend the bitrate, send the whole screen
- Tell the gateway where a phone can reach it
- Come back to where you were, and go where a tap says
- Lay the share stage out like a meeting client
- A share takes the whole screen, the way it has to
- A call that looks like a call to the system
- Drop the browser context menu
- A gateway for clients that cannot use a Vite proxy
- Voice, video, screen share and the remote-desktop viewer
- Servers, channels, messages, members, settings
- The stores, and the widgets every screen is built from
- The whole REST surface, and end-to-end encryption
- Sign in, switch servers, and land on home
- Nexora palette, and a server address the build does not decide
- Initialize Android project structure with basic configurations and resources
- Implement Picture-in-Picture (PiP) overlay for voice calls
- Add Teams-style floating Picture-in-Picture mode and fix screen occlusion
- One entrance for everything that opens on top
- Carry the workbench into the surfaces inside the panels
- Rebuild the client as a workbench of floating panels
- Enhance screen capturing on Windows with background throttling adjustments
- Add initial configuration for build and typecheck tasks
- One call per account, whichever device joins last
- Warn before a browser tab with a live call is closed
- Keep the call running while the client navigates away
- Add BM25 search engine for UI/UX style guides with design system generation and persistence options
- Add Hide/Show camera controls to expand stream content to full width
- Add Teams and Google Meet style Side Gallery camera layout alongside screen share
- Add auto-hiding controls, participant toggle, and polished glassmorphic UI for fullscreen mode
- The screen goes straight to the controller, not through a room
- A mesh of peer connections, where the SFU used to be
- A switchboard, so two clients can find each other without an SFU
- Relay media through TURN, so a call works from another network
- A render that throws is a message, not a blank window
- Implement LAN SFU and ICE candidate rewriting for remote access
- Reach the dev stack from a second machine on the network
- Notifications and provider sign-in in a browser
- Serve the web client at the root of the gateway
- Add the browser client as its own app
- Gate the remote-desktop section on the Electron bridge
- Restore the account encryption key on any machine you sign in on
- Store a sealed identity backup so an account is not tied to one machine
- Update TypeScript configuration and add path mappings for shared packages
- Check at startup that LiveKit accepts our tokens
- Give a new server a voice channel as well as #general
- Add packaging scripts for portable and NSIS targets in desktop app
- Enhance deployment instructions and add production scripts for easier setup
- Change microphone and speakers from inside the call
- Give Voice & Video something to set
- Let a deployment choose where local uploads live
- Publish the microphone the way this machine is set up
- Close the microphone when nobody is talking
- Decide what a microphone should sound like
- Encode a screen share like something worth watching
- Give control of a screen share in a call, with named cursors
- Choose which monitor a session watches
- Request control from somebody's screen share
- Public ingress that fits a tunnel you already run
- Be a remote machine, and reach one
- Enrolment, grants, sessions and the relay
- Remote machines, grants, sessions and an audit trail
- Proxy LiveKit signalling, so a deployment is one hostname
- Choose the server from the login screen
- One address for a whole deployment, resolved at runtime
- Message actions - tombstones, edits, pins, reactions, search
- Implement message deletion and friend event notifications
- Add high-res icon rendering and portable production build target
- Set taskbar, electron window, system tray, and installer application icon
- Integrate brand icon from icon.svg with dark gradient styling across desktop app
- Honour mutes, quiet hours and Do Not Disturb
- System tray, close to tray, and start with the system
- Notification-service owns mutes, quiet hours and read state
- Play video and audio inline, and cap image previews
- Upload avatars and server icons
- Attach, preview and download files in the message view
- Encrypted attachments, compressed and uploaded in parts
- Attachment manifest and settable profile pictures
- Multipart uploads and a picture/attachment split
- Drop the default Electron menu bar
- Rebuild the client as a Discord-shaped app
- Choosable status, with invisible resolved server-side
- Friends, user search and direct messages
- Private channels with a member allowlist
- Per-member permission overrides and one access resolver
- Web admin panel for users and sign-in providers
- Sign in with Google or GitHub
- Admin API, account management and OAuth sign-in
- Admin role, OAuth provider config, and
pnpm admin:create
- Notifications for messages and voice joins
- Request-scoped logging with a correlated request id
- Refresh-token reuse detection and service-level rate limits
- Screen-share picker, theatre layout and paged grid
- Voice channel screen with participant tiles
- Voice channels, online status and typing indicators
- Encrypted messages, LiveKit calls, two-window dev harness
- Enhance development configuration for API and WebSocket URLs
- Local-disk uploads when S3 is not configured
- Electron shell and Discord-style chat client
- Nginx gateway routing and full-stack compose
- Message REST API and /ws/chat realtime gateway
- Workspaces, membership and channels
- Registration, login, refresh rotation and /me
- Shared types, config, logger, auth, permissions, events, database
Bug fixes
- Fix service image builds and the E2EE integration smoke
- Wrap smoke channel keys for the account vault
- Copy dev-services.mjs into the image build stage
- Socket reconnect resilience, multi-server notifications, VA-API encode, and category UX
- Take every service address from the ports in .env
- Keep reconnecting past the offline deadline, as desktop does
- Keep reconnecting past the offline deadline
- Listen to every server's channels, not only the open one
- Let the whole top bar drag the window
- Keep text channels above voice channels in every sidebar section
- Refereed polls, message threads, channel categories, and scheduled sends
- Pass the thread root after the poll settings when replying in a thread
- Read drafts in the direct message list after merging categories
- Open the vault with the server-held key, and stop locking the phone
- Open the vault with the server-held key, and drop the lock screen
- Account vault E2EE keyring, storage reconciler, and screen share fixes
- Point default emulator endpoint to dev gateway on 8090 with 8080 fallback
- Improve CPU handling in share quality checks and ladder logic
- Share system audio without the call in it
- Keep the picture-in-picture overlay out of a screen share
- Linux desktop build, a one-line installer, and start with the system on Linux
- Role mentions, a quieter sidebar, and a boot screen you can see
- Hold the splash long enough to be seen
- Make the boot screen long enough to actually see
- Stop the account footer crushing its own name column
- Defer voice store subscription in ring store and update devdocs
- Step frame rate down under cpu pressure, cap Android's relay bitrate
- Workbench UI redesign, chat animation polish, and theme contrast fixes across Desktop and Android
- Darken low-contrast accent in two light themes
- Make the server rail follow the active theme
- Make the iMessage-style bubble pop actually animate
- Server rail unread badges, top-bar nav consistency
- Remove placeholder box, fix titlebar button spacing, and add active server ring and marker
- Mark subproject as dirty to indicate uncommitted changes
- Debounce the friend search and cache the block list
- Copy the username from the member menu, not the user id
- Screen share adaptive ladder, live candidate pair tracking, and client reconnection fixes
- Stop "Reconnecting…" sticking after doze or process death
- Stop the reconnect banner getting stuck after a long background
- Refactor Theatre component layout for improved screen sharing experience
- Stop budgeting resolution against the bandwidth estimate
- Read the live candidate pair, matching the desktop
- Read the live candidate pair, not the one an ICE restart left behind
- Carry the same frame-rate ladder as the desktop
- Drive the share ladder from the stats poll that already runs
- Hold the share's frame rate and size the picture to the measured link
- Tune speech ducking ratio to 0.55 and enable interruptible fade transitions
- Enable background autoplay in prod, perceptual volume, and hover-aware controls
- Enable background autoplay in prod, real-time perceptual volume control, and hover-aware controls
- Give the packaged Dev channel its own data directory
- Stop the clock strip appearing on a clock that is right
- A share that recovers, and one a relay can carry
- Auto-hide fullscreen controls and replace mouse-triggered strip
- Allow the fullscreen permission, so full screen is full screen
- Stop the faded full-screen strip from taking clicks
- Queue and retry stored-object fetches so media loads
- Stage all mediapipe wasm files, add dev server middleware and CPU fallback
- Render CameraLook popup in portal with smart viewport anchor positioning
- Give full screen its picture back, with a Docked mode for reading a screen
- Give the web client a way to control a machine, and stop lying about why it cannot
- Frame the full-screen share instead of covering it, and put its two keys behind chords
- Pin deploy.sh to the repo's .env and simplify disk reclamation step
- Prevent server tile unread badge from clipping in workspace drawer
- Place moments privacy under privacy & safety and add disappearing messages to android
- Correct typos and improve clarity in SKILL.md
- Fix unclickable buttons and headers in overlays and streaming fullscreen
- Keep overlay controls out from under the window buttons
- Stop a run skipping to the next person after its first moment
- Use the logical edge for the composer's remove badge
- Convert posted photos to JPEG, free the composer, add My moments
- Draw HEIC moments and hold the clock until one arrives
- Fix badges placement on landing page below CTA buttons and balance 6 centered items
- Default closed folders, compact directory paths, and mobile responsiveness
- Fix mobile responsive layout, badge positioning, and add device switcher
- Resolve dual active navbar links and clean up menu bar hierarchy
- Reload the gateway, or a new route answers HTML
- A moment's wraps are DTOs, not plain objects
- The story feature is called Updates, and Android can reach it
- A status bar that restarted whenever the store moved
- A shared screen is not on screen until Join is pressed
- A message under an arrival line is not part of anybody's run
- Stop
db:migrate resetting a database over a renamed directory
- A call screen that fits the phone it is on
- Stop the screen sleeping while there is video on it
- Keep the window buttons' corner clear in full screen
- Measure the sixteen ramps, and repair eleven of them
- Prune the images that fill the disk, and never the volumes
- Replace the containers a same-version deploy lands on
- The renamed migrations re-apply as a no-op
- A picture's type comes from its bytes, not from its uploader
- The health page, pointed at a deployment that is genuinely sick
- The three smoke scripts have been run, and two of them failed
- The two migrations that sorted backwards get a stamp that does not
- A film share holds its resolution instead of walking down to 480p
- The High profile preference that never once fired
- A share stops asking for a bitrate floor and sitting at 480p
- The call bar no longer leaves a status bar of empty space
- The call dock appears for a call started after the shell
- Coming back from picture-in-picture lands on the call
- A share picked from the sheet reaches the preview
- Resolve the relay from configuration, not from a mint that can 404
- Let the API client load outside Vite for the self-checks
- Scope event buffer lookup for query responses in smoke test
- Ask for the microphone somebody chose, not one like it
- Stop the SDP asking for a bitrate floor nobody can afford
- Stop blaming the microphone for a link that never connected
- Show the about line on a profile, and your own status on yours
- List everywhere a forward could go, not one server's channels
- Let the share picker be seen before the files are claimed
- Give the seen-by row its tap back
- Show the other person's photo in a direct message header
- Derive the version code from the version name
- Derive the build version from the repository manifest
- Resolve system daylight/dark theme state synchronization in themes and settings
- Disable navigation drawer gesture on settings screens
- Start the app after an install and after an update
- Cap a message at ten files where they are picked
- Size the message cap for its manifest
- Stop the ring elsewhere, and announce a call once
- Apply WebRTC signals one at a time per peer
- Recover a forked identity on the next sign-in
- Make a one-time message actually one-time
- Stop a one-time viewer closing itself, and refuse it on the web
- Fetch a one-time message before burning it
- One look each, and let people see what they opened
- Send an audio file with its own name and type
- Make the voice waveform visible, and lose the inner card
- Forget a deleted picture's plaintext
- Follow the device's 24-hour setting
- Tell the time the way the reader's system does
- Stop call tiles stretching to the shape of the stage
- Say when no relay is configured instead of failing silently
- Recover broken call links instead of dropping them
- Sign in without asking to unlock the key
- A blank line is a paragraph break when the notes are read
- Download the update without being asked, and say which channel is on
- Take the new-messages bar away the moment it is read
- Stop offering yourself a conversation with yourself
- Stop a refused DM crashing the members list
- Draw a person's name once
- Retry channel self-heal after a dropped mint request
- Use ECR Public mirror for node and nginx images to avoid pull limit issues
- Eliminate status bar color seam across chat, friends, servers, and sub-screens
- Match status bar and toolbar background across settings and themes screens
- Dynamic status bar icon tinting on light themes & update documentation
- Sync native window titlebar overlay with active theme
- Ensure live theme switching with css rules and dual-target property injection
- Map loopback origins to localhost and handle youtube embed errors gracefully
- Use youtube.com embed with strict-origin referrer to fix video unavailable error
- Fix player host offscreen parking and tab switching for web sync
- Broaden youtube origins and CSP frame-src for web client
- The sidebar menu was clipped, the die was never seen, and carrom aimed backwards
- A game nobody could sit down in looked like a board that ignored clicks
- Give the Listen Together player a real origin
- Keep the notice strips clear of the window controls
- Swap a portable update from a helper script, not from the app
- Give the YouTube embed a referrer so Listen Together loads
- The pause button that did nothing, in a window that was silent
- Nothing plays in the browser, on the one event that catches it
- The browser is not a second player
- A seek that snapped back, and a browser that could be heard
- The second copy of the song, playing in the browser tab
- One Listen Together panel, on the stage, bounded
- The sandbox that made it silent, and YouTube itself in the call
- Hide the members panel by default
- Grow the composer with what is typed, up to a cap
- Wrap long composer text instead of scrolling it
- Shrink the chat header call button to match its neighbours
- Double-click reply, not native word-select
- Swipe right-to-left replies, left-to-right stays the drawer's
- A peer id that survives a reconnect, and a seat held for one
- Reopen a socket the background killed, on the way back
- Only a refused credential ends a session
- Pad connection banner for status bar insets and consume them in shell
- Give the drawer a fixed gutter, not a fraction of the screen
- Make the status dot subscribe to statuses rather than to a function
- Give the drawer a third of the row rather than half
- Split the row down the middle, and make a swipe prove it is one
- Make the call screen readable, and let the chrome leave downwards
- Give the gutter to the drawer by moving the gesture, not guarding it
- Size the composer's buttons to the bar they are in
- Give the left edge to the drawer, the message to the reply
- Ask the system for the swipe area instead of ceding it
- Leave the left edge to Back and the drawer
- Catch up after the background, and stop the drawer stealing the swipe
- Centre the initial in a pictureless avatar
- Show the notification the prompt was asked for, and fade the read line
- Scope refresh-token reuse revocation to one sign-in
- Size the surface to the frame, so "fit" actually fits
- Show a whole camera, and give the call dock room to breathe
- Drop an answer that arrives after the connection is already settled
- Add ensure-electron script to prevent MODULE_NOT_FOUND during install
- Fix server members slide-over panel and auto-navigate to text on voice disconnect
- Remove duplicate mobile TopBar header and fix friends tab clipping
- Point the updater at the repository that publishes the APKs
- Correct indentation for ConnectionSheet visibility in VoiceChannelScreen
- Add drag region to LoginScreen for better window interaction
- Auto-extract and configure electron binary on install and dev
- The microphone is on when it is opened, not a moment later
- The packaged app died before it opened a window
- A copied image could not be pasted into a message
- A socket whose token expired gave up instead of refreshing
- A network blip during refresh signed you out
- A voice channel stopped listing people who had left
- Stop throwing away the microphone you picked
- The microphone gate was refused by CSP, so it never ran
- Correct every Nexora reference to the real repo name, BetweenUs
- Stop tracking .claude/worktrees, unbreak recursive-submodule checkouts
- One owner for the message list's scroll
- Keep the call header clear of the status bar
- Add caching for Electron build and implement retry logic for packaging
- A link that is refused or unanswered can now recover
- The self-view is inside its corners, and PiP shows the speaker
- Incoming video stops flickering
- The speaking ring reads a level that is actually there
- The self-view snaps to a corner, and the chrome gets out of the way
- Video has the rounded corners it appears to have
- Every attachment goes out under the foreground service
- The release build, broken by a listener that no longer exists
- Picture-in-picture refuses cleanly, and knows when it is on
- The screen share picker could not open
- A reply typed into the shade that cannot be sent is kept, not dropped
- Adding somebody to a server no longer means guessing a username
- The self-view that was always an empty box
- Let admin:create and seed run from the deployed image
- Repair action refs mangled by the arm64 patch script
- Point
latest at every release, not only stable ones
- Re-read the channel key when somebody joins the call
- Stop the scheduled backup racing the pre-migration one
- Download the two artifacts by name, and promote after publishing
- Mark gradlew executable in the index
- Decode a keystore secret in every shape it actually arrives in
- A merged release PR builds again
- Detect the release commit by the version moving, not by files changing
- Follow the compose split, and give prod:up something to pull
- Make the integration smokes match the services they test
- Restore the workspace links that typecheck resolves through
- Remove image file size from preview overlay header
- Remove duplicate avatar icon from account settings picture picker
- Keep the call's peer id in step with its socket
- Adjust launcher icon scale to 54% safe-zone to prevent circle mask clipping
- Update Firebase Crashlytics connection settings with actual values
- A second machine reads the history, not a wall of padlocks
- Fix drop image preview loading and discard upload handling
- Derive the OAuth redirect allow list, and take a username to sign in
- The key, the roster and the sign-in prompt
- Give every video tile the shape of the picture in it
- Re-anchor the message list when the keyboard opens
- Ensure backup directory permissions and add diagnostic write check
- An origin is not a string that starts the same way
- The endpoints behind a token still get a budget
- A session is not an entitlement to every attachment
- A socket frame is as big as the traffic, not as big as ws allows
- A token does not get to say how it is checked
- A caller does not get to choose which bucket counts them
- A picture sent from a phone says how big it is
- A growing row is not somebody scrolling away
- A picture that has been decrypted stays decrypted
- Scrolling away is something only the reader does
- A paired Bluetooth headset is found again
- The list stopped stuttering when pictures arrive
- A moderator cannot edit or kick an administrator
- An attachment is not served to a stranger
- Managing members is not permission to conscript the directory
- A capture bound to a device does not follow the one you plug in
- Open a channel at its newest message, not wherever the last one sat
- The server picker's recreate() was talking to nobody
- A still screen is not a share that ended
- Remove redundant YOU badge in message rows
- Hanging up now ends the call notification
- Watching a share no longer bounces back to the grid
- Mute the microphone, not just the track carrying it
- Say who is in a voice channel, and notice when it changes
- Do not start a projection before the service can carry one
- Stop asking the sender for 720p30
- A share that is not moving has not ended
- Be seen in the call, and give up on one that never answers
- Rejoin the call when the socket comes back
- Leaving a call goes back to the conversation, not into one
- Show a share at the shape and the resolution it is sent at
- Rotating during a share no longer loops until it crashes
- Write a message body the way the other clients read one
- Returning to a call from its notification no longer ends it
- Send a call to the speaker, not to silence
- The four transceiver slots a call is actually made of
- Start the dev gateway as part of pnpm dev
- Show a server the moment this account is added to it
- Re-read the key directory when a message arrives at an unknown epoch
- A failed call can be joined again
- Say which address could not be reached
- Fix server icon size and active background outline in server rail
- One Nexora mark, and a rail tile that says where it goes
- Keep the user strip at the bottom of the sidebar
- Put each layout toggle on the side it controls
- Only offer the right-panel toggle where there is a right panel
- Use the WGC feature name this Chromium actually knows
- Update codec type from RTCRtpCodecCapability to RTCRtpCodec
- Keep camera feeds permanently visible in fullscreen mode and only auto-hide controls
- Fix muted speaking flicker, add fullscreen theatre mode, and gate stream audio to viewers
- Maximize P2P screen sharing quality with High Profile H.264, SDP bandwidth signaling, and BWE fast-start
- Preserve native video quality
- Raise 60 fps bitrate ceiling
- Sync remote media state
- ICE candidates were being dropped, so no call ever connected
- The deployed SFU advertised its bridge address, so media never arrived
- /livekit reached LiveKit's root, so the WebSocket never upgraded
- Refuse to hand a client an SFU address only the server can reach
- A browser tab does not ask for a machine list it will never show
- A 200 that is not JSON is a failure, not null data
- The relay could not have 7881, so the candidate does not ask for it
- Address the containers by IPv4, not by "localhost"
- Serve the LAN dev app over TLS, or it has no crypto at all
- A stopped share should leave everyone else's stage, and let the browser own the audio question
- Give turbo enough slots for every persistent task
- Advertise an SFU address the host can actually reach
- Let the service write the volume its uploads go to
- Point the doctor at the compose file that is running the SFU
- Find the SFU from the host, not only from inside Docker
- Let a member who joined after the key was minted key itself
- Keep the package CommonJS; share the theme through a .mjs
- Stop a signed-in session dying on a backend that is not up yet
- Add type module and resolve electron binary installation
- Stop the dev SFU starting with a placeholder LiveKit secret
- Drop the workspace path mappings from tsconfig.base.json
- Let any member key an empty channel
- Stop sending requests without a bearer token
- Default LIVEKIT_URL to the gateway path in every mode
- Allow empty CLOUDFLARE_TUNNEL_TOKEN for compatibility with local setups
- Attach the gate after the track, not with it
- Bind the spliced gate source to a name instead of renaming it
- A shared screen no longer echoes the call back into it
- The pointer no longer disappears when control is taken
- The click lands where the pointer is, at the display size
- Control now reaches the machine, and add request-control
- Development ignores VITE_API_URL
- Announce a permission change to the member it is about
- Clear the unread line on its own, kill the last blue outline
- Clear an unread badge on focus, and mark where reading stopped
- Set AppUserModelID and explicit window.setIcon for Windows taskbar icon
- Replace thin rotated stroke path with solid bold CallEnd disconnect handset icon
- Fix disconnect button icon orientation and layout
- Notify only when the channel is not on screen, and cache history
- Migrations and OpenSSL in the container stack
- Upgrade SFU to v1.13.5 so track publishing negotiates
- Remove container loopback node_ip to fix WebRTC UDP media publishing in Docker
- Allow electron audio permissions, fix livekit docker UDP ports and voice channel retry
- Resolve dev-duo port conflict, voice connecting state & control buttons
- Improve logging for debugging and handle room disposal on hot reload
- Leave the roster on every disconnect, not just the button
- Allow the LiveKit origin through the renderer CSP
- Stop a third Electron window during pnpm dev:duo
Other changes
- !docs : Fix MDX compilation by escaping question placeholder in chat-service doc
- The share encoder row and Linux hardware encoding
- Ask for VA-API hardware encoding on Linux
- Moving a dev service off a port another program holds
- Point the submodule at the end-to-end check
- Point the submodule at the sidebar and notification write-up
- Offline sockets keep retrying, every server is subscribed, create into a category
- Point the submodule at the phase-41 write-up
- Merge: threads
- Merge: refereed polls
- Merge: channel categories
- Merge: local scheduled send and remind-me
- Merge: describe spoilers and highlighted code blocks
- Merge: describe per-channel drafts in features, README and the Android client page
- Local scheduled send and reminders, the trade-off, notifications and feature matrix
- Document channel categories, the layout endpoint and server.channels.changed
- Document thread replies, paging, push rules and the schema
- Document refereed polls across API, protocol, E2EE and schema pages
- Describe spoilers and highlighted code blocks
- Describe per-channel drafts in features, README and the Android client page
- Describe the server-held vault key and the removed lock screen
- Update public docs for account vault, object reconciler, and new E2EE architecture
- Stop dev postgres and redis from auto-starting on boot
- Document share audio without the call and the hidden PiP overlay
- Merge: Linux AppImage build, installer script and startup entry
- Document the Linux AppImage, its installer and autostart
- Build, smoke-test and publish the Linux AppImage
- Make the Linux AppImage start in seconds and run without libfuse2
- Merge: role mentions, the sidebar controls, and an animated boot screen
- Bump devdocs for the splash floor and sidebar controls
- The sidebar voice panel carries no controls
- Bump devdocs for the boot screen
- Drop the Voice Connected badge from the title bar
- Bump devdocs to the role-mentions notes
- Say what counts as a mention, now that a role does
- Update subproject commit reference in development
- Add implementation plan for @mentions on desktop and android
- Add design spec for @mentions on desktop and android
- Point the docs suite at the merged backlog and record the parity findings
- Note Calls & Data as a rail destination
- Add workbench ui redesign implementation plan
- Add workbench ui redesign design specification
- Add brag skill and lockfile entry
- Update readme with high-resolution screenshots and 9:16 showcase video
- Add brag plan and composition brief for 9:16 vertical video
- Generate voice, moments, and remote desktop screenshots
- Generate native android compose mobile showcase screenshot
- Generate high-resolution desktop workbench hero screenshot
- Add implementation plan for 9:16 vertical video and screenshots
- Add 9:16 vertical video and professional screenshot suite design
- Write down the client connection-liveness rules
- Bump docs submodule
- The selected candidate pair, and what the panel can now answer
- Bump docs submodule to phase 47
- Document the frame-rate ladder and why both preferences fail alone
- Adverts are run out, and why nothing is blocked
- Audio only, and a player that does not ask permission
- What decides a share picture, after phase 44
- !docs: restore feature screenshots, add video showcase section, and fix README video link
- Deploy the docs site on every release
- Replace static images with video.mp4 across README and docs
- !docs : fix MDX changelog compilation by escaping raw comparison angle brackets
- !docs : Update v1.0.0 changelog and publish release documentation
- Bump the npm_and_yarn group across 2 directories with 1 update (#42)
- Regenerate the code reference index
- Point the submodule at the size and performance matrix
- Document the artifact size budgets and the size matrix
- Drop unreferenced appcompat and material catalog entries
- Ship one Chromium locale and compress at maximum
- Upgrade Electron to 40.10.6 to drop extract-zip
- Regenerate changelog and code reference index
- Patch six Docusaurus transitives via npm overrides
- Override uuid to 11.1.1 in the Firebase dependency chain
- Override eight transitive packages to their patched versions
- Upgrade Electron to 39.8.10
- Upgrade NestJS to 11, Express to 5 and multer to 2
- Upgrade nodemailer to 9.1.1
- Upgrade electron-builder to 26.15.3
- Upgrade vite to 6.4.3 across web, admin and desktop
- Camera quality controls, device selection, and real-time color filters
- Remove portrait blur, keep camera filters and picker
- What decides a camera's picture, and the seam filters run on
- Design for camera settings, encoding and the effects seam
- !docs : Updating docs
- Moments audience privacy, reactions, disappearing messages, and UI fixes
- Record My moments on every client and its grid order
- Note why the moments clock is per-post
- Record moments privacy and reaction counts
- Only fetch a picture for the moment quote in a bubble
- Record reacting and replying to moments
- Record the moments media fix and the new My moments screen
- !docs : full-width repository code reference explorer, engineering health badges, and interactive 16-theme showcase
- Instant 0ms folder expand with memoized tree and full repository code browser
- Add native Android screenshots and update documentation gallery
- Add features page, capture real UI screenshots, and enhance homepage
- Say that the deploy reloads the gateway
- Encrypted Moments stories, profile cover banners, webhooks, and call stage overhaul
- Bump the dev-docs pointer for the moments composer notes
- The sealed moment, and the word for it
- The day-long posts are called Moments
- The status feature, and the submodule pointer
- A webhooks guide written for whoever is holding the curl
- Settings in named groups, the way the phone has them
- Where a share is joined, and where its mouse is asked for
- Listen and Play Together on the phone, a shortcut sheet on the desktop, and sixteen themes that actually read
- A tick-box that clears the host's images after a healthy deploy
- Desktop and web reconnect a dropped call link too
- Two Android emoji features that work, marked as missing
- Point at the phases 39-42 proposal
- A release that finishes, and a deployment it can reach
- Ask ECR again when it says "Rate exceeded"
- Fail when the tailnet join did not take
- Point at the standalone deploy workflow
- A deploy workflow of its own, so the host can be tested first
- Update the devdocs pointer for the tailnet policy
- Reach a host that has no port to forward, over Tailscale
- Name images rather than copy them, and stop hitting 429
- Rebuild images with migrations that survive the phase-35 rename
- Screen share audio, floating call dock, 1-to-1 direct calls, and sliding rate limiter
- Point at the phase 35-38 proposal
- What decides a share's picture is both clients, not one
- Document release trigger conventions in Release-Commit.md and update CLAUDE.md
- Add live TURN relay health probe and unify static relay configuration
- Update submodule pointer for the phase 29 relay docs
- One relay, configured in one place
- Stop passing a hosted TURN key nothing reads any more
- Add custom TURN relay support and coturn deployment runbooks
- Ignore session handoff file in gitignore
- A worked coturn setup on Oracle Cloud
- Update submodule pointer for the TURN runbook link
- A runbook for standing up a coturn relay
- Update submodule pointer for the TURN credential note
- Update submodule pointer for the phase 28 relay docs
- A second way to configure a relay, and where it has to live
- Pass TURN_URLS through to call-service and remote-gateway
- Fix call echo, add tiered noise suppression, and admin server health
- Noise suppression levels and why echo is a separate problem
- Update development submodule pointer
- Document the echo path and three-level noise suppression
- Explain how the health snapshot is assembled
- Document the health screen and its unmeasurable fields
- Who is on the call stage, and what is allowed to move
- How a microphone is chosen, and why it must be exact
- What decides a share's picture, and what must never be a floor
- Stop committing the Kotlin compiler's scratch directory
- Describe who may see a last-seen time
- Describe last seen and the about line across the suite
- Describe forwarding across the clients
- Describe the profile photo viewer across the clients
- Make all sub-settings direct top-level items and remove nested cross-links
- Enforce strict Setting -> Subsection -> Option hierarchy for settings
- Remove redundant Calls & Data and Auto Update rows from main settings
- Remove redundant Privacy & Safety row from main settings screen
- Add rule that AI assistants must never push code
- Document the patch marker and the docs deploy
- Revert a failed release, rebuild one in place, deploy the docs
- Add the patch marker and the docs scope
- Document how the installer starts the app
- Document the ten-file cap and what it protects
- Document declining across an account's devices
- Document call.answered and the once-per-call roster
- Document one-signal-at-a-time negotiation
- Document per-kind backups and identity recovery
- Add top-level section links and automate changelog extraction
- Add download links to navbar, hero section, and intro pointing to GitHub Releases
- Update verifiable architecture, sequence, and lifecycle diagrams to Archify standard
- Changes done for alpha release
- Add cache buster query parameter to LOC badge
- Remove legacy FCM directory and DEPLOYMENT.md in favor of docs/
- Say what stops a one-time message being opened twice
- The web opens one-time messages in the app instead
- Say what each client can actually stop
- Describe one look each and the MessageView table
- Describe how an attachment is named and typed
- Describe voice messages and their waveforms
- Describe messages that stop existing
- Point at the server-clock notes
- Write down the rule for clocks and expiry
- Point at the clock and timezone notes
- Record the clock and timezone rules
- Point at the day divider notes
- Describe the message list's day dividers
- Migrate push suppression doc to docs/ and update references
- Document pnpm android:* across the public docs
- Run the Gradle build from pnpm
- Document link recovery, signalling reconnect, and the relay's role
- Update system architecture section with Archify Mermaid diagram
- Standardize all flowcharts to vertical Archify format with zoom & pan support
- Streamline architecture flowchart layout and contrast
- Update high-level runtime architecture diagram and devdocs protocol
- Sign-in no longer asks to unlock the key
- Enhance APK and AAB build process with matrix support
- Release notes are drawn as markdown on every client
- Point the submodule at the updates rewrite
- One Windows installer, a download that happens on its own, two Android jobs
- One Windows build, and make it a real installer
- Point at the members-list follow-up
- Describe the two searches and the row that refuses
- Downgrade Java version to 17 in project configuration files
- Point at submodule safety guidance
- Point at pushed dev-docs, including the consistency guideline
- Android uses the screen it is on
- Clearing one conversation
- Android has the accounts pass too
- The accounts pass across the public docs and README
- Point at the accounts-pass tracker
- Correct README "no light theme" claim
- Record device and cross-network verification across clients
- Changes done for new release
- Document Android Material You dynamic wallpaper theming
- Update guidelines for AI assistants and contributors in SKILL.md
- Document loopback origin security mapping and embed error handling
- Update architecture and development documentation with sync and embed fixes
- Update references to CLAUDE.md and add commit guidelines
- Add AGENTS.md symlink pointing to CLAUDE.md
- Update master reference index and submodule pointer
- Update development submodule ref to include README
- Add root CLAUDE.md to repository
- Organize devdocs folder and link root claude.md
- Add root CLAUDE.md pointer to private development docs
- Migrate development documentation and claude.md to private submodule
- Browse means two different things, and says which
- The gamepad is a dot on the Apps button now
- The last roll, the forward flick, and the clipped menu
- The library is six games, and the rules take two more arguments
- Ludo and Carrom
- Record Play Together
- Play Together
- Record the three desktop fixes and the new portable swap
- !docs : Docs is done
- Update favicon and brand logo with app icon
- Add interactive installation & setup section and feature highlights
- Update architecture and service docs with listen together and rich formatting
- A blocked window looks like a blocked window
- The browser that had to stop playing, and the seek that had to stay put
- Clicking a video is the control
- Playing what you found, and the browser that was making its own noise
- The panel's shape, and the two bugs it came from
- Browsing YouTube in the call, and the sandbox that made it silent
- Listen Together
- Record the live profile and server updates, and the status dot that was not live
- Correct the swipe-to-reply rule, and note the jump button
- Record the Material 3 Expressive redesign
- Record the Android catch-up and the drawer gesture
- Record read receipts and the reply shortcuts
- Record the session, hold and reconnect work
- Note why the scaling type alone did not stop the crop
- Record the in-call ring on the web, and the phone showing a whole frame
- Record the per-link call data, the analytics page and the Android screens
- Record the call log in TRACK, TODO and TESTING
- Remove obsolete SDD progress ledger file
- How each client notices a release and takes it
- Add implementation plan for mobile web responsive UI adaptation
- Add design spec for mobile web responsive UI adaptation
- A ring is not channel-scoped news, so focus does not swallow it
- Write down what a ring is and why it may be loud
- Desktop installers point at the deployment, not at localhost
- Record the main-process crash in the packaged desktop app
- Record the share picker and clipboard paste on Android
- Record the two faults that ended live sessions
- Add the missing Notifications architecture page
- Make localhost:3000/ work for dev, keep /Nexora/ in production
- Match the desktop client's exact theme
- Center the Android screenshot
- Embed the Android screenshot, add offline local search
- Redesign the doc pages, not just the landing page
- Redesign the landing page
- Add Android client architecture page
- Split the one giant ERD into per-section diagrams
- Add pnpm docs / docs:build / docs:install root scripts
- Replace default Docusaurus README with a project-specific one
- Add docs deploy workflow, triggered by a !docs marker
- Deployment, CI, security, testing and local-run guides
- Per-service REST/WebSocket reference
- Architecture, system design and database schema content
- Scaffold Docusaurus site under docs/
- Changes done for android release
- The no-clone install path, and the build commands it dated
- Record the share sheet, composer paste and the two screen fixes
- Done with the enhancement
- The second call-screen pass, and the one bug it did not close
- The call-screen pass recorded in TRACK.md
- RELEASING.md, and the pass recorded in TRACK.md
- Remove outdated Android chat notification suppression and PiP design documents
- Catch every doc up to push suppression, self-update, and the send-path fix
- One send path for every attachment
- The daily check and the installer session
- Record the self-update phase
- The picker that would not open, and what picture-in-picture needs
- Phase 27's call half is answered by call.roster, and Android rings from it
- Record this pass in TRACK.md and ANDROID_TODO.md
- Reconcile TRACK.md and ANDROID_TODO.md with what the code actually has
- Record the call-screen fixes and what to try on a device
- Betweenus is also available on arm docs
- Apha release done
- Record the missing
latest tag and the image slimming
- Build the runtime from a production install, not the build stage
- Record the call key's epoch and how it is kept current
- Pin the one re-read on a rotated channel key
- First Release Done
- Refactor Docker Compose Configuration
- Update android development tracking for active chat notification suppression
- Add implementation plan for android active chat notification suppression
- Add design spec for android active chat notification suppression
- Add new SVG icon with gradient backgrounds and headset details
- Implement code changes to enhance functionality and improve performance
- Launcher icon sourced from desktop SVG with gradient headset pads and #3730A2 background
- Launcher icon with #3730A2 background, 75% zoom mark, and monochrome layer
- Install BetweenUs adaptive launcher icon and render all density mipmaps
- Restore original clean template launcher icons in android res
- Record URL hyperlinking and rich link previews across Android, Web, and Desktop in TRACK.md
- Record permission carousel progression and notification banner in TRACK.md
- Record clean image preview and bu_date naming in TRACK.md
- Record push across the development documents, and untrack google-services.json
- Record Android permissions carousel in TRACK.md
- Update TRACK.md for TopBar toggle cleanup
- Remove duplicate right panel toggle from TopBar
- Update TRACK.md for default hidden member list
- Update TRACK.md for chat attachment preview and discard fix
- Record this pass, and name the key-publish trap
- Upload a few parts at a time rather than one
- Rename the app to BetweenUs
- A feature table that says which client each thing works on
- Invite management has a screen now, and deep links have a reason
- Configure ABI splits, resource filtering, and bundle splitting to reduce release APK size
- Update README with data path commands and pre-migration backup details
- Who the API believes, and what it still does not
- The follow latch, the media cache, and what to click
- The Bluetooth fix, the device pickers and the permission screen
- Keep the Android client out of the build context
- No signing config, and the launcher icon is ours
- Custom emoji, R8, and a README that says what this app now does
- R8 on, code and resources shrunk
- The authorization pass, and the two things it did not build
- Ten items closed, and the three that are only half closed
- The join and leave tones, and what to listen for
- What landed this pass, and what it did not close
- What landed this pass, and the migrations waiting behind it
- Track the accepted work in its own document
- Add initial Android project configuration files
- Correct post-SFU claims and open phase 27 for push notifications
- Replace tokei badge with working sloc.xyz live LOC calculator
- Update README with dynamic GitHub shields for LOC and repo metrics
- Add badge tags and shields to repository README
- Add Android client entries to architecture and request flow in README
- Update README with Android client and enhanced chat media documentation
- Update ANDROID_TODO with image/video viewer and storage album features
- Update ANDROID_TODO with WhatsApp-style media picker
- Record the Android local cache and where channel keys now live
- Add modules.xml for project configuration in Android module
- The share stage, and why a call outlives its screen
- Write down the slot contract, since breaking it is silent
- The epoch re-read, and how to test a re-key with two clients
- Split :core and :ui-common out of :app
- Add phased Android client roadmap
- Update README with home preview image and clarify P2P WebRTC mesh architecture
- Record phase 26 - the workbench
- Add new skills for UI library selection, prototyping, and animation review
- Record phase 25 - the call follows the account
- Improve negotiation logic and track handling for media streams
- What an operator has to do about media, which is now almost nothing
- Remove LiveKit, and the deployment settings that only existed for it
- An SFU and a Cloudflare Tunnel were never going to fit together
- The relay is what makes a call work over the tunnel
- How to tell a broken /livekit proxy from a broken SFU
- A loopback LIVEKIT_URL is the one that only works on the server
- Drop the join step logs and LiveKit's debug level
- What a blank web client was, and the two halves of the fix
- Mirrored networking alone does not open the WSL VM
- Check the LAN address answers before telling the SFU to advertise it
- The three ways a dev stack looks dead when it is only unstarted
- Why a call could not be joined in development, and what says so now
- Pin the invited member's first message
- The refresh grace window, and where the web client actually listens
- Describe the shared image build and what makes a rebuild slow again
- Build every image from one Dockerfile instead of nine
- Keep the desktop app and the worktrees out of the build context
- Cover the identity backup endpoints in the chat-service smoke run
- Describe identity backup, its threat-model cost, and how to port it
- Add .dockerignore
- Improve LiveKit key management and enhance server probing logic
- Update environment variable notes for clarity on DATABASE_URL and POSTGRES_PASSWORD alignment
- Update Nginx configuration to use dynamic upstream variables for improved service resolution
- Point the README at DEPLOYMENT.md and spell out which API URL a client uses
- Merge: deployment guide
- Merge: storage volume mapping for local uploads
- Write down how to actually deploy this
- Record the in-call device picker and the processor fix
- Record the microphone work
- Record the screen-share encoding work
- Record monitor selection and in-call control
- Record the remote-desktop and screen-share audio fixes
- Record phases 17 and 18
- Record phase 16, one address for a whole deployment
- Add a source-available, view-only licence
- Add the request flow, renderer to Prisma to Postgres and back
- Rewrite the README around the architecture
- Note what the history cache does not cover yet
- Pnpm dev:backend runs the services without the renderer
- Record phase 14 — notifications, the tray and auto-start
- Record phase 13 — media, attachments and profile pictures
- Cover uploads in the smoke script
- Cover phase 12 in the smoke scripts and dev:duo
- Rename workspace to server across the stack
- Plan phase 12 — servers, permissions and direct messages
- Record the admin panel, OAuth and notifications
- Move landed phase 10 work into Done
- Record phase 10 progress
- GitHub Actions pipeline with an integration job
- Presence smoke test, and make the chat smoke fail loudly
- Record voice/presence verification and the publish issue
- MVP quick start and honest verification status
- Add local Postgres/Redis compose, env template, development docs
- Init git
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop | Built here |
| Android | Built here |
1.0.9 (2026-09-25)
Features
- Show the share encoder in the connection sheet
- Show share encoder and sent frame rate in the connection panel
- Draw uncategorized channels under Text and Voice headings
- Create text and voice channels straight into a category
Bug fixes
- Socket reconnect resilience, multi-server notifications, VA-API encode, and category UX
- Take every service address from the ports in .env
- Keep reconnecting past the offline deadline, as desktop does
- Keep reconnecting past the offline deadline
- Listen to every server's channels, not only the open one
- Let the whole top bar drag the window
- Keep text channels above voice channels in every sidebar section
Other changes
- The share encoder row and Linux hardware encoding
- Ask for VA-API hardware encoding on Linux
- Moving a dev service off a port another program holds
- Point the submodule at the end-to-end check
- Point the submodule at the sidebar and notification write-up
- Offline sockets keep retrying, every server is subscribed, create into a category
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop | Built here |
| Android | Built here |
1.0.8 (2026-09-21)
Features
- Scheduled sends and reminders with WorkManager, a when-sheet and a scheduled list
- Draw channels grouped under collapsible categories
- Open a thread as its own screen from the chip or the long-press sheet
- Group channels under collapsible categories with drag and keyboard reorder
- Render poll cards, vote and close, and preview polls locally
- Scheduling rules for sends and reminders, with unit tests
- Poll composer, live poll card and vote/close actions
- Send later from the composer, remind-me on a message, and a scheduled list
- Thread side panel, reply-in-thread menu item and reply-count chip
- Draw spoilers and highlighted code blocks, and mask spoilers in previews
- Keep unsent composer drafts per conversation in the local cache
- Channel category CRUD and a channel-layout reorder endpoint
- Local scheduling rules, encrypted on-device store and clock for scheduled sends and reminders
- Announce channel list changes as server.channels.changed
- Parse ||spoilers|| and fence languages, and lex code for colour
- Wake thread participants, keep thread replies out of unread
- Thread replies, thread paging and the root reply summary
- Referee poll votes by index without reading the question
- Poll wire types, limits and durations
- Keep unsent composer drafts per channel across restarts
- Add thread root pointer and reply summary to messages
- Add message_polls and poll_votes for refereed polls
- Add channel categories and a channel position
- Hold the account master key server-side, and reset a vault nobody can open
Bug fixes
- Refereed polls, message threads, channel categories, and scheduled sends
- Pass the thread root after the poll settings when replying in a thread
- Read drafts in the direct message list after merging categories
- Open the vault with the server-held key, and stop locking the phone
- Open the vault with the server-held key, and drop the lock screen
Other changes
- Point the submodule at the phase-41 write-up
- Merge: threads
- Merge: refereed polls
- Merge: channel categories
- Merge: local scheduled send and remind-me
- Merge: describe spoilers and highlighted code blocks
- Merge: describe per-channel drafts in features, README and the Android client page
- Local scheduled send and reminders, the trade-off, notifications and feature matrix
- Document channel categories, the layout endpoint and server.channels.changed
- Document thread replies, paging, push rules and the schema
- Document refereed polls across API, protocol, E2EE and schema pages
- Describe spoilers and highlighted code blocks
- Describe per-channel drafts in features, README and the Android client page
- Describe the server-held vault key and the removed lock screen
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop | Built here |
| Android | Built here |
1.0.7 (2026-09-20)
Features
- Open the account vault, and lock rather than fork
- Show the recovery code, and say plainly when a device is locked
- Open the account vault on every device, and never fork
- Collect objects the database has no reference to
- Wrap channel and moment keys for accounts, not machines
- Add the account vault schema and contracts
Bug fixes
- Account vault E2EE keyring, storage reconciler, and screen share fixes
- Point default emulator endpoint to dev gateway on 8090 with 8080 fallback
- Improve CPU handling in share quality checks and ladder logic
- Share system audio without the call in it
- Keep the picture-in-picture overlay out of a screen share
Other changes
- Update public docs for account vault, object reconciler, and new E2EE architecture
- Stop dev postgres and redis from auto-starting on boot
- Document share audio without the call and the hidden PiP overlay
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop | Built here |
| Android | Built here |
1.0.6 (2026-09-19)
Features
- One-line Linux installer that fetches the newest AppImage
- Start with the session on Linux through an XDG autostart entry
Bug fixes
- Linux desktop build, a one-line installer, and start with the system on Linux
Other changes
- Merge: Linux AppImage build, installer script and startup entry
- Document the Linux AppImage, its installer and autostart
- Build, smoke-test and publish the Linux AppImage
- Make the Linux AppImage start in seconds and run without libfuse2
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop | Built here |
| Android | Built here |
1.0.5 (2026-09-18)
Features
- The same animated boot screen, in this platform's idiom
- An animated boot screen, with a tip that waits its turn
- Offer custom roles in the @ menu
- Wake and tint for a role you hold
- Tint a message that addresses a role you hold
- Let a custom role be a mention target
- Add mention highlighting and addressed alert in MessageRow
- Wire MentionSuggestPopup into chat Composer
- Add WhatsApp-style MentionSuggestPopup and filter unit tests
- Add MentionQueryParser with unit tests
- Highlight @mentions in chat items and tint mentioned bubbles
- Integrate MentionSuggest in MessageComposer
- Add MentionSuggest popover component
- Add mentionQueryAt with check tests
- Let any member add someone to a direct message
- Add an append-only audit log for moderation actions
- Add a description column, editable and shown on the invite card
- Group the server rail into collapsible folders
- Android connection-panel parity, and a share-degraded warning
- Let a screen share capture below native resolution
Bug fixes
- Role mentions, a quieter sidebar, and a boot screen you can see
- Hold the splash long enough to be seen
- Make the boot screen long enough to actually see
- Stop the account footer crushing its own name column
- Defer voice store subscription in ring store and update devdocs
- Step frame rate down under cpu pressure, cap Android's relay bitrate
Other changes
- Merge: role mentions, the sidebar controls, and an animated boot screen
- Bump devdocs for the splash floor and sidebar controls
- The sidebar voice panel carries no controls
- Bump devdocs for the boot screen
- Drop the Voice Connected badge from the title bar
- Bump devdocs to the role-mentions notes
- Say what counts as a mention, now that a role does
- Update subproject commit reference in development
- Add implementation plan for @mentions on desktop and android
- Add design spec for @mentions on desktop and android
- Point the docs suite at the merged backlog and record the parity findings
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop | Built here |
| Android | Built here |
1.0.4 (2026-09-18)
Features
- Promote Calls & Data to a rail destination
- Staff role badge and full-date divider in chat
- Port iMessage-style bubble arrival animation
- Top-level Workbench/Activities/Moments nav and UI fixes
- Polish workbench redesign with motion and Apple-style materials
- Overhaul channel sidebar with voice participant tree and user controls
- Redesign topbar navigation and server rail
- Add headphones icon and motion animation tokens
- Render 9:16 showcase video with baked poster frame 0
- Implement 9:16 hyperframes composition for betweenus
Bug fixes
- Workbench UI redesign, chat animation polish, and theme contrast fixes across Desktop and Android
- Darken low-contrast accent in two light themes
- Make the server rail follow the active theme
- Make the iMessage-style bubble pop actually animate
- Server rail unread badges, top-bar nav consistency
- Remove placeholder box, fix titlebar button spacing, and add active server ring and marker
- Mark subproject as dirty to indicate uncommitted changes
- Debounce the friend search and cache the block list
- Copy the username from the member menu, not the user id
Other changes
- Note Calls & Data as a rail destination
- Add workbench ui redesign implementation plan
- Add workbench ui redesign design specification
- Add brag skill and lockfile entry
- Update readme with high-resolution screenshots and 9:16 showcase video
- Add brag plan and composition brief for 9:16 vertical video
- Generate voice, moments, and remote desktop screenshots
- Generate native android compose mobile showcase screenshot
- Generate high-resolution desktop workbench hero screenshot
- Add implementation plan for 9:16 vertical video and screenshots
- Add 9:16 vertical video and professional screenshot suite design
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop | Built here |
| Android | Built here |
1.0.3 (2026-09-17)
Features
- Show the bandwidth estimate and the media path in the connection panel
Bug fixes
- Screen share adaptive ladder, live candidate pair tracking, and client reconnection fixes
- Stop "Reconnecting…" sticking after doze or process death
- Stop the reconnect banner getting stuck after a long background
- Refactor Theatre component layout for improved screen sharing experience
- Stop budgeting resolution against the bandwidth estimate
- Read the live candidate pair, matching the desktop
- Read the live candidate pair, not the one an ICE restart left behind
- Carry the same frame-rate ladder as the desktop
- Drive the share ladder from the stats poll that already runs
- Hold the share's frame rate and size the picture to the measured link
- Tune speech ducking ratio to 0.55 and enable interruptible fade transitions
Other changes
- Write down the client connection-liveness rules
- Bump docs submodule
- The selected candidate pair, and what the panel can now answer
- Bump docs submodule to phase 47
- Document the frame-rate ladder and why both preferences fail alone
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop | Built here |
| Android | Built here |
1.0.2 (2026-09-17)
Features
- Run adverts out rather than sitting through them
- Play the real youtube.com, and only its sound
- A Dev channel that runs beside the installed app
- A maximum share resolution, 1080p by default
Bug fixes
- Enable background autoplay in prod, perceptual volume, and hover-aware controls
- Enable background autoplay in prod, real-time perceptual volume control, and hover-aware controls
- Give the packaged Dev channel its own data directory
- Stop the clock strip appearing on a clock that is right
- A share that recovers, and one a relay can carry
Other changes
- Adverts are run out, and why nothing is blocked
- Audio only, and a player that does not ask permission
- What decides a share picture, after phase 44
- !docs: restore feature screenshots, add video showcase section, and fix README video link
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop | Built here |
| Android | Built here |
1.0.1 (2026-09-16)
Features
- Auto-hide fullscreen controls after 3s with a small toggle button
- A handle for the full-screen strip, not a mouse twitch
- Take the screen in full screen, and let the strip be pinned
- One strip for the full-screen share, docked or floating
- Count remote access in Calls & Data
Bug fixes
- Auto-hide fullscreen controls and replace mouse-triggered strip
- Allow the fullscreen permission, so full screen is full screen
- Stop the faded full-screen strip from taking clicks
- Queue and retry stored-object fetches so media loads
Other changes
- Deploy the docs site on every release
- Replace static images with video.mp4 across README and docs
- !docs : fix MDX changelog compilation by escaping raw comparison angle brackets
- !docs : Update v1.0.0 changelog and publish release documentation
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop | Built here |
| Android | Built here |
1.0.0 (2026-09-11)
BetweenUs v1.0.0 is the first major stable release, marking the culmination of over 1,130 commits of engineering. It transitions BetweenUs from an alpha prototype into a production-grade, self-hostable, privacy-first collaboration and voice platform across Desktop (Windows, Linux), Android, and Web.
⚠ Breaking changes
- Final stable release v1.0.0 - The complete 1,000-commit cycle
Key Capabilities & Highlights
End-to-End Encryption & Privacy
- Double Ratchet & Signal-grade E2EE: Every direct message, private channel message, and group chat is encrypted end-to-end with forward secrecy and break-in recovery.
- Zero server knowledge: Server databases and object stores hold only opaque ciphertext and blinded IDs. Message plaintext, file names, photos, voice notes, and media keys never reach the server in the clear.
- Safety Numbers & Out-of-band Verification: Cryptographic identity fingerprint cards with QR codes allow peers to verify encryption keys directly.
- Passphrase Recovery & Backup: Mnemonic recovery phrases and encrypted local backup exports ensure account recovery without compromising zero-trust boundaries.
Voice, Video & Collaborative Stage
- P2P WebRTC Mesh & TURN Relay: Direct peer-to-peer audio/video streaming with automatic fallback to operator-configured TURN (coturn/eturnal) relay when direct NAT traversal is blocked.
- Acoustic Processing: Integrated acoustic echo cancellation (AEC3), adaptive noise suppression, auto gain control, and silence noise gating.
- High-FPS Screen Sharing: Share full monitors, application windows, or browser tabs with adaptive resolution and framerate scaling.
- Camera Look & Filters: In-call camera switcher, exposure adjustments, and real-time GPU-accelerated color shaders.
- In-Call Remote Desktop: Low-latency remote screen viewing and keyboard/mouse control directly inside voice calls.
Synchronized Apps: Listen Together & Play Together
- Listen Together: Synchronized YouTube playback across all call members using a shared gateway clock, drift correction (<250ms), and automatic music volume ducking during speech.
- Play Together: Six synchronized multiplayer board games (Chess, Checkers, Reversi, Connect 4, Tic-Tac-Toe, Carrom) with server-side move refereeing and spectator mode.
- Alpha status indicators: Transparent badge indicators with tooltips for experimental stage features.
- Full Markdown & Syntax Highlighting: Bold, italics, spoilers, blockquotes, inline/fenced code blocks with language highlighting, and rich metadata link previews.
- Interactive Voice Notes: In-chat voice messaging with real-time waveform recording and interactive playback scrubbers.
- Reactions & Custom Emojis: Unicode reactions, animated emoji stickers, and server-level custom emoji upload support.
- Ephemeral Moments: 24-hour disappearing photo updates with granular audience privacy controls, reaction tallies, and threaded in-conversation replies.
Desktop Application (Windows & Linux)
- Hardened Electron 40 Shell: Context isolation, sandboxed renderers, and strictly guarded IPC interfaces.
- Windows & Linux Support: Windows NSIS setup installer and standalone Linux AppImage.
- Self-Updater Daemon: Background update checks, automated downloads, and cryptographic verification before install.
- Frameless Titlebar & System Tray: Custom titlebar overlay respecting native OS controls, Windows snap layouts, and minimized-to-tray background daemon.
- Optimized Footprint: Single-locale pruning and maximum compression to maintain tight artifact budgets (
pnpm size).
Native Android Application
- Modern Compose UI: 100% Kotlin codebase built with Jetpack Compose and Material 3 Expressive design tokens.
- Native WebRTC Integration: Hardware-accelerated video codecs, earpiece/speaker/Bluetooth SCO routing, and background foreground call service.
- System Picture-in-Picture (PiP): Smooth PiP transition keeping active speakers in view while navigating other apps.
- Hardware Push-to-Talk: Dedicated physical key support for push-to-talk in voice channels.
Backend Microservices & Operations
- Decoupled Architecture: 9 specialized containerized NestJS microservices (auth, chat, call, remote, gateway, notification, storage, web, admin).
- Multi-Arch Docker Images: Native
linux/amd64 and linux/arm64 container images for every service.
- S3-Compatible Object Storage: Multi-bucket MinIO/S3 storage with automated background retention and cleanup sweepers.
- Admin Dashboard & Telemetry: Server management console with live health metrics, connection diagnostics, and webhook management.
Features
- Add alpha tag with icon and disclaimer to listen together across desktop, web, and android
- Add Linux AppImage build and self-updater support
- Add artifact budget matrix and
pnpm size reporting
Other changes
- Bump the npm_and_yarn group across 2 directories with 1 update (#42)
- Regenerate the code reference index and documentation links
- Point the submodule at the size and performance matrix
- Document the artifact size budgets and the size matrix
- Drop unreferenced appcompat and material catalog entries
- Ship one Chromium locale and compress at maximum
- Upgrade Electron to 40.10.6 to drop extract-zip
- Regenerate changelog and code reference index
- Patch six Docusaurus transitives via npm overrides
- Override uuid to 11.1.1 in the Firebase dependency chain
- Override eight transitive packages to their patched versions
- Upgrade Electron to 39.8.10
- Upgrade NestJS to 11, Express to 5 and multer to 2
- Upgrade nodemailer to 9.1.1
- Upgrade electron-builder to 26.15.3
- Upgrade vite to 6.4.3 across web, admin and desktop
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop (Windows) | Built here |
| Android | Built here |
Features
- Camera device picker, look controls, and settings parity
- Camera effects seam, filters and portrait blur with ML Kit
- Portrait blur, and a Look control on your own tile
- Let the phone choose its camera, and size its ceiling
- A seam between the camera and the sender, with filters on it
- Give the camera the treatment the mic and the share already had
Bug fixes
- Stage all mediapipe wasm files, add dev server middleware and CPU fallback
- Render CameraLook popup in portal with smart viewport anchor positioning
- Give full screen its picture back, with a Docked mode for reading a screen
- Give the web client a way to control a machine, and stop lying about why it cannot
- Frame the full-screen share instead of covering it, and put its two keys behind chords
- Pin deploy.sh to the repo's .env and simplify disk reclamation step
Other changes
- Camera quality controls, device selection, and real-time color filters
- Remove portrait blur, keep camera filters and picker
- What decides a camera's picture, and the seam filters run on
- Design for camera settings, encoding and the effects seam
- !docs : Updating docs
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop (Windows) | Built here |
| Android | Built here |
Features
- Move moments privacy to separate screen across platforms
- My moments, and a grid that reads newest first
- A moment's tally, and who it is shared with
- Reactions on a moment, and an audience its author chooses
- React and reply to a moment, and tag it in the conversation
- Answer a moment, and keep the tag when the moment is gone
- Add engineering badges, code health metrics, and interactive 16-theme showcase
- Expand Code Reference page and explorer to full viewport width
- Add interactive VS Code-style file tree to Code Reference explorer
- Add interactive code reference explorer and source documentation
- Replace 3D hero with dual Desktop and Android real app showcase
Bug fixes
- Prevent server tile unread badge from clipping in workspace drawer
- Place moments privacy under privacy & safety and add disappearing messages to android
- Correct typos and improve clarity in SKILL.md
- Fix unclickable buttons and headers in overlays and streaming fullscreen
- Keep overlay controls out from under the window buttons
- Stop a run skipping to the next person after its first moment
- Use the logical edge for the composer's remove badge
- Convert posted photos to JPEG, free the composer, add My moments
- Draw HEIC moments and hold the clock until one arrives
- Fix badges placement on landing page below CTA buttons and balance 6 centered items
- Default closed folders, compact directory paths, and mobile responsiveness
- Fix mobile responsive layout, badge positioning, and add device switcher
- Resolve dual active navbar links and clean up menu bar hierarchy
- Reload the gateway, or a new route answers HTML
Other changes
- Moments audience privacy, reactions, disappearing messages, and UI fixes
- Record My moments on every client and its grid order
- Note why the moments clock is per-post
- Record moments privacy and reaction counts
- Only fetch a picture for the moment quote in a bubble
- Record reacting and replying to moments
- Record the moments media fix and the new My moments screen
- !docs : full-width repository code reference explorer, engineering health badges, and interactive 16-theme showcase
- Instant 0ms folder expand with memoized tree and full repository code browser
- Add native Android screenshots and update documentation gallery
- Add features page, capture real UI screenshots, and enhance homepage
- !docs : Updating docs
- Say that the deploy reloads the gateway
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop (Windows) | Built here |
| Android | Built here |
Features
- Show the moment, not the face, in the tray rows
- Open the roll first, and post several moments at once
- One picker for photos and clips, several at a time
- A switcher for the three kinds, and a picker that opens whole
- Seal a moment before it is posted, and open it on the way in
- Seal statuses, and freeze the audience when they are posted
- Status tray, story player and composer
- Status tray, story viewer and composer
- Statuses that expire after a day, seen by friends
- Webhooks on the phone, and a body-carrying test that was wrong
- Webhooks on the server settings screen, badged in the channel
- Discord-shaped webhooks, and the exception they cost
- The cover band, and a profile screen behind the sheet
- A cover photo behind a name, and a profile worth opening
- Cover pictures on an account, and webhooks on a channel
Bug fixes
- A moment's wraps are DTOs, not plain objects
- The story feature is called Updates, and Android can reach it
- A status bar that restarted whenever the store moved
- A shared screen is not on screen until Join is pressed
- A message under an arrival line is not part of anybody's run
- Stop
db:migrate resetting a database over a renamed directory
- A call screen that fits the phone it is on
Other changes
- Encrypted Moments stories, profile cover banners, webhooks, and call stage overhaul
- Bump the dev-docs pointer for the moments composer notes
- The sealed moment, and the word for it
- The day-long posts are called Moments
- The status feature, and the submodule pointer
- A webhooks guide written for whoever is holding the curl
- Settings in named groups, the way the phone has them
- Where a share is joined, and where its mouse is asked for
- !docs : Updating docs
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop (Windows) | Built here |
| Android | Built here |
Features
- Make aria-modal true, and let the OS set the type size
- Point the layout the other way, and a place for the words
- One rule for a list with nothing in it
- Tell an account when its key exists on one machine only
- Cozy and compact, and a reason it is not a font size
- A shortcut sheet on
?, and Ctrl+F to search
- A notification goes away when you read it somewhere else
- Ask to drive a shared screen, and say no when asked
- A chair at Play Together, and no second copy of the rules
- Listen Together, in step and out loud
- A seat at Listen Together, without a second sound system
- Push to talk, held with a thumb
- A quick switcher, and one place that decides where a tap goes
- Search a conversation on the phone
Bug fixes
- Stop the screen sleeping while there is video on it
- Keep the window buttons' corner clear in full screen
- Measure the sixteen ramps, and repair eleven of them
Other changes
- Listen and Play Together on the phone, a shortcut sheet on the desktop, and sixteen themes that actually read
- A tick-box that clears the host's images after a healthy deploy
- Desktop and web reconnect a dropped call link too
- Two Android emoji features that work, marked as missing
- Point at the phases 39-42 proposal
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop (Windows) | Built here |
| Android | Built here |
Features
- The rate-limit window slides
- The rotation grace moves to Redis, and a second instance becomes possible
- A socket that stops when the account does
- Something that actually deploys the images the pipeline pushes
- A secret can come from a file, and a signing secret can be rotated
- A backup that leaves the host
- A migration check that replays the whole history, and the one-off the rename needs
- Back leaves the call screen, and a dock stands in for it
- A shared screen goes out with its sound
- The conversation says when somebody joins
- Let a new member be added with the chat history, and hide sealed rows
- One-to-one calls on every client, and a header that shows the name
- Add PACKAGE_VERSION fallback in AdminHealthService for app version retrieval
- Enhance voice channel and share stage with fullscreen toggle and layout adjustments
- Show whether the TURN relay would actually carry a call
- Accept an operator's own TURN server, not only Cloudflare's
- Warn about failing echo cancellation during a call
- Report server health, storage and bandwidth to the admin panel
- Surface echo canceller failure in voice settings
- Three-level noise suppression and echo canceller health
- Admin server health and storage contract
- Pin a face to the call stage, and stop the stage moving on its own
- A call stage that holds still, and a pin for the face that matters
- Make connection error banners dismissable across all views
- Say what is holding a share's picture down
- Put a status dot on every face in a conversation
- Decide who may see when you were last here
- Last seen in the header, and a profile a double tap away
- Say who is here, when they were last here, and what they say
- Give an account an about line and a last-seen time
- Give the forward picker icons, faces and a limit
- Forward a message into another channel
- Carry a forwarded-from tag inside the message body
- Open the photo behind an avatar
- Add dedicated PermissionDetailScreen subpage for each permission
- Add hierarchical settings subsections and options subpages
- Fix icon colors and create dedicated permissions page
- Declining stops the ring on this account's other devices
- Update changelog for alpha release 0.0.1-alpha.18 with new features, bug fixes, and documentation improvements
- Upgrade 3D hero showcase with interactive subsystem inspector and vector icons
- Add interactive 3D logo showcase and spatial chips to landing page
- Draw a voice message as a voice message
- A microphone, one look, and two windows
- One look, and a window that keeps moving
- Hold the microphone where send used to be
- Give a message an expiry and one look
- Read the time off the server's clock
- Divide the message list by day
- Rebuild a dead call link instead of asking the user to rejoin
- Expand max zoom level to 3000% with dynamic stepping
- Register zoom controls in MDXComponents and linearize architecture diagram
- Add interactive zoom pan and fullscreen controls for Mermaid diagrams
- Draw release notes as markdown on the sheet and the screen
- Draw release notes as markdown rather than as their source
- Give adding a friend its own screen
- Add project code style configuration and permissions settings
- Adaptive shell for tablets and foldables
- Clear one conversation, from a three-dot menu in its header
- Blocking, clearing your own history, and a way back into a forgotten account
- Outgoing mail settings and a per-account password reset
- Forgotten passwords, admin-configured SMTP, and a Bloom-filtered username check
- Block a user, and clear your own history everywhere
- Blocks, password resets, SMTP settings and a cleared-chats marker
- Add dynamic wallpaper theming (Material You) toggle and system palette generator
- Add fluid slide & fade transitions and animated theme grid for themes screen
- Create dedicated theme pages and navigation across all platforms
- Add 16-theme suite, custom accents, system sync, and appearance settings
- Expand theme suite to 16 themes with category filtering
- Add theme suite with system sync and custom accents
- Enhance user and server settings UI with desktop header and close button
- Add betweenus skill configuration for agents and claude
- The web client gets a search box, not just a paste box
- Apps is a screen on the stage, not a popover
- One Apps button, and a fullscreen board
- The sidebar music and gamepad buttons open the options
- Ludo and Carrom, the second with real physics
- Play Together - a games panel on the voice stage
- Referee a game on /ws/call
- The Play Together contract and the rules of four games
- Pressing play on the page plays it for the call
- Press a video, the call watches it - no link, no button
- Press a video on YouTube and it plays, without the queue detour
- The Listen Together panel
- The Listen Together player, and the clock it runs on
- Listen Together, the shared transport on /ws/call
- Show the marks in the composer as they are typed
- Return makes a newline inside a list, quote or fence
- Carry a list on to its next item
- Render markdown in messages
- A markup parser, ported from android
- Draw bulleted and numbered lists in messages
- Bulleted and numbered lists
- Bubble-style message rows, matching the android layout
- Repaint a changed picture, name or server without a restart
- Repaint a changed picture or name where it already is
- Announce a changed profile or server, rather than let it go stale
- Draw several photos as one album, not several cards
- Draw several photos as one album, not several attachments
- Draw messages the way a phone messenger draws them
- Offer a way back down when the conversation is scrolled up
- Let the sheets take their colour from the scheme
- Put the call controls in a floating toolbar
- Repaint the entry, friends and settings screens
- Redraw the conversation
- Move the shell onto the scheme, and give it motion
- Rebuild the shared controls in the expressive language
- Give the client a Material 3 Expressive theme
- Seen-by faces on a message, and swipe a row to reply
- Draw who has seen a message, and reply on a double click
- Say who has read a message, derived from the read markers
- Hold a call when another one takes the audio, and say so
- Say when the connection is down, and stop retrying after 30s
- Ring somebody into the call from the call controls
- Add somebody to a call from inside the call
- A Calls & data screen, and a phone that reports what it moved
- A Calls & Data page, and per-link measurement to fill it
- Record what each link in a call moved, and add up a month of them
- Show a call log in settings, and count what a call moved
- Record a per-person call log in call-service
- Optimize full-screen views, settings, and voice for mobile viewports
- Convert right panels to mobile slide-over sheets
- Add mobile header and hamburger navigation toggle
- Offer a reload when a newer build is being served
- Create android-style workspace navigation drawer
- Check for, download and apply updates, per Windows flavor
- Add responsive hooks and breakpoint utilities
- Answer a ring without leaving the window
- Answer a ring from the lock screen
- Carry a ring to every device the person has
- Ring one person into a call
- Show how long the call has been running
- Input sensitivity, which was not blocked after all
- Tell the owner when somebody is on their machine
- Web push, so a closed tab is still reachable
- Safety numbers, so a lying key directory can be caught
- Implement file transfer functionality over data channel
- A share sheet hand-off now asks where it is going
- Print every command the deployment needs after the copy
- The installer copies the files and stops there
- Install a deployment without cloning the repository
- Paste a picture into the composer
- Send into BetweenUs from the system share sheet
- Audio devices follow whatever is plugged in
- A platform a release skips keeps the last one's artifacts
- A marker can name the platforms it is for
- Reconnect a dropped call, and end one that cannot be reconnected
- A notification read on one device takes itself down on the others
- The connection panel, ported from the desktop
- The green speaking ring lights for your own tile too
- Do not wake a phone for a message being read on another device
- A daily update check, and an install that reports what happened
- The auto update screen, and the prompt on launch
- Fetch, download and hand over a newer release
- The rules for which release a device should install
- Phase 13 hardening - Keystore session, private CA, crash reports, CI
- The remote clipboard, both directions
- A direct call rings, full-screen, with the app dead
- A call ducks for a prompt and holds for a phone call
- The member menu - message, add friend, mute, copy id
- A colon menu, the server's own emoji in the picker, and animated ones
- Bold, italic, strike, code and quotes in a message body
- Back out of a call and it keeps going in a floating window
- A call takes the whole screen
- Publish the service images for arm64 as well as amd64
- Let a caller ask for a channel key that is not the cached one
- Release through a PR, and undo a release that fails halfway
- Marker-driven releases to Docker Hub, with the clients attached
- Implement adaptive stage grid scaling, uniform video cards, and floating control dock
- Redesign call screen with WhatsApp-style adaptive layout, PiP self-view, and camera flip
- Draw the four new pushes, and undraw a deleted message
- Push for deletes, friends, servers and calls
- Use PushGate.shouldSuppress in PushService
- Add PushGate.shouldSuppress active channel check with unit tests
- Make message URLs clickable hyperlinks and render rich OpenGraph previews
- Add URL unfurling service and metadata API endpoint
- Add WhatsApp-style permission flow and top notification warning banner
- Remove overlay on image cards and save media as bu_
{date}
- Add permissions carousel screen with progress and allow-all button
- FCM push, so a swiped-away phone is reachable
- Hide server people/members list by default
- Send files in the background, and shrink a video first
- Crop and rotate before a picture is sent or stored
- Set an avatar and a server icon from the phone
- Manage a machine's access and read its audit trail
- Add and remove a server's own emoji
- Make and edit a server's own roles
- Sign in with a provider, and open invite links
- Accept a mobile redirect, bound to a challenge the app keeps
- Upload large attachments in parts
- Invites as links, previewed before they are accepted
- Show what an invite leads to before it is accepted
- Convert every sent photo to JPEG, HEIC included
- Decode HEIC in the client, and send every photo as JPEG
- One data path, and a dump before every migration
- The headers a browser needs to be told once
- A server's own emoji, animated ones included
- Type ":" and a name to reach an emoji
- What you can do about a person, from the list that names them
- A link, so anybody can be let in without being added
- One screen at a time - a new share replaces the one before it
- A key per machine, so a lost one can be revoked
- Invite management, and a line that was lying about the slug
- Microphone processing, a hi-fi mode, and where the call comes out
- Reconnect when the network comes back, not when the timer says
- A reaction says who left it, not just how many
- A list of servers this client has been on, and a contract check
- Tell a LAN it is a LAN - a manual bitrate, frame rate and codec
- An unread line that survives a restart, and a way to reach it
- The same two notes when somebody joins or leaves a call
- Two notes when somebody joins the call, two when they leave
- A cache on desktop and web, so opening the app is not a spinner
- Look at a photo before sending it, and show a video's first frame
- Look at a photo before sending it, and drop files anywhere
- Scroll back through history on desktop and web
- Replies, on all three clients
- A monitor plugged in mid-session is noticed
- The roles screen learns to draw a server's own roles
- Two ways to be driven, two targets
- A chord that arrives as a chord
- Add Firebase Crashlytics configuration to appInsightsSettings
- A blob that leaves when its message does
- An attachment row per upload, so a blob has an owner
- Roles a server can invent for itself
- A session that survives its two halves landing on different replicas
- A record of what was done, and a way past the first hundred rows
- Edit who is on a private channel
- Measure the call, and say when nobody can hear you
- Push to talk
- Turn one person down, or off, without touching the others
- Invites that expire, run out and can be taken back
- Sweep what nothing was sweeping, and stop scanning for agent tokens
- Rotate a channel's key when somebody loses access to it
- A channel can be set to mentions only
- The roster comes from the service that holds the sockets
- Send presence only to the people entitled to it
- Go idle on its own after ten minutes, and come back
- Rate limit login per account as well as per address
- Add emoji picker and quick camera button in composer, auto-hiding camera when keyboard is open
- Display You in accent color for current user in chat view, pinned and search panels
- Enhance chat screen with media viewer, video player and gallery storage
- Add storage write permissions and video/audio attachment support
- Implement WhatsApp-style media picker and attachment sheet
- Add media and camera permissions and FileProvider setup
- Keep channel keys, so cached history opens without the network
- Open on what the app already knows, not on a spinner
- Spend the bitrate, send the whole screen
- Tell the gateway where a phone can reach it
- Come back to where you were, and go where a tap says
- Lay the share stage out like a meeting client
- A share takes the whole screen, the way it has to
- A call that looks like a call to the system
- Drop the browser context menu
- A gateway for clients that cannot use a Vite proxy
- Voice, video, screen share and the remote-desktop viewer
- Servers, channels, messages, members, settings
- The stores, and the widgets every screen is built from
- The whole REST surface, and end-to-end encryption
- Sign in, switch servers, and land on home
- Nexora palette, and a server address the build does not decide
- Initialize Android project structure with basic configurations and resources
- Implement Picture-in-Picture (PiP) overlay for voice calls
- Add Teams-style floating Picture-in-Picture mode and fix screen occlusion
- One entrance for everything that opens on top
- Carry the workbench into the surfaces inside the panels
- Rebuild the client as a workbench of floating panels
- Enhance screen capturing on Windows with background throttling adjustments
- Add initial configuration for build and typecheck tasks
- One call per account, whichever device joins last
- Warn before a browser tab with a live call is closed
- Keep the call running while the client navigates away
- Add BM25 search engine for UI/UX style guides with design system generation and persistence options
- Add Hide/Show camera controls to expand stream content to full width
- Add Teams and Google Meet style Side Gallery camera layout alongside screen share
- Add auto-hiding controls, participant toggle, and polished glassmorphic UI for fullscreen mode
- The screen goes straight to the controller, not through a room
- A mesh of peer connections, where the SFU used to be
- A switchboard, so two clients can find each other without an SFU
- Relay media through TURN, so a call works from another network
- A render that throws is a message, not a blank window
- Implement LAN SFU and ICE candidate rewriting for remote access
- Reach the dev stack from a second machine on the network
- Notifications and provider sign-in in a browser
- Serve the web client at the root of the gateway
- Add the browser client as its own app
- Gate the remote-desktop section on the Electron bridge
- Restore the account encryption key on any machine you sign in on
- Store a sealed identity backup so an account is not tied to one machine
- Update TypeScript configuration and add path mappings for shared packages
- Check at startup that LiveKit accepts our tokens
- Give a new server a voice channel as well as #general
- Add packaging scripts for portable and NSIS targets in desktop app
- Enhance deployment instructions and add production scripts for easier setup
- Change microphone and speakers from inside the call
- Give Voice & Video something to set
- Let a deployment choose where local uploads live
- Publish the microphone the way this machine is set up
- Close the microphone when nobody is talking
- Decide what a microphone should sound like
- Encode a screen share like something worth watching
- Give control of a screen share in a call, with named cursors
- Choose which monitor a session watches
- Request control from somebody's screen share
- Public ingress that fits a tunnel you already run
- Be a remote machine, and reach one
- Enrolment, grants, sessions and the relay
- Remote machines, grants, sessions and an audit trail
- Proxy LiveKit signalling, so a deployment is one hostname
- Choose the server from the login screen
- One address for a whole deployment, resolved at runtime
- Message actions - tombstones, edits, pins, reactions, search
- Implement message deletion and friend event notifications
- Add high-res icon rendering and portable production build target
- Set taskbar, electron window, system tray, and installer application icon
- Integrate brand icon from icon.svg with dark gradient styling across desktop app
- Honour mutes, quiet hours and Do Not Disturb
- System tray, close to tray, and start with the system
- Notification-service owns mutes, quiet hours and read state
- Play video and audio inline, and cap image previews
- Upload avatars and server icons
- Attach, preview and download files in the message view
- Encrypted attachments, compressed and uploaded in parts
- Attachment manifest and settable profile pictures
- Multipart uploads and a picture/attachment split
- Drop the default Electron menu bar
- Rebuild the client as a Discord-shaped app
- Choosable status, with invisible resolved server-side
- Friends, user search and direct messages
- Private channels with a member allowlist
- Per-member permission overrides and one access resolver
- Web admin panel for users and sign-in providers
- Sign in with Google or GitHub
- Admin API, account management and OAuth sign-in
- Admin role, OAuth provider config, and
pnpm admin:create
- Notifications for messages and voice joins
- Request-scoped logging with a correlated request id
- Refresh-token reuse detection and service-level rate limits
- Screen-share picker, theatre layout and paged grid
- Voice channel screen with participant tiles
- Voice channels, online status and typing indicators
- Encrypted messages, LiveKit calls, two-window dev harness
- Enhance development configuration for API and WebSocket URLs
- Local-disk uploads when S3 is not configured
- Electron shell and Discord-style chat client
- Nginx gateway routing and full-stack compose
- Message REST API and /ws/chat realtime gateway
- Workspaces, membership and channels
- Registration, login, refresh rotation and /me
- Shared types, config, logger, auth, permissions, events, database
Bug fixes
- Prune the images that fill the disk, and never the volumes
- Replace the containers a same-version deploy lands on
- The renamed migrations re-apply as a no-op
- A picture's type comes from its bytes, not from its uploader
- The health page, pointed at a deployment that is genuinely sick
- The three smoke scripts have been run, and two of them failed
- The two migrations that sorted backwards get a stamp that does not
- A film share holds its resolution instead of walking down to 480p
- The High profile preference that never once fired
- A share stops asking for a bitrate floor and sitting at 480p
- The call bar no longer leaves a status bar of empty space
- The call dock appears for a call started after the shell
- Coming back from picture-in-picture lands on the call
- A share picked from the sheet reaches the preview
- Resolve the relay from configuration, not from a mint that can 404
- Let the API client load outside Vite for the self-checks
- Scope event buffer lookup for query responses in smoke test
- Ask for the microphone somebody chose, not one like it
- Stop the SDP asking for a bitrate floor nobody can afford
- Stop blaming the microphone for a link that never connected
- Show the about line on a profile, and your own status on yours
- List everywhere a forward could go, not one server's channels
- Let the share picker be seen before the files are claimed
- Give the seen-by row its tap back
- Show the other person's photo in a direct message header
- Derive the version code from the version name
- Derive the build version from the repository manifest
- Resolve system daylight/dark theme state synchronization in themes and settings
- Disable navigation drawer gesture on settings screens
- Start the app after an install and after an update
- Cap a message at ten files where they are picked
- Size the message cap for its manifest
- Stop the ring elsewhere, and announce a call once
- Apply WebRTC signals one at a time per peer
- Recover a forked identity on the next sign-in
- Make a one-time message actually one-time
- Stop a one-time viewer closing itself, and refuse it on the web
- Fetch a one-time message before burning it
- One look each, and let people see what they opened
- Send an audio file with its own name and type
- Make the voice waveform visible, and lose the inner card
- Forget a deleted picture's plaintext
- Follow the device's 24-hour setting
- Tell the time the way the reader's system does
- Stop call tiles stretching to the shape of the stage
- Mark subproject as dirty to indicate uncommitted changes
- Say when no relay is configured instead of failing silently
- Recover broken call links instead of dropping them
- Sign in without asking to unlock the key
- A blank line is a paragraph break when the notes are read
- Download the update without being asked, and say which channel is on
- Take the new-messages bar away the moment it is read
- Stop offering yourself a conversation with yourself
- Stop a refused DM crashing the members list
- Draw a person's name once
- Retry channel self-heal after a dropped mint request
- Use ECR Public mirror for node and nginx images to avoid pull limit issues
- Eliminate status bar color seam across chat, friends, servers, and sub-screens
- Match status bar and toolbar background across settings and themes screens
- Dynamic status bar icon tinting on light themes & update documentation
- Sync native window titlebar overlay with active theme
- Ensure live theme switching with css rules and dual-target property injection
- Map loopback origins to localhost and handle youtube embed errors gracefully
- Use youtube.com embed with strict-origin referrer to fix video unavailable error
- Fix player host offscreen parking and tab switching for web sync
- Broaden youtube origins and CSP frame-src for web client
- The sidebar menu was clipped, the die was never seen, and carrom aimed backwards
- A game nobody could sit down in looked like a board that ignored clicks
- Give the Listen Together player a real origin
- Keep the notice strips clear of the window controls
- Swap a portable update from a helper script, not from the app
- Give the YouTube embed a referrer so Listen Together loads
- The pause button that did nothing, in a window that was silent
- Nothing plays in the browser, on the one event that catches it
- The browser is not a second player
- A seek that snapped back, and a browser that could be heard
- The second copy of the song, playing in the browser tab
- One Listen Together panel, on the stage, bounded
- The sandbox that made it silent, and YouTube itself in the call
- Hide the members panel by default
- Grow the composer with what is typed, up to a cap
- Wrap long composer text instead of scrolling it
- Shrink the chat header call button to match its neighbours
- Double-click reply, not native word-select
- Swipe right-to-left replies, left-to-right stays the drawer's
- A peer id that survives a reconnect, and a seat held for one
- Reopen a socket the background killed, on the way back
- Only a refused credential ends a session
- Pad connection banner for status bar insets and consume them in shell
- Give the drawer a fixed gutter, not a fraction of the screen
- Make the status dot subscribe to statuses rather than to a function
- Give the drawer a third of the row rather than half
- Split the row down the middle, and make a swipe prove it is one
- Make the call screen readable, and let the chrome leave downwards
- Give the gutter to the drawer by moving the gesture, not guarding it
- Size the composer's buttons to the bar they are in
- Give the left edge to the drawer, the message to the reply
- Ask the system for the swipe area instead of ceding it
- Leave the left edge to Back and the drawer
- Catch up after the background, and stop the drawer stealing the swipe
- Centre the initial in a pictureless avatar
- Show the notification the prompt was asked for, and fade the read line
- Scope refresh-token reuse revocation to one sign-in
- Size the surface to the frame, so "fit" actually fits
- Show a whole camera, and give the call dock room to breathe
- Drop an answer that arrives after the connection is already settled
- Add ensure-electron script to prevent MODULE_NOT_FOUND during install
- Fix server members slide-over panel and auto-navigate to text on voice disconnect
- Remove duplicate mobile TopBar header and fix friends tab clipping
- Point the updater at the repository that publishes the APKs
- Correct indentation for ConnectionSheet visibility in VoiceChannelScreen
- Add drag region to LoginScreen for better window interaction
- Auto-extract and configure electron binary on install and dev
- The microphone is on when it is opened, not a moment later
- The packaged app died before it opened a window
- A copied image could not be pasted into a message
- A socket whose token expired gave up instead of refreshing
- A network blip during refresh signed you out
- A voice channel stopped listing people who had left
- Stop throwing away the microphone you picked
- The microphone gate was refused by CSP, so it never ran
- Correct every Nexora reference to the real repo name, BetweenUs
- Stop tracking .claude/worktrees, unbreak recursive-submodule checkouts
- One owner for the message list's scroll
- Keep the call header clear of the status bar
- Add caching for Electron build and implement retry logic for packaging
- A link that is refused or unanswered can now recover
- The self-view is inside its corners, and PiP shows the speaker
- Incoming video stops flickering
- The speaking ring reads a level that is actually there
- The self-view snaps to a corner, and the chrome gets out of the way
- Video has the rounded corners it appears to have
- Every attachment goes out under the foreground service
- The release build, broken by a listener that no longer exists
- Picture-in-picture refuses cleanly, and knows when it is on
- The screen share picker could not open
- A reply typed into the shade that cannot be sent is kept, not dropped
- Adding somebody to a server no longer means guessing a username
- The self-view that was always an empty box
- Let admin:create and seed run from the deployed image
- Repair action refs mangled by the arm64 patch script
- Point
latest at every release, not only stable ones
- Re-read the channel key when somebody joins the call
- Stop the scheduled backup racing the pre-migration one
- Download the two artifacts by name, and promote after publishing
- Mark gradlew executable in the index
- Decode a keystore secret in every shape it actually arrives in
- A merged release PR builds again
- Detect the release commit by the version moving, not by files changing
- Follow the compose split, and give prod:up something to pull
- Make the integration smokes match the services they test
- Restore the workspace links that typecheck resolves through
- Remove image file size from preview overlay header
- Remove duplicate avatar icon from account settings picture picker
- Keep the call's peer id in step with its socket
- Adjust launcher icon scale to 54% safe-zone to prevent circle mask clipping
- Update Firebase Crashlytics connection settings with actual values
- A second machine reads the history, not a wall of padlocks
- Fix drop image preview loading and discard upload handling
- Derive the OAuth redirect allow list, and take a username to sign in
- The key, the roster and the sign-in prompt
- Give every video tile the shape of the picture in it
- Re-anchor the message list when the keyboard opens
- Ensure backup directory permissions and add diagnostic write check
- An origin is not a string that starts the same way
- The endpoints behind a token still get a budget
- A session is not an entitlement to every attachment
- A socket frame is as big as the traffic, not as big as ws allows
- A token does not get to say how it is checked
- A caller does not get to choose which bucket counts them
- A picture sent from a phone says how big it is
- A growing row is not somebody scrolling away
- A picture that has been decrypted stays decrypted
- Scrolling away is something only the reader does
- A paired Bluetooth headset is found again
- The list stopped stuttering when pictures arrive
- A moderator cannot edit or kick an administrator
- An attachment is not served to a stranger
- Managing members is not permission to conscript the directory
- A capture bound to a device does not follow the one you plug in
- Open a channel at its newest message, not wherever the last one sat
- The server picker's recreate() was talking to nobody
- A still screen is not a share that ended
- Remove redundant YOU badge in message rows
- Hanging up now ends the call notification
- Watching a share no longer bounces back to the grid
- Mute the microphone, not just the track carrying it
- Say who is in a voice channel, and notice when it changes
- Do not start a projection before the service can carry one
- Stop asking the sender for 720p30
- A share that is not moving has not ended
- Be seen in the call, and give up on one that never answers
- Rejoin the call when the socket comes back
- Leaving a call goes back to the conversation, not into one
- Show a share at the shape and the resolution it is sent at
- Rotating during a share no longer loops until it crashes
- Write a message body the way the other clients read one
- Returning to a call from its notification no longer ends it
- Send a call to the speaker, not to silence
- The four transceiver slots a call is actually made of
- Start the dev gateway as part of pnpm dev
- Show a server the moment this account is added to it
- Re-read the key directory when a message arrives at an unknown epoch
- A failed call can be joined again
- Say which address could not be reached
- Fix server icon size and active background outline in server rail
- One Nexora mark, and a rail tile that says where it goes
- Keep the user strip at the bottom of the sidebar
- Put each layout toggle on the side it controls
- Only offer the right-panel toggle where there is a right panel
- Use the WGC feature name this Chromium actually knows
- Update codec type from RTCRtpCodecCapability to RTCRtpCodec
- Keep camera feeds permanently visible in fullscreen mode and only auto-hide controls
- Fix muted speaking flicker, add fullscreen theatre mode, and gate stream audio to viewers
- Maximize P2P screen sharing quality with High Profile H.264, SDP bandwidth signaling, and BWE fast-start
- Preserve native video quality
- Raise 60 fps bitrate ceiling
- Sync remote media state
- ICE candidates were being dropped, so no call ever connected
- The deployed SFU advertised its bridge address, so media never arrived
- /livekit reached LiveKit's root, so the WebSocket never upgraded
- Refuse to hand a client an SFU address only the server can reach
- A browser tab does not ask for a machine list it will never show
- A 200 that is not JSON is a failure, not null data
- The relay could not have 7881, so the candidate does not ask for it
- Address the containers by IPv4, not by "localhost"
- Serve the LAN dev app over TLS, or it has no crypto at all
- A stopped share should leave everyone else's stage, and let the browser own the audio question
- Give turbo enough slots for every persistent task
- Advertise an SFU address the host can actually reach
- Let the service write the volume its uploads go to
- Point the doctor at the compose file that is running the SFU
- Find the SFU from the host, not only from inside Docker
- Let a member who joined after the key was minted key itself
- Keep the package CommonJS; share the theme through a .mjs
- Stop a signed-in session dying on a backend that is not up yet
- Add type module and resolve electron binary installation
- Stop the dev SFU starting with a placeholder LiveKit secret
- Drop the workspace path mappings from tsconfig.base.json
- Let any member key an empty channel
- Stop sending requests without a bearer token
- Default LIVEKIT_URL to the gateway path in every mode
- Allow empty CLOUDFLARE_TUNNEL_TOKEN for compatibility with local setups
- Attach the gate after the track, not with it
- Bind the spliced gate source to a name instead of renaming it
- A shared screen no longer echoes the call back into it
- The pointer no longer disappears when control is taken
- The click lands where the pointer is, at the display size
- Control now reaches the machine, and add request-control
- Development ignores VITE_API_URL
- Announce a permission change to the member it is about
- Clear the unread line on its own, kill the last blue outline
- Clear an unread badge on focus, and mark where reading stopped
- Set AppUserModelID and explicit window.setIcon for Windows taskbar icon
- Replace thin rotated stroke path with solid bold CallEnd disconnect handset icon
- Fix disconnect button icon orientation and layout
- Notify only when the channel is not on screen, and cache history
- Migrations and OpenSSL in the container stack
- Upgrade SFU to v1.13.5 so track publishing negotiates
- Remove container loopback node_ip to fix WebRTC UDP media publishing in Docker
- Allow electron audio permissions, fix livekit docker UDP ports and voice channel retry
- Resolve dev-duo port conflict, voice connecting state & control buttons
- Improve logging for debugging and handle room disposal on hot reload
- Leave the roster on every disconnect, not just the button
- Allow the LiveKit origin through the renderer CSP
- Stop a third Electron window during pnpm dev:duo
Other changes
- A release that finishes, and a deployment it can reach
- Ask ECR again when it says "Rate exceeded"
- Fail when the tailnet join did not take
- Point at the standalone deploy workflow
- A deploy workflow of its own, so the host can be tested first
- Update the devdocs pointer for the tailnet policy
- Reach a host that has no port to forward, over Tailscale
- Name images rather than copy them, and stop hitting 429
- Rebuild images with migrations that survive the phase-35 rename
- Screen share audio, floating call dock, 1-to-1 direct calls, and sliding rate limiter
- Point at the phase 35-38 proposal
- What decides a share's picture is both clients, not one
- Document release trigger conventions in Release-Commit.md and update CLAUDE.md
- Add live TURN relay health probe and unify static relay configuration
- Update submodule pointer for the phase 29 relay docs
- One relay, configured in one place
- Stop passing a hosted TURN key nothing reads any more
- !docs : Updating docs
- Add custom TURN relay support and coturn deployment runbooks
- Ignore session handoff file in gitignore
- A worked coturn setup on Oracle Cloud
- Update submodule pointer for the TURN runbook link
- A runbook for standing up a coturn relay
- Update submodule pointer for the TURN credential note
- Update submodule pointer for the phase 28 relay docs
- A second way to configure a relay, and where it has to live
- Pass TURN_URLS through to call-service and remote-gateway
- Fix call echo, add tiered noise suppression, and admin server health
- Noise suppression levels and why echo is a separate problem
- Update development submodule pointer
- Document the echo path and three-level noise suppression
- Explain how the health snapshot is assembled
- Document the health screen and its unmeasurable fields
- Who is on the call stage, and what is allowed to move
- How a microphone is chosen, and why it must be exact
- What decides a share's picture, and what must never be a floor
- Stop committing the Kotlin compiler's scratch directory
- Describe who may see a last-seen time
- Describe last seen and the about line across the suite
- Describe forwarding across the clients
- Describe the profile photo viewer across the clients
- Make all sub-settings direct top-level items and remove nested cross-links
- Enforce strict Setting -> Subsection -> Option hierarchy for settings
- Remove redundant Calls & Data and Auto Update rows from main settings
- Remove redundant Privacy & Safety row from main settings screen
- Add rule that AI assistants must never push code
- Document the patch marker and the docs deploy
- Revert a failed release, rebuild one in place, deploy the docs
- Add the patch marker and the docs scope
- Document how the installer starts the app
- Document the ten-file cap and what it protects
- Document declining across an account's devices
- Document call.answered and the once-per-call roster
- Document one-signal-at-a-time negotiation
- Document per-kind backups and identity recovery
- Add top-level section links and automate changelog extraction
- Add download links to navbar, hero section, and intro pointing to GitHub Releases
- Update verifiable architecture, sequence, and lifecycle diagrams to Archify standard
- Changes done for alpha release
- Add cache buster query parameter to LOC badge
- Remove legacy FCM directory and DEPLOYMENT.md in favor of docs/
- Say what stops a one-time message being opened twice
- The web opens one-time messages in the app instead
- Say what each client can actually stop
- Describe one look each and the MessageView table
- Describe how an attachment is named and typed
- Describe voice messages and their waveforms
- Describe messages that stop existing
- Point at the server-clock notes
- Write down the rule for clocks and expiry
- Point at the clock and timezone notes
- Record the clock and timezone rules
- Point at the day divider notes
- Describe the message list's day dividers
- Migrate push suppression doc to docs/ and update references
- Document pnpm android:* across the public docs
- Run the Gradle build from pnpm
- Document link recovery, signalling reconnect, and the relay's role
- Update system architecture section with Archify Mermaid diagram
- Standardize all flowcharts to vertical Archify format with zoom & pan support
- Streamline architecture flowchart layout and contrast
- Update high-level runtime architecture diagram and devdocs protocol
- Sign-in no longer asks to unlock the key
- Enhance APK and AAB build process with matrix support
- Release notes are drawn as markdown on every client
- Point the submodule at the updates rewrite
- One Windows installer, a download that happens on its own, two Android jobs
- One Windows build, and make it a real installer
- Point at the members-list follow-up
- Describe the two searches and the row that refuses
- Downgrade Java version to 17 in project configuration files
- Point at submodule safety guidance
- Point at pushed dev-docs, including the consistency guideline
- Android uses the screen it is on
- Clearing one conversation
- Android has the accounts pass too
- The accounts pass across the public docs and README
- Point at the accounts-pass tracker
- Correct README "no light theme" claim
- Record device and cross-network verification across clients
- Changes done for new release
- Document Android Material You dynamic wallpaper theming
- Update guidelines for AI assistants and contributors in SKILL.md
- Document loopback origin security mapping and embed error handling
- Update architecture and development documentation with sync and embed fixes
- Update references to CLAUDE.md and add commit guidelines
- Add AGENTS.md symlink pointing to CLAUDE.md
- Update master reference index and submodule pointer
- Update development submodule ref to include README
- Add root CLAUDE.md to repository
- Organize devdocs folder and link root claude.md
- Add root CLAUDE.md pointer to private development docs
- Migrate development documentation and claude.md to private submodule
- Browse means two different things, and says which
- The gamepad is a dot on the Apps button now
- The last roll, the forward flick, and the clipped menu
- The library is six games, and the rules take two more arguments
- Ludo and Carrom
- Record Play Together
- Play Together
- Record the three desktop fixes and the new portable swap
- !docs : Docs is done
- Update favicon and brand logo with app icon
- Add interactive installation & setup section and feature highlights
- Update architecture and service docs with listen together and rich formatting
- A blocked window looks like a blocked window
- The browser that had to stop playing, and the seek that had to stay put
- Clicking a video is the control
- Playing what you found, and the browser that was making its own noise
- The panel's shape, and the two bugs it came from
- Browsing YouTube in the call, and the sandbox that made it silent
- Listen Together
- Record the live profile and server updates, and the status dot that was not live
- Correct the swipe-to-reply rule, and note the jump button
- Record the Material 3 Expressive redesign
- Record the Android catch-up and the drawer gesture
- Record read receipts and the reply shortcuts
- Record the session, hold and reconnect work
- Note why the scaling type alone did not stop the crop
- Record the in-call ring on the web, and the phone showing a whole frame
- Record the per-link call data, the analytics page and the Android screens
- Record the call log in TRACK, TODO and TESTING
- Remove obsolete SDD progress ledger file
- How each client notices a release and takes it
- Add implementation plan for mobile web responsive UI adaptation
- Add design spec for mobile web responsive UI adaptation
- A ring is not channel-scoped news, so focus does not swallow it
- Write down what a ring is and why it may be loud
- Desktop installers point at the deployment, not at localhost
- Record the main-process crash in the packaged desktop app
- Record the share picker and clipboard paste on Android
- Record the two faults that ended live sessions
- Add the missing Notifications architecture page
- Make localhost:3000/ work for dev, keep /Nexora/ in production
- Match the desktop client's exact theme
- Center the Android screenshot
- Embed the Android screenshot, add offline local search
- Redesign the doc pages, not just the landing page
- Redesign the landing page
- Add Android client architecture page
- Split the one giant ERD into per-section diagrams
- Add pnpm docs / docs:build / docs:install root scripts
- Replace default Docusaurus README with a project-specific one
- Add docs deploy workflow, triggered by a !docs marker
- Deployment, CI, security, testing and local-run guides
- Per-service REST/WebSocket reference
- Architecture, system design and database schema content
- Scaffold Docusaurus site under docs/
- Changes done for android release
- The no-clone install path, and the build commands it dated
- Record the share sheet, composer paste and the two screen fixes
- Done with the enhancement
- The second call-screen pass, and the one bug it did not close
- The call-screen pass recorded in TRACK.md
- RELEASING.md, and the pass recorded in TRACK.md
- Remove outdated Android chat notification suppression and PiP design documents
- Catch every doc up to push suppression, self-update, and the send-path fix
- One send path for every attachment
- The daily check and the installer session
- Record the self-update phase
- The picker that would not open, and what picture-in-picture needs
- Phase 27's call half is answered by call.roster, and Android rings from it
- Record this pass in TRACK.md and ANDROID_TODO.md
- Reconcile TRACK.md and ANDROID_TODO.md with what the code actually has
- Record the call-screen fixes and what to try on a device
- Betweenus is also available on arm docs
- Apha release done
- Record the missing
latest tag and the image slimming
- Build the runtime from a production install, not the build stage
- Record the call key's epoch and how it is kept current
- Pin the one re-read on a rotated channel key
- First Release Done
- Refactor Docker Compose Configuration
- Update android development tracking for active chat notification suppression
- Add implementation plan for android active chat notification suppression
- Add design spec for android active chat notification suppression
- Add new SVG icon with gradient backgrounds and headset details
- Implement code changes to enhance functionality and improve performance
- Launcher icon sourced from desktop SVG with gradient headset pads and #3730A2 background
- Launcher icon with #3730A2 background, 75% zoom mark, and monochrome layer
- Install BetweenUs adaptive launcher icon and render all density mipmaps
- Restore original clean template launcher icons in android res
- Record URL hyperlinking and rich link previews across Android, Web, and Desktop in TRACK.md
- Record permission carousel progression and notification banner in TRACK.md
- Record clean image preview and bu_date naming in TRACK.md
- Record push across the development documents, and untrack google-services.json
- Record Android permissions carousel in TRACK.md
- Update TRACK.md for TopBar toggle cleanup
- Remove duplicate right panel toggle from TopBar
- Update TRACK.md for default hidden member list
- Update TRACK.md for chat attachment preview and discard fix
- Record this pass, and name the key-publish trap
- Upload a few parts at a time rather than one
- Rename the app to BetweenUs
- A feature table that says which client each thing works on
- Invite management has a screen now, and deep links have a reason
- Configure ABI splits, resource filtering, and bundle splitting to reduce release APK size
- Update README with data path commands and pre-migration backup details
- Who the API believes, and what it still does not
- The follow latch, the media cache, and what to click
- The Bluetooth fix, the device pickers and the permission screen
- Keep the Android client out of the build context
- No signing config, and the launcher icon is ours
- Custom emoji, R8, and a README that says what this app now does
- R8 on, code and resources shrunk
- The authorization pass, and the two things it did not build
- Ten items closed, and the three that are only half closed
- The join and leave tones, and what to listen for
- What landed this pass, and what it did not close
- What landed this pass, and the migrations waiting behind it
- Track the accepted work in its own document
- Add initial Android project configuration files
- Correct post-SFU claims and open phase 27 for push notifications
- Replace tokei badge with working sloc.xyz live LOC calculator
- Update README with dynamic GitHub shields for LOC and repo metrics
- Add badge tags and shields to repository README
- Add Android client entries to architecture and request flow in README
- Update README with Android client and enhanced chat media documentation
- Update ANDROID_TODO with image/video viewer and storage album features
- Update ANDROID_TODO with WhatsApp-style media picker
- Record the Android local cache and where channel keys now live
- Add modules.xml for project configuration in Android module
- The share stage, and why a call outlives its screen
- Write down the slot contract, since breaking it is silent
- The epoch re-read, and how to test a re-key with two clients
- Split :core and :ui-common out of :app
- Add phased Android client roadmap
- Update README with home preview image and clarify P2P WebRTC mesh architecture
- Record phase 26 - the workbench
- Add new skills for UI library selection, prototyping, and animation review
- Record phase 25 - the call follows the account
- Improve negotiation logic and track handling for media streams
- What an operator has to do about media, which is now almost nothing
- Remove LiveKit, and the deployment settings that only existed for it
- An SFU and a Cloudflare Tunnel were never going to fit together
- The relay is what makes a call work over the tunnel
- How to tell a broken /livekit proxy from a broken SFU
- A loopback LIVEKIT_URL is the one that only works on the server
- Drop the join step logs and LiveKit's debug level
- What a blank web client was, and the two halves of the fix
- Mirrored networking alone does not open the WSL VM
- Check the LAN address answers before telling the SFU to advertise it
- The three ways a dev stack looks dead when it is only unstarted
- Why a call could not be joined in development, and what says so now
- Pin the invited member's first message
- The refresh grace window, and where the web client actually listens
- Describe the shared image build and what makes a rebuild slow again
- Build every image from one Dockerfile instead of nine
- Keep the desktop app and the worktrees out of the build context
- Cover the identity backup endpoints in the chat-service smoke run
- Describe identity backup, its threat-model cost, and how to port it
- Add .dockerignore
- Improve LiveKit key management and enhance server probing logic
- Update environment variable notes for clarity on DATABASE_URL and POSTGRES_PASSWORD alignment
- Update Nginx configuration to use dynamic upstream variables for improved service resolution
- Point the README at DEPLOYMENT.md and spell out which API URL a client uses
- Merge: deployment guide
- Merge: storage volume mapping for local uploads
- Write down how to actually deploy this
- Record the in-call device picker and the processor fix
- Record the microphone work
- Record the screen-share encoding work
- Record monitor selection and in-call control
- Record the remote-desktop and screen-share audio fixes
- Record phases 17 and 18
- Record phase 16, one address for a whole deployment
- Add a source-available, view-only licence
- Add the request flow, renderer to Prisma to Postgres and back
- Rewrite the README around the architecture
- Note what the history cache does not cover yet
- Pnpm dev:backend runs the services without the renderer
- Record phase 14 — notifications, the tray and auto-start
- Record phase 13 — media, attachments and profile pictures
- Cover uploads in the smoke script
- Cover phase 12 in the smoke scripts and dev:duo
- Rename workspace to server across the stack
- Plan phase 12 — servers, permissions and direct messages
- Record the admin panel, OAuth and notifications
- Move landed phase 10 work into Done
- Record phase 10 progress
- GitHub Actions pipeline with an integration job
- Presence smoke test, and make the chat smoke fail loudly
- Record voice/presence verification and the publish issue
- MVP quick start and honest verification status
- Add local Postgres/Redis compose, env template, development docs
- Init git
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop (Windows) | Built here |
| Android | Built here |
Features
- The rate-limit window slides
- The rotation grace moves to Redis, and a second instance becomes possible
- A socket that stops when the account does
- Something that actually deploys the images the pipeline pushes
- A secret can come from a file, and a signing secret can be rotated
- A backup that leaves the host
- A migration check that replays the whole history, and the one-off the rename needs
- Back leaves the call screen, and a dock stands in for it
- A shared screen goes out with its sound
- The conversation says when somebody joins
- Let a new member be added with the chat history, and hide sealed rows
- One-to-one calls on every client, and a header that shows the name
- Add PACKAGE_VERSION fallback in AdminHealthService for app version retrieval
- Enhance voice channel and share stage with fullscreen toggle and layout adjustments
Bug fixes
- A picture's type comes from its bytes, not from its uploader
- The health page, pointed at a deployment that is genuinely sick
- The three smoke scripts have been run, and two of them failed
- The two migrations that sorted backwards get a stamp that does not
- A film share holds its resolution instead of walking down to 480p
- The High profile preference that never once fired
- A share stops asking for a bitrate floor and sitting at 480p
- The call bar no longer leaves a status bar of empty space
- The call dock appears for a call started after the shell
- Coming back from picture-in-picture lands on the call
- A share picked from the sheet reaches the preview
Other changes
- Screen share audio, floating call dock, 1-to-1 direct calls, and sliding rate limiter
- Point at the phase 35-38 proposal
- What decides a share's picture is both clients, not one
- Document release trigger conventions in Release-Commit.md and update CLAUDE.md
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop (Windows) | Built here |
| Android | Built here |
Features
- Show whether the TURN relay would actually carry a call
Bug fixes
- Resolve the relay from configuration, not from a mint that can 404
Other changes
- Add live TURN relay health probe and unify static relay configuration
- Update submodule pointer for the phase 29 relay docs
- One relay, configured in one place
- Stop passing a hosted TURN key nothing reads any more
- !docs : Updating docs
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop (Windows) | Built here |
| Android | Built here |
Features
- Accept an operator's own TURN server, not only Cloudflare's
Other changes
- Add custom TURN relay support and coturn deployment runbooks
- Ignore session handoff file in gitignore
- A worked coturn setup on Oracle Cloud
- Update submodule pointer for the TURN runbook link
- A runbook for standing up a coturn relay
- Update submodule pointer for the TURN credential note
- Update submodule pointer for the phase 28 relay docs
- A second way to configure a relay, and where it has to live
- Pass TURN_URLS through to call-service and remote-gateway
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop (Windows) | Built here |
| Android | Built here |
Features
- Warn about failing echo cancellation during a call
- Report server health, storage and bandwidth to the admin panel
- Surface echo canceller failure in voice settings
- Three-level noise suppression and echo canceller health
- Admin server health and storage contract
- Pin a face to the call stage, and stop the stage moving on its own
- A call stage that holds still, and a pin for the face that matters
- Make connection error banners dismissable across all views
- Say what is holding a share's picture down
- Put a status dot on every face in a conversation
- Decide who may see when you were last here
- Last seen in the header, and a profile a double tap away
- Say who is here, when they were last here, and what they say
- Give an account an about line and a last-seen time
- Give the forward picker icons, faces and a limit
- Forward a message into another channel
- Carry a forwarded-from tag inside the message body
- Open the photo behind an avatar
- Add dedicated PermissionDetailScreen subpage for each permission
- Add hierarchical settings subsections and options subpages
- Fix icon colors and create dedicated permissions page
- Declining stops the ring on this account's other devices
- Update changelog for alpha release 0.0.1-alpha.18 with new features, bug fixes, and documentation improvements
- Upgrade 3D hero showcase with interactive subsystem inspector and vector icons
- Add interactive 3D logo showcase and spatial chips to landing page
Bug fixes
- Let the API client load outside Vite for the self-checks
- Scope event buffer lookup for query responses in smoke test
- Ask for the microphone somebody chose, not one like it
- Stop the SDP asking for a bitrate floor nobody can afford
- Stop blaming the microphone for a link that never connected
- Show the about line on a profile, and your own status on yours
- List everywhere a forward could go, not one server's channels
- Let the share picker be seen before the files are claimed
- Give the seen-by row its tap back
- Show the other person's photo in a direct message header
- Derive the version code from the version name
- Derive the build version from the repository manifest
- Resolve system daylight/dark theme state synchronization in themes and settings
- Disable navigation drawer gesture on settings screens
- Start the app after an install and after an update
- Cap a message at ten files where they are picked
- Size the message cap for its manifest
- Stop the ring elsewhere, and announce a call once
- Apply WebRTC signals one at a time per peer
- Recover a forked identity on the next sign-in
Other changes
- Fix call echo, add tiered noise suppression, and admin server health
- Noise suppression levels and why echo is a separate problem
- Update development submodule pointer
- Document the echo path and three-level noise suppression
- Explain how the health snapshot is assembled
- Document the health screen and its unmeasurable fields
- Who is on the call stage, and what is allowed to move
- How a microphone is chosen, and why it must be exact
- What decides a share's picture, and what must never be a floor
- Stop committing the Kotlin compiler's scratch directory
- Describe who may see a last-seen time
- Describe last seen and the about line across the suite
- Describe forwarding across the clients
- Describe the profile photo viewer across the clients
- Make all sub-settings direct top-level items and remove nested cross-links
- Enforce strict Setting -> Subsection -> Option hierarchy for settings
- Remove redundant Calls & Data and Auto Update rows from main settings
- Remove redundant Privacy & Safety row from main settings screen
- Add rule that AI assistants must never push code
- Document the patch marker and the docs deploy
- Revert a failed release, rebuild one in place, deploy the docs
- Add the patch marker and the docs scope
- Document how the installer starts the app
- Document the ten-file cap and what it protects
- Document declining across an account's devices
- Document call.answered and the once-per-call roster
- Document one-signal-at-a-time negotiation
- Document per-kind backups and identity recovery
- !docs : Updating docs
- Add top-level section links and automate changelog extraction
- Add download links to navbar, hero section, and intro pointing to GitHub Releases
- Update verifiable architecture, sequence, and lifecycle diagrams to Archify standard
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop (Windows) | Built here |
| Android | Built here |
Features
- Draw a voice message as a voice message
- A microphone, one look, and two windows
- One look, and a window that keeps moving
- Hold the microphone where send used to be
- Give a message an expiry and one look
- Read the time off the server's clock
- Divide the message list by day
- Rebuild a dead call link instead of asking the user to rejoin
- Expand max zoom level to 3000% with dynamic stepping
- Register zoom controls in MDXComponents and linearize architecture diagram
- Add interactive zoom pan and fullscreen controls for Mermaid diagrams
Bug fixes
- Make a one-time message actually one-time
- Stop a one-time viewer closing itself, and refuse it on the web
- Fetch a one-time message before burning it
- One look each, and let people see what they opened
- Send an audio file with its own name and type
- Make the voice waveform visible, and lose the inner card
- Forget a deleted picture's plaintext
- Follow the device's 24-hour setting
- Tell the time the way the reader's system does
- Stop call tiles stretching to the shape of the stage
- Mark subproject as dirty to indicate uncommitted changes
- Say when no relay is configured instead of failing silently
- Recover broken call links instead of dropping them
- Sign in without asking to unlock the key
Other changes
- Changes done for alpha release
- Add cache buster query parameter to LOC badge
- Remove legacy FCM directory and DEPLOYMENT.md in favor of docs/
- Say what stops a one-time message being opened twice
- The web opens one-time messages in the app instead
- Say what each client can actually stop
- Describe one look each and the MessageView table
- Describe how an attachment is named and typed
- Describe voice messages and their waveforms
- Describe messages that stop existing
- Point at the server-clock notes
- Write down the rule for clocks and expiry
- Point at the clock and timezone notes
- Record the clock and timezone rules
- Point at the day divider notes
- Describe the message list's day dividers
- Migrate push suppression doc to docs/ and update references
- Document pnpm android:* across the public docs
- Run the Gradle build from pnpm
- Document link recovery, signalling reconnect, and the relay's role
- Update system architecture section with Archify Mermaid diagram
- Standardize all flowcharts to vertical Archify format with zoom & pan support
- Streamline architecture flowchart layout and contrast
- Update high-level runtime architecture diagram and devdocs protocol
- Sign-in no longer asks to unlock the key
- !docs : Updating docs
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop (Windows) | Built here |
| Android | Built here |
Other changes
- Enhance APK and AAB build process with matrix support
Artifacts
Features
- Draw release notes as markdown on the sheet and the screen
- Draw release notes as markdown rather than as their source
- Give adding a friend its own screen
- Add project code style configuration and permissions settings
- Adaptive shell for tablets and foldables
- Clear one conversation, from a three-dot menu in its header
- Blocking, clearing your own history, and a way back into a forgotten account
- Outgoing mail settings and a per-account password reset
- Forgotten passwords, admin-configured SMTP, and a Bloom-filtered username check
- Block a user, and clear your own history everywhere
- Blocks, password resets, SMTP settings and a cleared-chats marker
Bug fixes
- A blank line is a paragraph break when the notes are read
- Download the update without being asked, and say which channel is on
- Take the new-messages bar away the moment it is read
- Stop offering yourself a conversation with yourself
- Stop a refused DM crashing the members list
- Draw a person's name once
- Retry channel self-heal after a dropped mint request
Other changes
- Changes done for alpha release
- Release notes are drawn as markdown on every client
- Point the submodule at the updates rewrite
- One Windows installer, a download that happens on its own, two Android jobs
- One Windows build, and make it a real installer
- Point at the members-list follow-up
- Describe the two searches and the row that refuses
- Downgrade Java version to 17 in project configuration files
- Point at submodule safety guidance
- Point at pushed dev-docs, including the consistency guideline
- Android uses the screen it is on
- Clearing one conversation
- Android has the accounts pass too
- The accounts pass across the public docs and README
- Point at the accounts-pass tracker
- Correct README "no light theme" claim
- Record device and cross-network verification across clients
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop (Windows) | Built here |
| Android | Built here |
Features
- Add dynamic wallpaper theming (Material You) toggle and system palette generator
- Add fluid slide & fade transitions and animated theme grid for themes screen
- Create dedicated theme pages and navigation across all platforms
- Add 16-theme suite, custom accents, system sync, and appearance settings
- Expand theme suite to 16 themes with category filtering
- Add theme suite with system sync and custom accents
- Enhance user and server settings UI with desktop header and close button
- Add betweenus skill configuration for agents and claude
Bug fixes
- Use ECR Public mirror for node and nginx images to avoid pull limit issues
- Eliminate status bar color seam across chat, friends, servers, and sub-screens
- Match status bar and toolbar background across settings and themes screens
- Dynamic status bar icon tinting on light themes & update documentation
- Sync native window titlebar overlay with active theme
- Ensure live theme switching with css rules and dual-target property injection
- Map loopback origins to localhost and handle youtube embed errors gracefully
- Use youtube.com embed with strict-origin referrer to fix video unavailable error
- Fix player host offscreen parking and tab switching for web sync
- Broaden youtube origins and CSP frame-src for web client
Other changes
- Changes done for new release
- Document Android Material You dynamic wallpaper theming
- Update guidelines for AI assistants and contributors in SKILL.md
- Document loopback origin security mapping and embed error handling
- Update architecture and development documentation with sync and embed fixes
- Update references to CLAUDE.md and add commit guidelines
- Add AGENTS.md symlink pointing to CLAUDE.md
- Update master reference index and submodule pointer
- Update development submodule ref to include README
- Add root CLAUDE.md to repository
- Organize devdocs folder and link root claude.md
- Add root CLAUDE.md pointer to private development docs
- Migrate development documentation and claude.md to private submodule
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop (Windows) | Built here |
| Android | Built here |
Features
- The web client gets a search box, not just a paste box
- Apps is a screen on the stage, not a popover
- One Apps button, and a fullscreen board
- The sidebar music and gamepad buttons open the options
- Ludo and Carrom, the second with real physics
- Play Together - a games panel on the voice stage
- Referee a game on /ws/call
- The Play Together contract and the rules of four games
Bug fixes
- The sidebar menu was clipped, the die was never seen, and carrom aimed backwards
- A game nobody could sit down in looked like a board that ignored clicks
- Give the Listen Together player a real origin
- Keep the notice strips clear of the window controls
- Swap a portable update from a helper script, not from the app
- Give the YouTube embed a referrer so Listen Together loads
Other changes
- Changes done for new release
- Browse means two different things, and says which
- The gamepad is a dot on the Apps button now
- The last roll, the forward flick, and the clipped menu
- The library is six games, and the rules take two more arguments
- Ludo and Carrom
- Record Play Together
- Play Together
- Record the three desktop fixes and the new portable swap
- !docs : Docs is done
- Update favicon and brand logo with app icon
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop (Windows) | Built here |
| Android | Built here |
Features
- Pressing play on the page plays it for the call
- Press a video, the call watches it - no link, no button
- Press a video on YouTube and it plays, without the queue detour
- The Listen Together panel
- The Listen Together player, and the clock it runs on
- Listen Together, the shared transport on /ws/call
- Show the marks in the composer as they are typed
- Return makes a newline inside a list, quote or fence
- Carry a list on to its next item
- Render markdown in messages
- A markup parser, ported from android
- Draw bulleted and numbered lists in messages
- Bulleted and numbered lists
- Bubble-style message rows, matching the android layout
Bug fixes
- The pause button that did nothing, in a window that was silent
- Nothing plays in the browser, on the one event that catches it
- The browser is not a second player
- A seek that snapped back, and a browser that could be heard
- The second copy of the song, playing in the browser tab
- One Listen Together panel, on the stage, bounded
- The sandbox that made it silent, and YouTube itself in the call
- Hide the members panel by default
- Grow the composer with what is typed, up to a cap
- Wrap long composer text instead of scrolling it
- Shrink the chat header call button to match its neighbours
- Double-click reply, not native word-select
- Swipe right-to-left replies, left-to-right stays the drawer's
- A peer id that survives a reconnect, and a seat held for one
- Reopen a socket the background killed, on the way back
- Only a refused credential ends a session
Other changes
- Changes done for new release
- Add interactive installation & setup section and feature highlights
- Update architecture and service docs with listen together and rich formatting
- A blocked window looks like a blocked window
- The browser that had to stop playing, and the seek that had to stay put
- Clicking a video is the control
- Playing what you found, and the browser that was making its own noise
- The panel's shape, and the two bugs it came from
- Browsing YouTube in the call, and the sandbox that made it silent
- Listen Together
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop (Windows) | Built here |
| Android | Built here |
Features
- Repaint a changed picture, name or server without a restart
- Repaint a changed picture or name where it already is
- Announce a changed profile or server, rather than let it go stale
- Draw several photos as one album, not several cards
- Draw several photos as one album, not several attachments
- Draw messages the way a phone messenger draws them
- Offer a way back down when the conversation is scrolled up
- Let the sheets take their colour from the scheme
- Put the call controls in a floating toolbar
- Repaint the entry, friends and settings screens
- Redraw the conversation
- Move the shell onto the scheme, and give it motion
- Rebuild the shared controls in the expressive language
- Give the client a Material 3 Expressive theme
- Seen-by faces on a message, and swipe a row to reply
- Draw who has seen a message, and reply on a double click
- Say who has read a message, derived from the read markers
- Hold a call when another one takes the audio, and say so
- Say when the connection is down, and stop retrying after 30s
Bug fixes
- Pad connection banner for status bar insets and consume them in shell
- Give the drawer a fixed gutter, not a fraction of the screen
- Make the status dot subscribe to statuses rather than to a function
- Give the drawer a third of the row rather than half
- Split the row down the middle, and make a swipe prove it is one
- Make the call screen readable, and let the chrome leave downwards
- Give the gutter to the drawer by moving the gesture, not guarding it
- Size the composer's buttons to the bar they are in
- Give the left edge to the drawer, the message to the reply
- Ask the system for the swipe area instead of ceding it
- Leave the left edge to Back and the drawer
- Catch up after the background, and stop the drawer stealing the swipe
- Centre the initial in a pictureless avatar
- Show the notification the prompt was asked for, and fade the read line
- Scope refresh-token reuse revocation to one sign-in
Other changes
- Changes done for new release
- Record the live profile and server updates, and the status dot that was not live
- Correct the swipe-to-reply rule, and note the jump button
- Record the Material 3 Expressive redesign
- Record the Android catch-up and the drawer gesture
- Record read receipts and the reply shortcuts
- Record the session, hold and reconnect work
- !docs : Docs is done
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop (Windows) | Built here |
| Android | Built here |
Features
- Ring somebody into the call from the call controls
- Add somebody to a call from inside the call
- A Calls & data screen, and a phone that reports what it moved
- A Calls & Data page, and per-link measurement to fill it
- Record what each link in a call moved, and add up a month of them
Bug fixes
- Size the surface to the frame, so "fit" actually fits
- Show a whole camera, and give the call dock room to breathe
- Drop an answer that arrives after the connection is already settled
Other changes
- Changes done for new release
- Note why the scaling type alone did not stop the crop
- Record the in-call ring on the web, and the phone showing a whole frame
- Record the per-link call data, the analytics page and the Android screens
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop (Windows) | Built here |
| Android | Built here |
Features
- Show a call log in settings, and count what a call moved
- Record a per-person call log in call-service
- Optimize full-screen views, settings, and voice for mobile viewports
- Convert right panels to mobile slide-over sheets
- Add mobile header and hamburger navigation toggle
- Offer a reload when a newer build is being served
- Create android-style workspace navigation drawer
- Check for, download and apply updates, per Windows flavor
- Add responsive hooks and breakpoint utilities
- Answer a ring without leaving the window
- Answer a ring from the lock screen
- Carry a ring to every device the person has
- Ring one person into a call
Bug fixes
- Add ensure-electron script to prevent MODULE_NOT_FOUND during install
- Fix server members slide-over panel and auto-navigate to text on voice disconnect
- Remove duplicate mobile TopBar header and fix friends tab clipping
- Point the updater at the repository that publishes the APKs
- Correct indentation for ConnectionSheet visibility in VoiceChannelScreen
- Add drag region to LoginScreen for better window interaction
- Auto-extract and configure electron binary on install and dev
- The microphone is on when it is opened, not a moment later
Other changes
- Changes done for new release
- Record the call log in TRACK, TODO and TESTING
- Remove obsolete SDD progress ledger file
- How each client notices a release and takes it
- Add implementation plan for mobile web responsive UI adaptation
- Add design spec for mobile web responsive UI adaptation
- A ring is not channel-scoped news, so focus does not swallow it
- Write down what a ring is and why it may be loud
- Desktop installers point at the deployment, not at localhost
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop (Windows) | Built here |
| Android | Built here |
Features
- Show how long the call has been running
- Input sensitivity, which was not blocked after all
- Tell the owner when somebody is on their machine
- Web push, so a closed tab is still reachable
- Safety numbers, so a lying key directory can be caught
- Implement file transfer functionality over data channel
- A share sheet hand-off now asks where it is going
Bug fixes
- The packaged app died before it opened a window
- A copied image could not be pasted into a message
- A socket whose token expired gave up instead of refreshing
- A network blip during refresh signed you out
- A voice channel stopped listing people who had left
- Stop throwing away the microphone you picked
- The microphone gate was refused by CSP, so it never ran
- Correct every Nexora reference to the real repo name, BetweenUs
- Stop tracking .claude/worktrees, unbreak recursive-submodule checkouts
Other changes
- Changes done for new release
- Record the main-process crash in the packaged desktop app
- Record the share picker and clipboard paste on Android
- Record the two faults that ended live sessions
- !docs : Docs is done
- Add the missing Notifications architecture page
- Make localhost:3000/ work for dev, keep /Nexora/ in production
- Match the desktop client's exact theme
- Center the Android screenshot
- Embed the Android screenshot, add offline local search
- Redesign the doc pages, not just the landing page
- Redesign the landing page
- Add Android client architecture page
- Split the one giant ERD into per-section diagrams
- Add pnpm docs / docs:build / docs:install root scripts
- Replace default Docusaurus README with a project-specific one
- Add docs deploy workflow, triggered by a !docs marker
- Deployment, CI, security, testing and local-run guides
- Per-service REST/WebSocket reference
- Architecture, system design and database schema content
- Scaffold Docusaurus site under docs/
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop (Windows) | Built here |
| Android | Built here |
Features
- Print every command the deployment needs after the copy
- The installer copies the files and stops there
- Install a deployment without cloning the repository
- Paste a picture into the composer
- Send into BetweenUs from the system share sheet
Bug fixes
- One owner for the message list's scroll
- Keep the call header clear of the status bar
Other changes
- Changes done for android release
- The no-clone install path, and the build commands it dated
- Record the share sheet, composer paste and the two screen fixes
Artifacts
Features
- Audio devices follow whatever is plugged in
Bug fixes
- Add caching for Electron build and implement retry logic for packaging
- A link that is refused or unanswered can now recover
- The self-view is inside its corners, and PiP shows the speaker
- Incoming video stops flickering
- The speaking ring reads a level that is actually there
Other changes
- Done with the enhancement
- The second call-screen pass, and the one bug it did not close
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop (Windows) | Built here |
| Android | Built here |
Features
- A platform a release skips keeps the last one's artifacts
- A marker can name the platforms it is for
- Reconnect a dropped call, and end one that cannot be reconnected
- A notification read on one device takes itself down on the others
- The connection panel, ported from the desktop
- The green speaking ring lights for your own tile too
- Do not wake a phone for a message being read on another device
- A daily update check, and an install that reports what happened
- The auto update screen, and the prompt on launch
- Fetch, download and hand over a newer release
- The rules for which release a device should install
Bug fixes
- The self-view snaps to a corner, and the chrome gets out of the way
- Video has the rounded corners it appears to have
- Every attachment goes out under the foreground service
Other changes
- Done with the enhancement
- The call-screen pass recorded in TRACK.md
- RELEASING.md, and the pass recorded in TRACK.md
- Remove outdated Android chat notification suppression and PiP design documents
- Catch every doc up to push suppression, self-update, and the send-path fix
- One send path for every attachment
- The daily check and the installer session
- Record the self-update phase
Artifacts
| Platform | This release |
|---|
| Server images | Built here |
| Desktop (Windows) | Built here |
| Android | Built here |
Features
- Phase 13 hardening - Keystore session, private CA, crash reports, CI
- The remote clipboard, both directions
- A direct call rings, full-screen, with the app dead
- A call ducks for a prompt and holds for a phone call
- The member menu - message, add friend, mute, copy id
- A colon menu, the server's own emoji in the picker, and animated ones
- Bold, italic, strike, code and quotes in a message body
- Back out of a call and it keeps going in a floating window
- A call takes the whole screen
- Publish the service images for arm64 as well as amd64
- Let a caller ask for a channel key that is not the cached one
- Release through a PR, and undo a release that fails halfway
- Marker-driven releases to Docker Hub, with the clients attached
- Implement adaptive stage grid scaling, uniform video cards, and floating control dock
- Redesign call screen with WhatsApp-style adaptive layout, PiP self-view, and camera flip
- Draw the four new pushes, and undraw a deleted message
- Push for deletes, friends, servers and calls
- Use PushGate.shouldSuppress in PushService
- Add PushGate.shouldSuppress active channel check with unit tests
- Make message URLs clickable hyperlinks and render rich OpenGraph previews
- Add URL unfurling service and metadata API endpoint
- Add WhatsApp-style permission flow and top notification warning banner
- Remove overlay on image cards and save media as bu_
{date}
- Add permissions carousel screen with progress and allow-all button
- FCM push, so a swiped-away phone is reachable
- Hide server people/members list by default
- Send files in the background, and shrink a video first
- Crop and rotate before a picture is sent or stored
- Set an avatar and a server icon from the phone
- Manage a machine's access and read its audit trail
- Add and remove a server's own emoji
- Make and edit a server's own roles
- Sign in with a provider, and open invite links
- Accept a mobile redirect, bound to a challenge the app keeps
- Upload large attachments in parts
- Invites as links, previewed before they are accepted
- Show what an invite leads to before it is accepted
- Convert every sent photo to JPEG, HEIC included
- Decode HEIC in the client, and send every photo as JPEG
- One data path, and a dump before every migration
- The headers a browser needs to be told once
- A server's own emoji, animated ones included
- Type ":" and a name to reach an emoji
- What you can do about a person, from the list that names them
- A link, so anybody can be let in without being added
- One screen at a time - a new share replaces the one before it
- A key per machine, so a lost one can be revoked
- Invite management, and a line that was lying about the slug
- Microphone processing, a hi-fi mode, and where the call comes out
- Reconnect when the network comes back, not when the timer says
- A reaction says who left it, not just how many
- A list of servers this client has been on, and a contract check
- Tell a LAN it is a LAN - a manual bitrate, frame rate and codec
- An unread line that survives a restart, and a way to reach it
- The same two notes when somebody joins or leaves a call
- Two notes when somebody joins the call, two when they leave
- A cache on desktop and web, so opening the app is not a spinner
- Look at a photo before sending it, and show a video's first frame
- Look at a photo before sending it, and drop files anywhere
- Scroll back through history on desktop and web
- Replies, on all three clients
- A monitor plugged in mid-session is noticed
- The roles screen learns to draw a server's own roles
- Two ways to be driven, two targets
- A chord that arrives as a chord
- Add Firebase Crashlytics configuration to appInsightsSettings
- A blob that leaves when its message does
- An attachment row per upload, so a blob has an owner
- Roles a server can invent for itself
- A session that survives its two halves landing on different replicas
- A record of what was done, and a way past the first hundred rows
- Edit who is on a private channel
- Measure the call, and say when nobody can hear you
- Push to talk
- Turn one person down, or off, without touching the others
- Invites that expire, run out and can be taken back
- Sweep what nothing was sweeping, and stop scanning for agent tokens
- Rotate a channel's key when somebody loses access to it
- A channel can be set to mentions only
- The roster comes from the service that holds the sockets
- Send presence only to the people entitled to it
- Go idle on its own after ten minutes, and come back
- Rate limit login per account as well as per address
- Add emoji picker and quick camera button in composer, auto-hiding camera when keyboard is open
- Display You in accent color for current user in chat view, pinned and search panels
- Enhance chat screen with media viewer, video player and gallery storage
- Add storage write permissions and video/audio attachment support
- Implement WhatsApp-style media picker and attachment sheet
- Add media and camera permissions and FileProvider setup
- Keep channel keys, so cached history opens without the network
- Open on what the app already knows, not on a spinner
- Spend the bitrate, send the whole screen
- Tell the gateway where a phone can reach it
- Come back to where you were, and go where a tap says
- Lay the share stage out like a meeting client
- A share takes the whole screen, the way it has to
- A call that looks like a call to the system
- Drop the browser context menu
- A gateway for clients that cannot use a Vite proxy
- Voice, video, screen share and the remote-desktop viewer
- Servers, channels, messages, members, settings
- The stores, and the widgets every screen is built from
- The whole REST surface, and end-to-end encryption
- Sign in, switch servers, and land on home
- Nexora palette, and a server address the build does not decide
- Initialize Android project structure with basic configurations and resources
- Implement Picture-in-Picture (PiP) overlay for voice calls
- Add Teams-style floating Picture-in-Picture mode and fix screen occlusion
- One entrance for everything that opens on top
- Carry the workbench into the surfaces inside the panels
- Rebuild the client as a workbench of floating panels
- Enhance screen capturing on Windows with background throttling adjustments
- Add initial configuration for build and typecheck tasks
- One call per account, whichever device joins last
- Warn before a browser tab with a live call is closed
- Keep the call running while the client navigates away
- Add BM25 search engine for UI/UX style guides with design system generation and persistence options
- Add Hide/Show camera controls to expand stream content to full width
- Add Teams and Google Meet style Side Gallery camera layout alongside screen share
- Add auto-hiding controls, participant toggle, and polished glassmorphic UI for fullscreen mode
- The screen goes straight to the controller, not through a room
- A mesh of peer connections, where the SFU used to be
- A switchboard, so two clients can find each other without an SFU
- Relay media through TURN, so a call works from another network
- A render that throws is a message, not a blank window
- Implement LAN SFU and ICE candidate rewriting for remote access
- Reach the dev stack from a second machine on the network
- Notifications and provider sign-in in a browser
- Serve the web client at the root of the gateway
- Add the browser client as its own app
- Gate the remote-desktop section on the Electron bridge
- Restore the account encryption key on any machine you sign in on
- Store a sealed identity backup so an account is not tied to one machine
- Update TypeScript configuration and add path mappings for shared packages
- Check at startup that LiveKit accepts our tokens
- Give a new server a voice channel as well as #general
- Add packaging scripts for portable and NSIS targets in desktop app
- Enhance deployment instructions and add production scripts for easier setup
- Change microphone and speakers from inside the call
- Give Voice & Video something to set
- Let a deployment choose where local uploads live
- Publish the microphone the way this machine is set up
- Close the microphone when nobody is talking
- Decide what a microphone should sound like
- Encode a screen share like something worth watching
- Give control of a screen share in a call, with named cursors
- Choose which monitor a session watches
- Request control from somebody's screen share
- Public ingress that fits a tunnel you already run
- Be a remote machine, and reach one
- Enrolment, grants, sessions and the relay
- Remote machines, grants, sessions and an audit trail
- Proxy LiveKit signalling, so a deployment is one hostname
- Choose the server from the login screen
- One address for a whole deployment, resolved at runtime
- Message actions - tombstones, edits, pins, reactions, search
- Implement message deletion and friend event notifications
- Add high-res icon rendering and portable production build target
- Set taskbar, electron window, system tray, and installer application icon
- Integrate brand icon from icon.svg with dark gradient styling across desktop app
- Honour mutes, quiet hours and Do Not Disturb
- System tray, close to tray, and start with the system
- Notification-service owns mutes, quiet hours and read state
- Play video and audio inline, and cap image previews
- Upload avatars and server icons
- Attach, preview and download files in the message view
- Encrypted attachments, compressed and uploaded in parts
- Attachment manifest and settable profile pictures
- Multipart uploads and a picture/attachment split
- Drop the default Electron menu bar
- Rebuild the client as a Discord-shaped app
- Choosable status, with invisible resolved server-side
- Friends, user search and direct messages
- Private channels with a member allowlist
- Per-member permission overrides and one access resolver
- Web admin panel for users and sign-in providers
- Sign in with Google or GitHub
- Admin API, account management and OAuth sign-in
- Admin role, OAuth provider config, and
pnpm admin:create
- Notifications for messages and voice joins
- Request-scoped logging with a correlated request id
- Refresh-token reuse detection and service-level rate limits
- Screen-share picker, theatre layout and paged grid
- Voice channel screen with participant tiles
- Voice channels, online status and typing indicators
- Encrypted messages, LiveKit calls, two-window dev harness
- Enhance development configuration for API and WebSocket URLs
- Local-disk uploads when S3 is not configured
- Electron shell and Discord-style chat client
- Nginx gateway routing and full-stack compose
- Message REST API and /ws/chat realtime gateway
- Workspaces, membership and channels
- Registration, login, refresh rotation and /me
- Shared types, config, logger, auth, permissions, events, database
Bug fixes
- The release build, broken by a listener that no longer exists
- Picture-in-picture refuses cleanly, and knows when it is on
- The screen share picker could not open
- A reply typed into the shade that cannot be sent is kept, not dropped
- Adding somebody to a server no longer means guessing a username
- The self-view that was always an empty box
- Let admin:create and seed run from the deployed image
- Repair action refs mangled by the arm64 patch script
- Point
latest at every release, not only stable ones
- Re-read the channel key when somebody joins the call
- Stop the scheduled backup racing the pre-migration one
- Download the two artifacts by name, and promote after publishing
- Mark gradlew executable in the index
- Decode a keystore secret in every shape it actually arrives in
- A merged release PR builds again
- Detect the release commit by the version moving, not by files changing
- Follow the compose split, and give prod:up something to pull
- Make the integration smokes match the services they test
- Restore the workspace links that typecheck resolves through
- Remove image file size from preview overlay header
- Remove duplicate avatar icon from account settings picture picker
- Keep the call's peer id in step with its socket
- Adjust launcher icon scale to 54% safe-zone to prevent circle mask clipping
- Update Firebase Crashlytics connection settings with actual values
- A second machine reads the history, not a wall of padlocks
- Fix drop image preview loading and discard upload handling
- Derive the OAuth redirect allow list, and take a username to sign in
- The key, the roster and the sign-in prompt
- Give every video tile the shape of the picture in it
- Re-anchor the message list when the keyboard opens
- Ensure backup directory permissions and add diagnostic write check
- An origin is not a string that starts the same way
- The endpoints behind a token still get a budget
- A session is not an entitlement to every attachment
- A socket frame is as big as the traffic, not as big as ws allows
- A token does not get to say how it is checked
- A caller does not get to choose which bucket counts them
- A picture sent from a phone says how big it is
- A growing row is not somebody scrolling away
- A picture that has been decrypted stays decrypted
- Scrolling away is something only the reader does
- A paired Bluetooth headset is found again
- The list stopped stuttering when pictures arrive
- A moderator cannot edit or kick an administrator
- An attachment is not served to a stranger
- Managing members is not permission to conscript the directory
- A capture bound to a device does not follow the one you plug in
- Open a channel at its newest message, not wherever the last one sat
- The server picker's recreate() was talking to nobody
- A still screen is not a share that ended
- Remove redundant YOU badge in message rows
- Hanging up now ends the call notification
- Watching a share no longer bounces back to the grid
- Mute the microphone, not just the track carrying it
- Say who is in a voice channel, and notice when it changes
- Do not start a projection before the service can carry one
- Stop asking the sender for 720p30
- A share that is not moving has not ended
- Be seen in the call, and give up on one that never answers
- Rejoin the call when the socket comes back
- Leaving a call goes back to the conversation, not into one
- Show a share at the shape and the resolution it is sent at
- Rotating during a share no longer loops until it crashes
- Write a message body the way the other clients read one
- Returning to a call from its notification no longer ends it
- Send a call to the speaker, not to silence
- The four transceiver slots a call is actually made of
- Start the dev gateway as part of pnpm dev
- Show a server the moment this account is added to it
- Re-read the key directory when a message arrives at an unknown epoch
- A failed call can be joined again
- Say which address could not be reached
- Fix server icon size and active background outline in server rail
- One Nexora mark, and a rail tile that says where it goes
- Keep the user strip at the bottom of the sidebar
- Put each layout toggle on the side it controls
- Only offer the right-panel toggle where there is a right panel
- Use the WGC feature name this Chromium actually knows
- Update codec type from RTCRtpCodecCapability to RTCRtpCodec
- Keep camera feeds permanently visible in fullscreen mode and only auto-hide controls
- Fix muted speaking flicker, add fullscreen theatre mode, and gate stream audio to viewers
- Maximize P2P screen sharing quality with High Profile H.264, SDP bandwidth signaling, and BWE fast-start
- Preserve native video quality
- Raise 60 fps bitrate ceiling
- Sync remote media state
- ICE candidates were being dropped, so no call ever connected
- The deployed SFU advertised its bridge address, so media never arrived
- /livekit reached LiveKit's root, so the WebSocket never upgraded
- Refuse to hand a client an SFU address only the server can reach
- A browser tab does not ask for a machine list it will never show
- A 200 that is not JSON is a failure, not null data
- The relay could not have 7881, so the candidate does not ask for it
- Address the containers by IPv4, not by "localhost"
- Serve the LAN dev app over TLS, or it has no crypto at all
- A stopped share should leave everyone else's stage, and let the browser own the audio question
- Give turbo enough slots for every persistent task
- Advertise an SFU address the host can actually reach
- Let the service write the volume its uploads go to
- Point the doctor at the compose file that is running the SFU
- Find the SFU from the host, not only from inside Docker
- Let a member who joined after the key was minted key itself
- Keep the package CommonJS; share the theme through a .mjs
- Stop a signed-in session dying on a backend that is not up yet
- Add type module and resolve electron binary installation
- Stop the dev SFU starting with a placeholder LiveKit secret
- Drop the workspace path mappings from tsconfig.base.json
- Let any member key an empty channel
- Stop sending requests without a bearer token
- Default LIVEKIT_URL to the gateway path in every mode
- Allow empty CLOUDFLARE_TUNNEL_TOKEN for compatibility with local setups
- Attach the gate after the track, not with it
- Bind the spliced gate source to a name instead of renaming it
- A shared screen no longer echoes the call back into it
- The pointer no longer disappears when control is taken
- The click lands where the pointer is, at the display size
- Control now reaches the machine, and add request-control
- Development ignores VITE_API_URL
- Announce a permission change to the member it is about
- Clear the unread line on its own, kill the last blue outline
- Clear an unread badge on focus, and mark where reading stopped
- Set AppUserModelID and explicit window.setIcon for Windows taskbar icon
- Replace thin rotated stroke path with solid bold CallEnd disconnect handset icon
- Fix disconnect button icon orientation and layout
- Notify only when the channel is not on screen, and cache history
- Migrations and OpenSSL in the container stack
- Upgrade SFU to v1.13.5 so track publishing negotiates
- Remove container loopback node_ip to fix WebRTC UDP media publishing in Docker
- Allow electron audio permissions, fix livekit docker UDP ports and voice channel retry
- Resolve dev-duo port conflict, voice connecting state & control buttons
- Improve logging for debugging and handle room disposal on hot reload
- Leave the roster on every disconnect, not just the button
- Allow the LiveKit origin through the renderer CSP
- Stop a third Electron window during pnpm dev:duo
Other changes
- Done with the enhancement
- The picker that would not open, and what picture-in-picture needs
- Phase 27's call half is answered by call.roster, and Android rings from it
- Record this pass in TRACK.md and ANDROID_TODO.md
- Reconcile TRACK.md and ANDROID_TODO.md with what the code actually has
- Record the call-screen fixes and what to try on a device
- Betweenus is also available on arm docs
- Apha release done
- Record the missing
latest tag and the image slimming
- Build the runtime from a production install, not the build stage
- Record the call key's epoch and how it is kept current
- Pin the one re-read on a rotated channel key
- First Release Done
- Refactor Docker Compose Configuration
- Update android development tracking for active chat notification suppression
- Add implementation plan for android active chat notification suppression
- Add design spec for android active chat notification suppression
- Add new SVG icon with gradient backgrounds and headset details
- Implement code changes to enhance functionality and improve performance
- Launcher icon sourced from desktop SVG with gradient headset pads and #3730A2 background
- Launcher icon with #3730A2 background, 75% zoom mark, and monochrome layer
- Install BetweenUs adaptive launcher icon and render all density mipmaps
- Restore original clean template launcher icons in android res
- Record URL hyperlinking and rich link previews across Android, Web, and Desktop in TRACK.md
- Record permission carousel progression and notification banner in TRACK.md
- Record clean image preview and bu_date naming in TRACK.md
- Record push across the development documents, and untrack google-services.json
- Record Android permissions carousel in TRACK.md
- Update TRACK.md for TopBar toggle cleanup
- Remove duplicate right panel toggle from TopBar
- Update TRACK.md for default hidden member list
- Update TRACK.md for chat attachment preview and discard fix
- Record this pass, and name the key-publish trap
- Upload a few parts at a time rather than one
- Rename the app to BetweenUs
- A feature table that says which client each thing works on
- Invite management has a screen now, and deep links have a reason
- Configure ABI splits, resource filtering, and bundle splitting to reduce release APK size
- Update README with data path commands and pre-migration backup details
- Who the API believes, and what it still does not
- The follow latch, the media cache, and what to click
- The Bluetooth fix, the device pickers and the permission screen
- Keep the Android client out of the build context
- No signing config, and the launcher icon is ours
- Custom emoji, R8, and a README that says what this app now does
- R8 on, code and resources shrunk
- The authorization pass, and the two things it did not build
- Ten items closed, and the three that are only half closed
- The join and leave tones, and what to listen for
- What landed this pass, and what it did not close
- What landed this pass, and the migrations waiting behind it
- Track the accepted work in its own document
- Add initial Android project configuration files
- Correct post-SFU claims and open phase 27 for push notifications
- Replace tokei badge with working sloc.xyz live LOC calculator
- Update README with dynamic GitHub shields for LOC and repo metrics
- Add badge tags and shields to repository README
- Add Android client entries to architecture and request flow in README
- Update README with Android client and enhanced chat media documentation
- Update ANDROID_TODO with image/video viewer and storage album features
- Update ANDROID_TODO with WhatsApp-style media picker
- Record the Android local cache and where channel keys now live
- Add modules.xml for project configuration in Android module
- The share stage, and why a call outlives its screen
- Write down the slot contract, since breaking it is silent
- The epoch re-read, and how to test a re-key with two clients
- Split :core and :ui-common out of :app
- Add phased Android client roadmap
- Update README with home preview image and clarify P2P WebRTC mesh architecture
- Record phase 26 - the workbench
- Add new skills for UI library selection, prototyping, and animation review
- Record phase 25 - the call follows the account
- Improve negotiation logic and track handling for media streams
- What an operator has to do about media, which is now almost nothing
- Remove LiveKit, and the deployment settings that only existed for it
- An SFU and a Cloudflare Tunnel were never going to fit together
- The relay is what makes a call work over the tunnel
- How to tell a broken /livekit proxy from a broken SFU
- A loopback LIVEKIT_URL is the one that only works on the server
- Drop the join step logs and LiveKit's debug level
- What a blank web client was, and the two halves of the fix
- Mirrored networking alone does not open the WSL VM
- Check the LAN address answers before telling the SFU to advertise it
- The three ways a dev stack looks dead when it is only unstarted
- Why a call could not be joined in development, and what says so now
- Pin the invited member's first message
- The refresh grace window, and where the web client actually listens
- Describe the shared image build and what makes a rebuild slow again
- Build every image from one Dockerfile instead of nine
- Keep the desktop app and the worktrees out of the build context
- Cover the identity backup endpoints in the chat-service smoke run
- Describe identity backup, its threat-model cost, and how to port it
- Add .dockerignore
- Improve LiveKit key management and enhance server probing logic
- Update environment variable notes for clarity on DATABASE_URL and POSTGRES_PASSWORD alignment
- Update Nginx configuration to use dynamic upstream variables for improved service resolution
- Point the README at DEPLOYMENT.md and spell out which API URL a client uses
- Merge: deployment guide
- Merge: storage volume mapping for local uploads
- Write down how to actually deploy this
- Record the in-call device picker and the processor fix
- Record the microphone work
- Record the screen-share encoding work
- Record monitor selection and in-call control
- Record the remote-desktop and screen-share audio fixes
- Record phases 17 and 18
- Record phase 16, one address for a whole deployment
- Add a source-available, view-only licence
- Add the request flow, renderer to Prisma to Postgres and back
- Rewrite the README around the architecture
- Note what the history cache does not cover yet
- Pnpm dev:backend runs the services without the renderer
- Record phase 14 — notifications, the tray and auto-start
- Record phase 13 — media, attachments and profile pictures
- Cover uploads in the smoke script
- Cover phase 12 in the smoke scripts and dev:duo
- Rename workspace to server across the stack
- Plan phase 12 — servers, permissions and direct messages
- Record the admin panel, OAuth and notifications
- Move landed phase 10 work into Done
- Record phase 10 progress
- GitHub Actions pipeline with an integration job
- Presence smoke test, and make the chat smoke fail loudly
- Record voice/presence verification and the publish issue
- MVP quick start and honest verification status
- Add local Postgres/Redis compose, env template, development docs
- Init git
Features
- Phase 13 hardening - Keystore session, private CA, crash reports, CI
- The remote clipboard, both directions
- A direct call rings, full-screen, with the app dead
- A call ducks for a prompt and holds for a phone call
- The member menu - message, add friend, mute, copy id
- A colon menu, the server's own emoji in the picker, and animated ones
- Bold, italic, strike, code and quotes in a message body
- Back out of a call and it keeps going in a floating window
- A call takes the whole screen
Bug fixes
- Picture-in-picture refuses cleanly, and knows when it is on
- The screen share picker could not open
- A reply typed into the shade that cannot be sent is kept, not dropped
- Adding somebody to a server no longer means guessing a username
- The self-view that was always an empty box
- Let admin:create and seed run from the deployed image
Other changes
- Done with the enhancement
- The picker that would not open, and what picture-in-picture needs
- Phase 27's call half is answered by call.roster, and Android rings from it
- Record this pass in TRACK.md and ANDROID_TODO.md
- Reconcile TRACK.md and ANDROID_TODO.md with what the code actually has
- Record the call-screen fixes and what to try on a device
Features
- Publish the service images for arm64 as well as amd64
Bug fixes
- Repair action refs mangled by the arm64 patch script
Other changes
- Betweenus is also available on arm docs
Features
- Let a caller ask for a channel key that is not the cached one
Bug fixes
- Point
latest at every release, not only stable ones
- Re-read the channel key when somebody joins the call
- Stop the scheduled backup racing the pre-migration one
Other changes
- Apha release done
- Record the missing
latest tag and the image slimming
- Build the runtime from a production install, not the build stage
- Record the call key's epoch and how it is kept current
- Pin the one re-read on a rotated channel key
Features
- Release through a PR, and undo a release that fails halfway
- Marker-driven releases to Docker Hub, with the clients attached
- Implement adaptive stage grid scaling, uniform video cards, and floating control dock
- Redesign call screen with WhatsApp-style adaptive layout, PiP self-view, and camera flip
- Draw the four new pushes, and undraw a deleted message
- Push for deletes, friends, servers and calls
- Use PushGate.shouldSuppress in PushService
- Add PushGate.shouldSuppress active channel check with unit tests
- Make message URLs clickable hyperlinks and render rich OpenGraph previews
- Add URL unfurling service and metadata API endpoint
- Add WhatsApp-style permission flow and top notification warning banner
- Remove overlay on image cards and save media as bu_
{date}
- Add permissions carousel screen with progress and allow-all button
- FCM push, so a swiped-away phone is reachable
- Hide server people/members list by default
- Send files in the background, and shrink a video first
- Crop and rotate before a picture is sent or stored
- Set an avatar and a server icon from the phone
- Manage a machine's access and read its audit trail
- Add and remove a server's own emoji
- Make and edit a server's own roles
- Sign in with a provider, and open invite links
- Accept a mobile redirect, bound to a challenge the app keeps
- Upload large attachments in parts
- Invites as links, previewed before they are accepted
- Show what an invite leads to before it is accepted
- Convert every sent photo to JPEG, HEIC included
- Decode HEIC in the client, and send every photo as JPEG
- One data path, and a dump before every migration
- The headers a browser needs to be told once
- A server's own emoji, animated ones included
- Type ":" and a name to reach an emoji
- What you can do about a person, from the list that names them
- A link, so anybody can be let in without being added
- One screen at a time - a new share replaces the one before it
- A key per machine, so a lost one can be revoked
- Invite management, and a line that was lying about the slug
- Microphone processing, a hi-fi mode, and where the call comes out
- Reconnect when the network comes back, not when the timer says
- A reaction says who left it, not just how many
- A list of servers this client has been on, and a contract check
- Tell a LAN it is a LAN - a manual bitrate, frame rate and codec
- An unread line that survives a restart, and a way to reach it
- The same two notes when somebody joins or leaves a call
- Two notes when somebody joins the call, two when they leave
- A cache on desktop and web, so opening the app is not a spinner
- Look at a photo before sending it, and show a video's first frame
- Look at a photo before sending it, and drop files anywhere
- Scroll back through history on desktop and web
- Replies, on all three clients
- A monitor plugged in mid-session is noticed
- The roles screen learns to draw a server's own roles
- Two ways to be driven, two targets
- A chord that arrives as a chord
- Add Firebase Crashlytics configuration to appInsightsSettings
- A blob that leaves when its message does
- An attachment row per upload, so a blob has an owner
- Roles a server can invent for itself
- A session that survives its two halves landing on different replicas
- A record of what was done, and a way past the first hundred rows
- Edit who is on a private channel
- Measure the call, and say when nobody can hear you
- Push to talk
- Turn one person down, or off, without touching the others
- Invites that expire, run out and can be taken back
- Sweep what nothing was sweeping, and stop scanning for agent tokens
- Rotate a channel's key when somebody loses access to it
- A channel can be set to mentions only
- The roster comes from the service that holds the sockets
- Send presence only to the people entitled to it
- Go idle on its own after ten minutes, and come back
- Rate limit login per account as well as per address
- Add emoji picker and quick camera button in composer, auto-hiding camera when keyboard is open
- Display You in accent color for current user in chat view, pinned and search panels
- Enhance chat screen with media viewer, video player and gallery storage
- Add storage write permissions and video/audio attachment support
- Implement WhatsApp-style media picker and attachment sheet
- Add media and camera permissions and FileProvider setup
- Keep channel keys, so cached history opens without the network
- Open on what the app already knows, not on a spinner
- Spend the bitrate, send the whole screen
- Tell the gateway where a phone can reach it
- Come back to where you were, and go where a tap says
- Lay the share stage out like a meeting client
- A share takes the whole screen, the way it has to
- A call that looks like a call to the system
- Drop the browser context menu
- A gateway for clients that cannot use a Vite proxy
- Voice, video, screen share and the remote-desktop viewer
- Servers, channels, messages, members, settings
- The stores, and the widgets every screen is built from
- The whole REST surface, and end-to-end encryption
- Sign in, switch servers, and land on home
- Nexora palette, and a server address the build does not decide
- Initialize Android project structure with basic configurations and resources
- Implement Picture-in-Picture (PiP) overlay for voice calls
- Add Teams-style floating Picture-in-Picture mode and fix screen occlusion
- One entrance for everything that opens on top
- Carry the workbench into the surfaces inside the panels
- Rebuild the client as a workbench of floating panels
- Enhance screen capturing on Windows with background throttling adjustments
- Add initial configuration for build and typecheck tasks
- One call per account, whichever device joins last
- Warn before a browser tab with a live call is closed
- Keep the call running while the client navigates away
- Add BM25 search engine for UI/UX style guides with design system generation and persistence options
- Add Hide/Show camera controls to expand stream content to full width
- Add Teams and Google Meet style Side Gallery camera layout alongside screen share
- Add auto-hiding controls, participant toggle, and polished glassmorphic UI for fullscreen mode
- The screen goes straight to the controller, not through a room
- A mesh of peer connections, where the SFU used to be
- A switchboard, so two clients can find each other without an SFU
- Relay media through TURN, so a call works from another network
- A render that throws is a message, not a blank window
- Implement LAN SFU and ICE candidate rewriting for remote access
- Reach the dev stack from a second machine on the network
- Notifications and provider sign-in in a browser
- Serve the web client at the root of the gateway
- Add the browser client as its own app
- Gate the remote-desktop section on the Electron bridge
- Restore the account encryption key on any machine you sign in on
- Store a sealed identity backup so an account is not tied to one machine
- Update TypeScript configuration and add path mappings for shared packages
- Check at startup that LiveKit accepts our tokens
- Give a new server a voice channel as well as #general
- Add packaging scripts for portable and NSIS targets in desktop app
- Enhance deployment instructions and add production scripts for easier setup
- Change microphone and speakers from inside the call
- Give Voice & Video something to set
- Let a deployment choose where local uploads live
- Publish the microphone the way this machine is set up
- Close the microphone when nobody is talking
- Decide what a microphone should sound like
- Encode a screen share like something worth watching
- Give control of a screen share in a call, with named cursors
- Choose which monitor a session watches
- Request control from somebody's screen share
- Public ingress that fits a tunnel you already run
- Be a remote machine, and reach one
- Enrolment, grants, sessions and the relay
- Remote machines, grants, sessions and an audit trail
- Proxy LiveKit signalling, so a deployment is one hostname
- Choose the server from the login screen
- One address for a whole deployment, resolved at runtime
- Message actions - tombstones, edits, pins, reactions, search
- Implement message deletion and friend event notifications
- Add high-res icon rendering and portable production build target
- Set taskbar, electron window, system tray, and installer application icon
- Integrate brand icon from icon.svg with dark gradient styling across desktop app
- Honour mutes, quiet hours and Do Not Disturb
- System tray, close to tray, and start with the system
- Notification-service owns mutes, quiet hours and read state
- Play video and audio inline, and cap image previews
- Upload avatars and server icons
- Attach, preview and download files in the message view
- Encrypted attachments, compressed and uploaded in parts
- Attachment manifest and settable profile pictures
- Multipart uploads and a picture/attachment split
- Drop the default Electron menu bar
- Rebuild the client as a Discord-shaped app
- Choosable status, with invisible resolved server-side
- Friends, user search and direct messages
- Private channels with a member allowlist
- Per-member permission overrides and one access resolver
- Web admin panel for users and sign-in providers
- Sign in with Google or GitHub
- Admin API, account management and OAuth sign-in
- Admin role, OAuth provider config, and
pnpm admin:create
- Notifications for messages and voice joins
- Request-scoped logging with a correlated request id
- Refresh-token reuse detection and service-level rate limits
- Screen-share picker, theatre layout and paged grid
- Voice channel screen with participant tiles
- Voice channels, online status and typing indicators
- Encrypted messages, LiveKit calls, two-window dev harness
- Enhance development configuration for API and WebSocket URLs
- Local-disk uploads when S3 is not configured
- Electron shell and Discord-style chat client
- Nginx gateway routing and full-stack compose
- Message REST API and /ws/chat realtime gateway
- Workspaces, membership and channels
- Registration, login, refresh rotation and /me
- Shared types, config, logger, auth, permissions, events, database
Bug fixes
- Download the two artifacts by name, and promote after publishing
- Mark gradlew executable in the index
- Decode a keystore secret in every shape it actually arrives in
- A merged release PR builds again
- Detect the release commit by the version moving, not by files changing
- Follow the compose split, and give prod:up something to pull
- Make the integration smokes match the services they test
- Restore the workspace links that typecheck resolves through
- Remove image file size from preview overlay header
- Remove duplicate avatar icon from account settings picture picker
- Keep the call's peer id in step with its socket
- Adjust launcher icon scale to 54% safe-zone to prevent circle mask clipping
- Update Firebase Crashlytics connection settings with actual values
- A second machine reads the history, not a wall of padlocks
- Fix drop image preview loading and discard upload handling
- Derive the OAuth redirect allow list, and take a username to sign in
- The key, the roster and the sign-in prompt
- Give every video tile the shape of the picture in it
- Re-anchor the message list when the keyboard opens
- Ensure backup directory permissions and add diagnostic write check
- An origin is not a string that starts the same way
- The endpoints behind a token still get a budget
- A session is not an entitlement to every attachment
- A socket frame is as big as the traffic, not as big as ws allows
- A token does not get to say how it is checked
- A caller does not get to choose which bucket counts them
- A picture sent from a phone says how big it is
- A growing row is not somebody scrolling away
- A picture that has been decrypted stays decrypted
- Scrolling away is something only the reader does
- A paired Bluetooth headset is found again
- The list stopped stuttering when pictures arrive
- A moderator cannot edit or kick an administrator
- An attachment is not served to a stranger
- Managing members is not permission to conscript the directory
- A capture bound to a device does not follow the one you plug in
- Open a channel at its newest message, not wherever the last one sat
- The server picker's recreate() was talking to nobody
- A still screen is not a share that ended
- Remove redundant YOU badge in message rows
- Hanging up now ends the call notification
- Watching a share no longer bounces back to the grid
- Mute the microphone, not just the track carrying it
- Say who is in a voice channel, and notice when it changes
- Do not start a projection before the service can carry one
- Stop asking the sender for 720p30
- A share that is not moving has not ended
- Be seen in the call, and give up on one that never answers
- Rejoin the call when the socket comes back
- Leaving a call goes back to the conversation, not into one
- Show a share at the shape and the resolution it is sent at
- Rotating during a share no longer loops until it crashes
- Write a message body the way the other clients read one
- Returning to a call from its notification no longer ends it
- Send a call to the speaker, not to silence
- The four transceiver slots a call is actually made of
- Start the dev gateway as part of pnpm dev
- Show a server the moment this account is added to it
- Re-read the key directory when a message arrives at an unknown epoch
- A failed call can be joined again
- Say which address could not be reached
- Fix server icon size and active background outline in server rail
- One Nexora mark, and a rail tile that says where it goes
- Keep the user strip at the bottom of the sidebar
- Put each layout toggle on the side it controls
- Only offer the right-panel toggle where there is a right panel
- Use the WGC feature name this Chromium actually knows
- Update codec type from RTCRtpCodecCapability to RTCRtpCodec
- Keep camera feeds permanently visible in fullscreen mode and only auto-hide controls
- Fix muted speaking flicker, add fullscreen theatre mode, and gate stream audio to viewers
- Maximize P2P screen sharing quality with High Profile H.264, SDP bandwidth signaling, and BWE fast-start
- Preserve native video quality
- Raise 60 fps bitrate ceiling
- Sync remote media state
- ICE candidates were being dropped, so no call ever connected
- The deployed SFU advertised its bridge address, so media never arrived
- /livekit reached LiveKit's root, so the WebSocket never upgraded
- Refuse to hand a client an SFU address only the server can reach
- A browser tab does not ask for a machine list it will never show
- A 200 that is not JSON is a failure, not null data
- The relay could not have 7881, so the candidate does not ask for it
- Address the containers by IPv4, not by "localhost"
- Serve the LAN dev app over TLS, or it has no crypto at all
- A stopped share should leave everyone else's stage, and let the browser own the audio question
- Give turbo enough slots for every persistent task
- Advertise an SFU address the host can actually reach
- Let the service write the volume its uploads go to
- Point the doctor at the compose file that is running the SFU
- Find the SFU from the host, not only from inside Docker
- Let a member who joined after the key was minted key itself
- Keep the package CommonJS; share the theme through a .mjs
- Stop a signed-in session dying on a backend that is not up yet
- Add type module and resolve electron binary installation
- Stop the dev SFU starting with a placeholder LiveKit secret
- Drop the workspace path mappings from tsconfig.base.json
- Let any member key an empty channel
- Stop sending requests without a bearer token
- Default LIVEKIT_URL to the gateway path in every mode
- Allow empty CLOUDFLARE_TUNNEL_TOKEN for compatibility with local setups
- Attach the gate after the track, not with it
- Bind the spliced gate source to a name instead of renaming it
- A shared screen no longer echoes the call back into it
- The pointer no longer disappears when control is taken
- The click lands where the pointer is, at the display size
- Control now reaches the machine, and add request-control
- Development ignores VITE_API_URL
- Announce a permission change to the member it is about
- Clear the unread line on its own, kill the last blue outline
- Clear an unread badge on focus, and mark where reading stopped
- Set AppUserModelID and explicit window.setIcon for Windows taskbar icon
- Replace thin rotated stroke path with solid bold CallEnd disconnect handset icon
- Fix disconnect button icon orientation and layout
- Notify only when the channel is not on screen, and cache history
- Migrations and OpenSSL in the container stack
- Upgrade SFU to v1.13.5 so track publishing negotiates
- Remove container loopback node_ip to fix WebRTC UDP media publishing in Docker
- Allow electron audio permissions, fix livekit docker UDP ports and voice channel retry
- Resolve dev-duo port conflict, voice connecting state & control buttons
- Improve logging for debugging and handle room disposal on hot reload
- Leave the roster on every disconnect, not just the button
- Allow the LiveKit origin through the renderer CSP
- Stop a third Electron window during pnpm dev:duo
Other changes
- First Release Done
- Refactor Docker Compose Configuration
- Update android development tracking for active chat notification suppression
- Add implementation plan for android active chat notification suppression
- Add design spec for android active chat notification suppression
- Add new SVG icon with gradient backgrounds and headset details
- Implement code changes to enhance functionality and improve performance
- Launcher icon sourced from desktop SVG with gradient headset pads and #3730A2 background
- Launcher icon with #3730A2 background, 75% zoom mark, and monochrome layer
- Install BetweenUs adaptive launcher icon and render all density mipmaps
- Restore original clean template launcher icons in android res
- Record URL hyperlinking and rich link previews across Android, Web, and Desktop in TRACK.md
- Record permission carousel progression and notification banner in TRACK.md
- Record clean image preview and bu_date naming in TRACK.md
- Record push across the development documents, and untrack google-services.json
- Record Android permissions carousel in TRACK.md
- Update TRACK.md for TopBar toggle cleanup
- Remove duplicate right panel toggle from TopBar
- Update TRACK.md for default hidden member list
- Update TRACK.md for chat attachment preview and discard fix
- Record this pass, and name the key-publish trap
- Upload a few parts at a time rather than one
- Rename the app to BetweenUs
- A feature table that says which client each thing works on
- Invite management has a screen now, and deep links have a reason
- Configure ABI splits, resource filtering, and bundle splitting to reduce release APK size
- Update README with data path commands and pre-migration backup details
- Who the API believes, and what it still does not
- The follow latch, the media cache, and what to click
- The Bluetooth fix, the device pickers and the permission screen
- Keep the Android client out of the build context
- No signing config, and the launcher icon is ours
- Custom emoji, R8, and a README that says what this app now does
- R8 on, code and resources shrunk
- The authorization pass, and the two things it did not build
- Ten items closed, and the three that are only half closed
- The join and leave tones, and what to listen for
- What landed this pass, and what it did not close
- What landed this pass, and the migrations waiting behind it
- Track the accepted work in its own document
- Add initial Android project configuration files
- Correct post-SFU claims and open phase 27 for push notifications
- Replace tokei badge with working sloc.xyz live LOC calculator
- Update README with dynamic GitHub shields for LOC and repo metrics
- Add badge tags and shields to repository README
- Add Android client entries to architecture and request flow in README
- Update README with Android client and enhanced chat media documentation
- Update ANDROID_TODO with image/video viewer and storage album features
- Update ANDROID_TODO with WhatsApp-style media picker
- Record the Android local cache and where channel keys now live
- Add modules.xml for project configuration in Android module
- The share stage, and why a call outlives its screen
- Write down the slot contract, since breaking it is silent
- The epoch re-read, and how to test a re-key with two clients
- Split :core and :ui-common out of :app
- Add phased Android client roadmap
- Update README with home preview image and clarify P2P WebRTC mesh architecture
- Record phase 26 - the workbench
- Add new skills for UI library selection, prototyping, and animation review
- Record phase 25 - the call follows the account
- Improve negotiation logic and track handling for media streams
- What an operator has to do about media, which is now almost nothing
- Remove LiveKit, and the deployment settings that only existed for it
- An SFU and a Cloudflare Tunnel were never going to fit together
- The relay is what makes a call work over the tunnel
- How to tell a broken /livekit proxy from a broken SFU
- A loopback LIVEKIT_URL is the one that only works on the server
- Drop the join step logs and LiveKit's debug level
- What a blank web client was, and the two halves of the fix
- Mirrored networking alone does not open the WSL VM
- Check the LAN address answers before telling the SFU to advertise it
- The three ways a dev stack looks dead when it is only unstarted
- Why a call could not be joined in development, and what says so now
- Pin the invited member's first message
- The refresh grace window, and where the web client actually listens
- Describe the shared image build and what makes a rebuild slow again
- Build every image from one Dockerfile instead of nine
- Keep the desktop app and the worktrees out of the build context
- Cover the identity backup endpoints in the chat-service smoke run
- Describe identity backup, its threat-model cost, and how to port it
- Add .dockerignore
- Improve LiveKit key management and enhance server probing logic
- Update environment variable notes for clarity on DATABASE_URL and POSTGRES_PASSWORD alignment
- Update Nginx configuration to use dynamic upstream variables for improved service resolution
- Point the README at DEPLOYMENT.md and spell out which API URL a client uses
- Merge: deployment guide
- Merge: storage volume mapping for local uploads
- Write down how to actually deploy this
- Record the in-call device picker and the processor fix
- Record the microphone work
- Record the screen-share encoding work
- Record monitor selection and in-call control
- Record the remote-desktop and screen-share audio fixes
- Record phases 17 and 18
- Record phase 16, one address for a whole deployment
- Add a source-available, view-only licence
- Add the request flow, renderer to Prisma to Postgres and back
- Rewrite the README around the architecture
- Note what the history cache does not cover yet
- Pnpm dev:backend runs the services without the renderer
- Record phase 14 — notifications, the tray and auto-start
- Record phase 13 — media, attachments and profile pictures
- Cover uploads in the smoke script
- Cover phase 12 in the smoke scripts and dev:duo
- Rename workspace to server across the stack
- Plan phase 12 — servers, permissions and direct messages
- Record the admin panel, OAuth and notifications
- Move landed phase 10 work into Done
- Record phase 10 progress
- GitHub Actions pipeline with an integration job
- Presence smoke test, and make the chat smoke fail loudly
- Record voice/presence verification and the publish issue
- MVP quick start and honest verification status
- Add local Postgres/Redis compose, env template, development docs
- Init git