XMPP client written in JavaScript that works both in browser and as native app using Tauri.rs
  • TypeScript 73.4%
  • Rust 9.4%
  • Kotlin 6.7%
  • Python 5.8%
  • JavaScript 2%
  • Other 2.6%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Paavel A. 890608ff44
0.8.0-rc4, on libtacky v1.2.0-rc3 (28ab9df0), pairing with tackygram 0.4.0-rc3: 0.8.0-rc3 with typing that says paused as the device locks, so a Telegram contact no longer sees typing for minutes (fix/typing-lock), no network mark on a gateway contact's picture until the gateway's network is known (fix/network-badge-unknown), libtacky pinned to v1.2.0-rc3 with the generated API regenerated, and "Ignore for 7 days" passing the sha256 of the certificate shown so the exception binds to it; made the fourth release candidate: version 0.8.0-rc4 in the UI package and its lock, tauri.conf.json, Cargo.toml and Cargo.lock and the README's version line, Android versionCode 8008; a compact 0.8.0-rc4 CHANGELOG entry (Chats, Chat list, Settings, From libtacky 1.2.0-rc3) in place of the Unreleased bullets; the metainfo's development release 0.8.0~rc4 (appstreamcli validate --no-net passes). docs/macos.md stays at the last Mac release. README's tables measured again on this tree: 110,997 lines of code and 115,521 of tests (the change since 0.8.0-rc3 counted by the same rules), the UI's 66,317 of 67,834 lines (97.8%, 90.8% of branches), the shell's 12,441 of 13,135 source lines (94.7%), the Kotlin's 4,449 of 4,705 (94.6%), the worker's 872 of 872. Gates on d6fd0423: make check STRICT=1 clean (2,401 strings in all five catalogues, six obsolete); make test-ui 5,086 passed, 8 skipped (432 files); make test-shell 442 in 55 modules; make test-worker green; make release-check passed (no advisory, again on this commit); the Android JVM tests free 628 and gms 631 passed; make coverage-shell-all green; the WebKit smoke 927 screens, 9,566 checks, 0 failed with SMOKE_JOBS=16; cargo check of the shell for x86_64-pc-windows-gnu clean.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-11-05 21:12:23 +02:00
docker Perf: make bench-typing, and the BENCH_* knobs carried into the container 2026-11-05 02:10:45 +02:00
docs #79: an Android call's sound goes to a connected Bluetooth headset 2026-11-04 19:28:36 +02:00
flatpak 0.8.0-rc4, on libtacky v1.2.0-rc3 (28ab9df0), pairing with tackygram 0.4.0-rc3: 0.8.0-rc3 with typing that says paused as the device locks, so a Telegram contact no longer sees typing for minutes (fix/typing-lock), no network mark on a gateway contact's picture until the gateway's network is known (fix/network-badge-unknown), libtacky pinned to v1.2.0-rc3 with the generated API regenerated, and "Ignore for 7 days" passing the sha256 of the certificate shown so the exception binds to it; made the fourth release candidate: version 0.8.0-rc4 in the UI package and its lock, tauri.conf.json, Cargo.toml and Cargo.lock and the README's version line, Android versionCode 8008; a compact 0.8.0-rc4 CHANGELOG entry (Chats, Chat list, Settings, From libtacky 1.2.0-rc3) in place of the Unreleased bullets; the metainfo's development release 0.8.0~rc4 (appstreamcli validate --no-net passes). docs/macos.md stays at the last Mac release. README's tables measured again on this tree: 110,997 lines of code and 115,521 of tests (the change since 0.8.0-rc3 counted by the same rules), the UI's 66,317 of 67,834 lines (97.8%, 90.8% of branches), the shell's 12,441 of 13,135 source lines (94.7%), the Kotlin's 4,449 of 4,705 (94.6%), the worker's 872 of 872. Gates on d6fd0423: make check STRICT=1 clean (2,401 strings in all five catalogues, six obsolete); make test-ui 5,086 passed, 8 skipped (432 files); make test-shell 442 in 55 modules; make test-worker green; make release-check passed (no advisory, again on this commit); the Android JVM tests free 628 and gms 631 passed; make coverage-shell-all green; the WebKit smoke 927 screens, 9,566 checks, 0 failed with SMOKE_JOBS=16; cargo check of the shell for x86_64-pc-windows-gnu clean. 2026-11-05 21:12:23 +02:00
libtacky@28ab9df067 libtacky to v1.2.0-rc3 (28ab9df0) for 0.8.0-rc4, and ui/src/protocol/generated/api.ts regenerated from it with tools/api/api.py gen --ts in the container: CertificateTrust gains ignore_sha256, the one certificate an "ignore for seven days" exception accepts; account and setting ignore_certificate_errors take an optional sha256, the fingerprint of the <CertificateUntrusted> being answered; the event's changed and previous_sha256 now cover a live exception as they cover a pin; the installation settings' text names calls_from_strangers. 1.2.0-rc3 is 1.2.0-rc2 with the catch-up's peek-then-walk (the newest page first, then the walk in order, sealed OMEMO placeholders opened in place), calls_from_strangers, the call tier's read sync, the certificate exception bound to the certificate shown, disappearing-message timers inside OMEMO 2 and no link-preview fetch for a send that cannot carry it. 2026-11-05 20:42:59 +02:00
src-tauri 0.8.0-rc4, on libtacky v1.2.0-rc3 (28ab9df0), pairing with tackygram 0.4.0-rc3: 0.8.0-rc3 with typing that says paused as the device locks, so a Telegram contact no longer sees typing for minutes (fix/typing-lock), no network mark on a gateway contact's picture until the gateway's network is known (fix/network-badge-unknown), libtacky pinned to v1.2.0-rc3 with the generated API regenerated, and "Ignore for 7 days" passing the sha256 of the certificate shown so the exception binds to it; made the fourth release candidate: version 0.8.0-rc4 in the UI package and its lock, tauri.conf.json, Cargo.toml and Cargo.lock and the README's version line, Android versionCode 8008; a compact 0.8.0-rc4 CHANGELOG entry (Chats, Chat list, Settings, From libtacky 1.2.0-rc3) in place of the Unreleased bullets; the metainfo's development release 0.8.0~rc4 (appstreamcli validate --no-net passes). docs/macos.md stays at the last Mac release. README's tables measured again on this tree: 110,997 lines of code and 115,521 of tests (the change since 0.8.0-rc3 counted by the same rules), the UI's 66,317 of 67,834 lines (97.8%, 90.8% of branches), the shell's 12,441 of 13,135 source lines (94.7%), the Kotlin's 4,449 of 4,705 (94.6%), the worker's 872 of 872. Gates on d6fd0423: make check STRICT=1 clean (2,401 strings in all five catalogues, six obsolete); make test-ui 5,086 passed, 8 skipped (432 files); make test-shell 442 in 55 modules; make test-worker green; make release-check passed (no advisory, again on this commit); the Android JVM tests free 628 and gms 631 passed; make coverage-shell-all green; the WebKit smoke 927 screens, 9,566 checks, 0 failed with SMOKE_JOBS=16; cargo check of the shell for x86_64-pc-windows-gnu clean. 2026-11-05 21:12:23 +02:00
tools Merge branch 'fix/typing-cpu' into develop 2026-11-05 03:09:58 +02:00
ui 0.8.0-rc4, on libtacky v1.2.0-rc3 (28ab9df0), pairing with tackygram 0.4.0-rc3: 0.8.0-rc3 with typing that says paused as the device locks, so a Telegram contact no longer sees typing for minutes (fix/typing-lock), no network mark on a gateway contact's picture until the gateway's network is known (fix/network-badge-unknown), libtacky pinned to v1.2.0-rc3 with the generated API regenerated, and "Ignore for 7 days" passing the sha256 of the certificate shown so the exception binds to it; made the fourth release candidate: version 0.8.0-rc4 in the UI package and its lock, tauri.conf.json, Cargo.toml and Cargo.lock and the README's version line, Android versionCode 8008; a compact 0.8.0-rc4 CHANGELOG entry (Chats, Chat list, Settings, From libtacky 1.2.0-rc3) in place of the Unreleased bullets; the metainfo's development release 0.8.0~rc4 (appstreamcli validate --no-net passes). docs/macos.md stays at the last Mac release. README's tables measured again on this tree: 110,997 lines of code and 115,521 of tests (the change since 0.8.0-rc3 counted by the same rules), the UI's 66,317 of 67,834 lines (97.8%, 90.8% of branches), the shell's 12,441 of 13,135 source lines (94.7%), the Kotlin's 4,449 of 4,705 (94.6%), the worker's 872 of 872. Gates on d6fd0423: make check STRICT=1 clean (2,401 strings in all five catalogues, six obsolete); make test-ui 5,086 passed, 8 skipped (432 files); make test-shell 442 in 55 modules; make test-worker green; make release-check passed (no advisory, again on this commit); the Android JVM tests free 628 and gms 631 passed; make coverage-shell-all green; the WebKit smoke 927 screens, 9,566 checks, 0 failed with SMOKE_JOBS=16; cargo check of the shell for x86_64-pc-windows-gnu clean. 2026-11-05 21:12:23 +02:00
worker The web image builds the browser backend with emsdk's Emscripten 6.0.13 (LLVM, binaryen 133) in place of Debian's 3.1.69, and one Rust, 1.99.1 with the wasm32-unknown-emscripten std, builds the native parts and the wasm worker alike, where it was 1.90.0 beside a 1.85.1 kept for the worker alone: Debian's binaryen 120 and its frozen cache were what held the worker's Rust at 1.85, and libtacky's 1.2 line (lane L10, 2026-11-02) proved the pair in a probe image. emsdk is pinned by its release tag and checked against the commit that tag names, its cache carries the prebuilt sysroot and the zlib port Tcl links, so no run fetches or compiles a library, and Debian's emscripten package (and with it clang-19, lld-19, llvm-19 and binaryen, which nothing else here used) is gone; the image is 4.65 GB where it was 5.27 GB. The worker needed three small fixes for the newer Emscripten: opfsfs.js throws new FS.ErrnoError(ENOENT) from lookup, as FS.genericErrors is gone; the link exports MEMFS, which test/store.mjs now mounts by that name since FS.filesystems is gone too; and the store suite calls the stream's allocate, FS.allocate having been removed. The Android image, derived from this one, takes its Android targets onto the same 1.99.1; its comments say so. docs/building.md names the toolchain, the worker's toolchain hint points at emsdk, and the changelog says what changed. 2026-11-02 02:44:40 +02:00
.gitignore The UI build's source maps are moved out of its output into <outDir>.maps (ui/dist.maps, dist/web.maps), so the shells stop carrying them: Tauri's codegen embeds every file under frontendDist in the binary (tauri-codegen 2.7.4 embedded_assets.rs walks the whole directory, brotli quality 9), and the hidden maps were 1,733 KiB of the 2,885 KiB of UI each apk, AppImage, Flatpak and Windows exe embedded, 60 % of it, that nothing reads, while dist/web served 7.6 MB of them to anyone who asked. Measured with the new tools/perf/bundle-size.mjs (every chunk raw, gzip -9 and brotli -11, each window's start-up set, the embedded total as Tauri compresses it, and the main window's bytes by source file from the maps): embedded 2,885.3 -> 1,152.3 KiB, 59 -> 43 files; the chunks are byte-identical. A stack trace is still read against the copy beside the build; the mock build keeps its maps in place, as it is never shipped and tools/bench-catchup-webkit.py reads them there. tools/perf/startup-webkit.py times the main window's start in WebKitGTK (fresh web process per run: entry chunk, module graph defined, first chat-list row, main-thread busy time), for the code-splitting that follows. Part of the performance pass the user asked for on 2026-11-02 ("please all the attention on optimization and speed"). 2026-11-02 06:43:57 +02:00
.gitmodules The build follows libtacky v1.0.0-alpha7's layout, built and tested against the release candidate d0d79d4c (a standalone clone, ANOTHER_IM_TACKY), with the submodule pin left at v1.0.0-alpha4 until the tag exists: native/ is gone, so tacky-checkout no longer fetches libomemo-c (OMEMO is the Rust tacky-omemo and the backend needs none of its submodules here), BACKEND_VARS and the Flatpak manifest's make line name TACKY_MEDIA_BUILD and TACKY_MEDIA_DL instead of the OMEMO, libomemo-c and media trees, DEV_WATCH watches tacky/, ext/, tacky-core and tacky-omemo, and tools/flatpak-sources.py vendors the crates of the three Cargo.lock files make lib builds from, there being no workspace lockfile any more. The webrtc media backend is tacky-media/webrtc's libtackymedia_webrtc, a C library with no Tcl in it: webrtc.mk builds it from there without a Tcl prefix and make webrtc no longer waits for libtacky, the Android and Windows goals build it through tacky-media's own webrtc-android and win-webrtc (platforms/webrtc.mk is gone) and macOS through libtacky's webrtc-macos, and the file is libtackymedia_webrtc.{so,dll,dylib} everywhere the shell and the packaging name it (app.rs's WEBRTC_LIB, the AppImage, the Flatpak, the apk's jniLib and MainActivity's loadLibrary, the Windows installer and its smoke run). The browser worker links the new wasm archives (libtacky_omemo.a and libtacky_crypto.a in place of libomemo-c.a and libcrypto.a), calls Tackycore_Init, Tackyomemo_Init and Tackycrypto_Init beside Sqlite3_Init as embed/extensions.h lists them (Tackykeyring, Tackyxml and Tclcrypto are gone), dispatches to ::tacky::core::wire::dispatch, stops with ::tacky::backend destroy and releases acks with ::tacky::xmpp::session::durable_all; its boot and omemo suites use the renamed packages (tacky::core::storage's tacky_store, the typed tacky::core::keyring 0.2, tacky::omemo's ratchet commands, tacky::crypto, tacky::http) and bench-store's seed the renamed wire and store, though its OMEMO rows still use the removed high-level ratchet API. The connection suite is not ported: its fake peer was tacky-xmpp's FakePeer, which libtacky deleted with the crate, and the Tcl peer that replaced it needs tdom, which this image lacks. Checked in the image: make bundle-appimage (dist/another-im-tauri-0.3.6-x86_64.AppImage, 138,668,536 bytes, carrying libtackymedia_webrtc.so), make check clean, test-ui 130 files 1,644 passed, test-shell 17 binaries 93 passed, test-embed 74 and 6 passed against the built archive, the worker's spike 8, boot 35, omemo 3, host 18, store 64 and page 40 checks passed with test-connect failing on the missing crate, and make (dist/web) built. 2026-10-07 22:31:18 +03:00
audit.toml make audit passes, and leaves make check for a new make release-check (the user, 2026-10-27: everyday coding needs no network and is not blocked by a new advisory). src-tauri/Cargo.lock takes ctutils 0.4.4 (RUSTSEC-2026-0385), time 0.3.47 (-0009), tokio 1.53.3 (-0386, unsound) and plist 1.10.0, which brings quick-xml 0.41.0 (-0194, -0195), each a cargo update --precise in the image (time and plist need Rust 1.88, ctutils 1.87; every lane builds with 1.90, the Flatpak with the 25.08 SDK's rust-stable), and flatpak/cargo-sources.json is written again from it. crypto-bigint 0.5.5's RUSTSEC-2026-0387 goes into audit.toml: it comes in through p256 0.13 and elliptic-curve 0.13, and web-push-native 0.5, the latest, pins p256 ^0.13. p256 0.13 takes from it only the scalar's U256 add_mod, sub_mod, sbb, ct_lt and conditional_select, its multiplications being its own code. 0.5.5's sbb is the older WideWord form, before the branch #1029 brought into the 0.7 line, and the Montgomery multiplication, division, UintRef and BoxedMontyForm::invert fixed in 0.7.6 are never reached. The entry says this has not been BINSEC-verified and names p256 0.14 as the follow-up. make check is now tsc and i18n-check alone. make release-check runs check-pins and the audit, online, and docs/building.md's target table and README's Build section say it comes before every release. In the container: make audit clean (warnings only: the unmaintained gtk-rs/unic/zvariant set, glib's unsound advisory and a yanked yoke-derive, as before); make check STRICT=1 passed; test-shell passed; test-ui ran 4,048 of 4,049 under load, and the one failure, contact-info's this-device row, passed 49 of 49 alone (no UI code changed); cargo build --features desktop,fake-tacky --bin anotherim built. The libtacky pin stays where it is (libtacky fe96faeb is its own lock files and audit.toml). 2026-10-27 12:25:48 +02:00
CHANGELOG.md 0.8.0-rc4, on libtacky v1.2.0-rc3 (28ab9df0), pairing with tackygram 0.4.0-rc3: 0.8.0-rc3 with typing that says paused as the device locks, so a Telegram contact no longer sees typing for minutes (fix/typing-lock), no network mark on a gateway contact's picture until the gateway's network is known (fix/network-badge-unknown), libtacky pinned to v1.2.0-rc3 with the generated API regenerated, and "Ignore for 7 days" passing the sha256 of the certificate shown so the exception binds to it; made the fourth release candidate: version 0.8.0-rc4 in the UI package and its lock, tauri.conf.json, Cargo.toml and Cargo.lock and the README's version line, Android versionCode 8008; a compact 0.8.0-rc4 CHANGELOG entry (Chats, Chat list, Settings, From libtacky 1.2.0-rc3) in place of the Unreleased bullets; the metainfo's development release 0.8.0~rc4 (appstreamcli validate --no-net passes). docs/macos.md stays at the last Mac release. README's tables measured again on this tree: 110,997 lines of code and 115,521 of tests (the change since 0.8.0-rc3 counted by the same rules), the UI's 66,317 of 67,834 lines (97.8%, 90.8% of branches), the shell's 12,441 of 13,135 source lines (94.7%), the Kotlin's 4,449 of 4,705 (94.6%), the worker's 872 of 872. Gates on d6fd0423: make check STRICT=1 clean (2,401 strings in all five catalogues, six obsolete); make test-ui 5,086 passed, 8 skipped (432 files); make test-shell 442 in 55 modules; make test-worker green; make release-check passed (no advisory, again on this commit); the Android JVM tests free 628 and gms 631 passed; make coverage-shell-all green; the WebKit smoke 927 screens, 9,566 checks, 0 failed with SMOKE_JOBS=16; cargo check of the shell for x86_64-pc-windows-gnu clean. 2026-11-05 21:12:23 +02:00
LICENSE anotherim-web is MPL-2.0 (the user, 2026-09-29: "License is GPL-3.0 for libtacky and MPL 2.0 for anotherim-web and anotherim-swift"): LICENSE is the Mozilla Public License 2.0 text instead of the GPL-3.0's, ui/package.json and its lockfile's root entry and src-tauri/Cargo.toml say MPL-2.0, and the README gains a licence section that says so and that a build linking the GPL-3.0 libtacky (the worker, the Tauri shells) is conveyed under the GPL-3.0 as a whole, which MPL-2.0 permits 2026-09-29 22:56:13 +03:00
Makefile Perf: make bench-typing, and the BENCH_* knobs carried into the container 2026-11-05 02:10:45 +02:00
README.md 0.8.0-rc4, on libtacky v1.2.0-rc3 (28ab9df0), pairing with tackygram 0.4.0-rc3: 0.8.0-rc3 with typing that says paused as the device locks, so a Telegram contact no longer sees typing for minutes (fix/typing-lock), no network mark on a gateway contact's picture until the gateway's network is known (fix/network-badge-unknown), libtacky pinned to v1.2.0-rc3 with the generated API regenerated, and "Ignore for 7 days" passing the sha256 of the certificate shown so the exception binds to it; made the fourth release candidate: version 0.8.0-rc4 in the UI package and its lock, tauri.conf.json, Cargo.toml and Cargo.lock and the README's version line, Android versionCode 8008; a compact 0.8.0-rc4 CHANGELOG entry (Chats, Chat list, Settings, From libtacky 1.2.0-rc3) in place of the Unreleased bullets; the metainfo's development release 0.8.0~rc4 (appstreamcli validate --no-net passes). docs/macos.md stays at the last Mac release. README's tables measured again on this tree: 110,997 lines of code and 115,521 of tests (the change since 0.8.0-rc3 counted by the same rules), the UI's 66,317 of 67,834 lines (97.8%, 90.8% of branches), the shell's 12,441 of 13,135 source lines (94.7%), the Kotlin's 4,449 of 4,705 (94.6%), the worker's 872 of 872. Gates on d6fd0423: make check STRICT=1 clean (2,401 strings in all five catalogues, six obsolete); make test-ui 5,086 passed, 8 skipped (432 files); make test-shell 442 in 55 modules; make test-worker green; make release-check passed (no advisory, again on this commit); the Android JVM tests free 628 and gms 631 passed; make coverage-shell-all green; the WebKit smoke 927 screens, 9,566 checks, 0 failed with SMOKE_JOBS=16; cargo check of the shell for x86_64-pc-windows-gnu clean. 2026-11-05 21:12:23 +02:00
webrtc.mk The build follows libtacky v1.0.0-alpha7's layout, built and tested against the release candidate d0d79d4c (a standalone clone, ANOTHER_IM_TACKY), with the submodule pin left at v1.0.0-alpha4 until the tag exists: native/ is gone, so tacky-checkout no longer fetches libomemo-c (OMEMO is the Rust tacky-omemo and the backend needs none of its submodules here), BACKEND_VARS and the Flatpak manifest's make line name TACKY_MEDIA_BUILD and TACKY_MEDIA_DL instead of the OMEMO, libomemo-c and media trees, DEV_WATCH watches tacky/, ext/, tacky-core and tacky-omemo, and tools/flatpak-sources.py vendors the crates of the three Cargo.lock files make lib builds from, there being no workspace lockfile any more. The webrtc media backend is tacky-media/webrtc's libtackymedia_webrtc, a C library with no Tcl in it: webrtc.mk builds it from there without a Tcl prefix and make webrtc no longer waits for libtacky, the Android and Windows goals build it through tacky-media's own webrtc-android and win-webrtc (platforms/webrtc.mk is gone) and macOS through libtacky's webrtc-macos, and the file is libtackymedia_webrtc.{so,dll,dylib} everywhere the shell and the packaging name it (app.rs's WEBRTC_LIB, the AppImage, the Flatpak, the apk's jniLib and MainActivity's loadLibrary, the Windows installer and its smoke run). The browser worker links the new wasm archives (libtacky_omemo.a and libtacky_crypto.a in place of libomemo-c.a and libcrypto.a), calls Tackycore_Init, Tackyomemo_Init and Tackycrypto_Init beside Sqlite3_Init as embed/extensions.h lists them (Tackykeyring, Tackyxml and Tclcrypto are gone), dispatches to ::tacky::core::wire::dispatch, stops with ::tacky::backend destroy and releases acks with ::tacky::xmpp::session::durable_all; its boot and omemo suites use the renamed packages (tacky::core::storage's tacky_store, the typed tacky::core::keyring 0.2, tacky::omemo's ratchet commands, tacky::crypto, tacky::http) and bench-store's seed the renamed wire and store, though its OMEMO rows still use the removed high-level ratchet API. The connection suite is not ported: its fake peer was tacky-xmpp's FakePeer, which libtacky deleted with the crate, and the Tcl peer that replaced it needs tdom, which this image lacks. Checked in the image: make bundle-appimage (dist/another-im-tauri-0.3.6-x86_64.AppImage, 138,668,536 bytes, carrying libtackymedia_webrtc.so), make check clean, test-ui 130 files 1,644 passed, test-shell 17 binaries 93 passed, test-embed 74 and 6 passed against the built archive, the worker's spike 8, boot 35, omemo 3, host 18, store 64 and page 40 checks passed with test-connect failing on the missing crate, and make (dist/web) built. 2026-10-07 22:31:18 +03:00

anotherim-js

Another IM is an XMPP messenger. This repository holds its client: one UI in TypeScript with lit, in a browser tab, a desktop app for Linux, Windows and macOS (a Tauri 2 shell), and an Android app (the same shell, plus Kotlin for push, calls and files).

Version 0.8.0-rc4. Breaking changes are still possible. Licence MPL-2.0.

The desktop window in the Night theme over a wallpaper: the chat list with pictures, pins, unread and muted rooms, Telegram contacts; a 1:1 chat with OMEMO, a photo, a reply, a sticker, reactions

A group chat on a phone in the Day theme, with two @-mentions The chat list on a phone in the Night theme: pinned chats, rooms with unread mentions, a muted room, Telegram contacts

A chat on the desktop; a group chat with @-mentions and the chat list on a phone. The people are invented: make screenshots draws them from the mock backend.

Features

  • Several accounts; sign in by password, OAuth or an SSO broker; sign up with CAPTCHA or proof-of-work
  • 1:1 and group chats with server history, replies, edits, reactions, threads, pins and search
  • Delivery ticks and read markers; retracted messages kept, with edit history
  • Albums with captions, silent and scheduled messages, polls, places, stickers
  • @-mentions, rooms on "mentions only", roles and moderation
  • OMEMO in chats and private rooms, keys verified by QR code
  • Telegram and other networks through gateways, Telegram secret chats in the apps
  • Local store encrypted by default with the system keyring
  • HTTP upload and direct device-to-device transfer, voice and round video messages
  • 1:1 audio and video calls
  • Push while closed: Web Push, UnifiedPush, FCM
  • Night and Day themes, five languages, backup and restore

The whole list is in docs/features.md, with what has not been tried on a real device yet. Tests run against a mock backend, not real servers.

Download

Builds of each release are on the releases page: the Android apk (UnifiedPush, or FCM in the -gms one), the Linux AppImage and Flatpak, the Windows installer and portable zip, and the browser client as a tarball to serve yourself (docs/building.md).

platform minimum
Chromium browsers 97 ('wasm-unsafe-eval' in the CSP)
Firefox 114 (module workers)
Safari, iOS 16
Android app Android 11, arm64; WebView 80
Linux AppImage glibc 2.35, or EL9's 2.34; x86_64
Linux Flatpak GNOME 50 runtime, x86_64
Windows 10 or 11, x86_64, with WebView2
macOS 11, Apple silicon

An engine too old for the bundle shows "This browser is too old" (or, on Android, "Update Android System WebView") instead of a blank page.

Build

Everything builds in this repository's container images. The host needs git and podman (or docker); make <goal> runs the goal in the container. A Mac builds on the Mac (docs/macos.md).

git clone --recurse-submodules https://dev.another.im/another-im/anotherim-js.git
cd anotherim-js
make docker-build             # backend, dist/web, web tarball, AppImage
make test-ui check test-shell # the tests that need no backend
make dev                      # the UI on http://localhost:5173 (DEV_BACKEND=mock: no backend)

make release-check runs make check-pins and make audit, the RustSec audit of src-tauri/Cargo.lock, before a release; make check stays offline (docs/building.md).

build target
Browser make web-tar
Linux make bundle-appimage, make bundle-flatpak
Windows make bundle-windows
Android make bundle-android, make bundle-android-gms ANOTHER_IM_GOOGLE_SERVICES=<file>
macOS make bundle-macos, on a Mac

make help lists every target. Outputs, signing, build knobs, command-line options and serving the browser client are in docs/building.md.

How it fits together

The UI does not speak XMPP itself. Protocol, storage, encryption, calls and file transfer all come from libtacky, through its JSON wire API.

                ui/                 TypeScript + lit: views, state, the wire API
                 │                  one Transport interface, three implementations
     ┌───────────┼────────────┐
   mock        worker        tauri
  in-page    libtacky as     libtacky.a in the Tauri shell
  (dev)     wasm (browser)   (desktop, Android)
component language what it is code tests coverage
ui/ TypeScript the client: views (46,647), state (27,932), protocol and the mock backend (11,087), the rest (1,921) 87,587 95,975 97.8%
JS two boot scripts that catch an old browser 73 -- not measured
src-tauri/ Rust the shell: libtacky binding, files, notices, push, tray, windows 14,847 8,259 94.7% (all of src-tauri/src on Linux)
src-tauri/gen/android/ Kotlin push, notifications, calls, files, share target 7,167 9,290 94.6%
worker/ JS the worker, its OPFS store and file system 880 1,997 100%
C the backend host compiled to wasm 439 -- not measured
Tcl a package index for stubs 4 -- not measured
total TypeScript 87,587 · Rust 14,847 · Kotlin 7,167 · JS 953 · C 439 · Tcl 4 110,997 115,521
everything else make, sh, Python, JS tools/, docker/, flatpak/, the Makefiles; not in the total 14,495 -- --

Measured on 2026-11-05 for v0.8.0-rc4 (develop d6fd0423; libtacky 28ab9df0, v1.2.0-rc3).

  • code: non-blank, non-comment lines of the files git tracks, by the rules of libtacky's tools/stats.py. The generated wire API (ui/src/protocol/generated/api.ts, 17,544 lines), JSON, CSS, HTML and the language catalogues are not counted.
  • tests: ui/test/, src-tauri/tests/, Rust #[cfg(test)] modules, Kotlin src/test/ and src/testGms/, worker/test/.
  • coverage: line coverage. make coverage-ui runs the UI tests under V8 over every ui/src file but the generated API: 66,317 of 67,834 lines, 90.8% of branches. make coverage-shell-all runs all of src-tauri/src on Linux under LLVM, with libtacky faked (feature fake-tacky): 12,441 of 13,135 source lines (94.7%). make coverage-android runs the Kotlin unit tests under JaCoCo with Robolectric: 4,449 of 4,705 lines (94.6%). make coverage-worker runs the worker's node suites: 872 of 872 lines. Measured 2026-11-05.

Tests

suite command files cases last run
UI (vitest, happy-dom) make test-ui 432 5,094 2026-11-05: 5,086 passed, 8 skipped
Types and catalogues make check -- -- 2026-11-05: passed, 2,401 strings in all five languages
Shell, plain-std modules make test-shell 55 442 2026-11-05: all passed
Shell, whole crate with libtacky.a make test-embed 41 263 not run for this count
Android JVM unit tests gradle in the android image (make coverage-android) 49 631 2026-11-05: all passed (free 628, gms 631)
wasm worker under node make test-worker 5 -- 2026-11-05: all passed
WebKitGTK layout smoke make webkit-smoke 1 9,566 checks 2026-11-05: all passed
Chromium smoke of dist/web make web-smoke 1 1 not run for this count

Docs

Licence

anotherim-js is MPL-2.0 (LICENSE). libtacky is GPL-3.0, so a build as a whole is distributed under the GPL-3.0. Bundled third-party parts:

  • Fira Sans Condensed, SIL Open Font License 1.1 (ui/public/fonts/OFL.txt)
  • Lucide icons, ISC, some from Feather, MIT (ui/public/licenses/lucide.txt)
  • FFmpeg decoders for H.264, HEVC and AAC in the AppImage, LGPL-2.1+ (patent-encumbered in some countries)

The sounds, the call tones included, are generated by tools/sounds/make-sounds.py.