No description
Find a file
2026-08-15 17:36:52 -05:00
.agents docs: update privacy mode and testing guidelines for clearnet calls 2026-08-14 12:12:48 -05:00
.githooks feat: update Makefile and docs 2026-07-13 14:10:38 -05:00
.github refactor: replace inline APK staging script with a dedicated shell script for improved maintainability 2026-08-15 16:44:16 -05:00
.vscode feat: integrate Vue DevTools for local development and improve debugging capabilities with debugpy 2026-08-13 16:35:41 -05:00
android update READMEs 2026-08-15 16:44:11 -05:00
cogs feat: various updates to filesync, ui, deps, add active sessions in about page and stuff related to new rns 1.4.0 2026-07-22 10:32:36 -05:00
config/cogs feat: various updates to filesync, ui, deps, add active sessions in about page and stuff related to new rns 1.4.0 2026-07-22 10:32:36 -05:00
docs feat: opt-in map announce and fix catalog fetch 2026-08-15 17:36:39 -05:00
electron feat: various bug fixes and improvements and naming scheme changes for android apk 2026-08-15 16:44:01 -05:00
lang update READMEs 2026-08-15 16:44:11 -05:00
logo 1.0.0 2026-01-01 15:25:23 -06:00
meshchatx feat: opt-in map announce and fix catalog fetch 2026-08-15 17:36:39 -05:00
packaging/arch feat: fix pycodec2 for macos and improve CI 2026-08-15 14:10:49 -05:00
patches feat(canvas): update canvas performance by setting willReadFrequently to true in context creation for improved read operations 2026-04-22 22:10:14 -05:00
screenshots feat(docs): add MeshChatX installation guide for Meta Quest headsets and include setup requirements 2026-06-08 07:44:20 -05:00
scripts feat: fix unify-backend script to support mirroring architecture-specific native libraries for consistency across builds 2026-08-15 17:26:39 -05:00
tests fix: update ConfirmDialog snapshot 2026-08-15 17:36:48 -05:00
typings feat(typings): add stubs for Android and Java dependencies to support type checking 2026-07-10 15:52:07 -05:00
vendor refactor: update path response and link establishment timeout handling across various components to improve reliability and performance 2026-08-13 17:51:02 -05:00
visualiser-wasm feat: visualiser improvements and 3D view and decrease collapased sidebar width a bit. 2026-08-13 18:24:52 -05:00
.dockerignore feat: improve portable storage handling and announce settings for page nodes 2026-07-28 18:07:39 -05:00
.gitignore feat: integrate Vue DevTools for local development and improve debugging capabilities with debugpy 2026-08-13 16:35:41 -05:00
.prettierignore chore(config): add temp-tests directory to .prettierignore and eslint configuration to exclude temporary test files 2026-07-07 22:42:59 -05:00
.prettierrc 1.0.0 2026-01-01 15:25:23 -06:00
.python-version chore(python): add .python-version file to specify Python version 3.14 2026-07-04 17:16:31 -05:00
AGENTS.md feat: update agent docs 2026-08-12 20:44:17 -05:00
CHANGELOG.md Update CHANGELOG 2026-08-15 17:36:52 -05:00
CONTRIBUTING.md chore(LXMF): update LXMF address across documentation and codebase 2026-06-12 20:10:33 -05:00
CONTRIBUTORS chore(CONTRIBUTORS): add zenith to the list of contributors 2026-05-06 16:21:04 -05:00
cosign.pub feat(ci): add scripts for cosign setup, release asset attestation, and verification 2026-03-31 00:32:22 +03:00
cx_setup.py feat: fix pycodec2 for macos and improve CI 2026-08-15 14:10:49 -05:00
docker-compose.coolify.yml feat: harden Docker configurations and commands 2026-07-26 06:35:03 -05:00
docker-compose.demo.yml feat: add demo mode and ALTCHA integration for better security for internet deployments and showcase functionality 2026-07-26 07:06:45 -05:00
docker-compose.dev.yml feat: harden Docker configurations and commands 2026-07-26 06:35:03 -05:00
docker-compose.yml feat: harden Docker configurations and commands 2026-07-26 06:35:03 -05:00
Dockerfile feat: add vite-dx script 2026-08-13 18:24:27 -05:00
Dockerfile.build feat: improve portable storage handling and announce settings for page nodes 2026-07-28 18:07:39 -05:00
Dockerfile.hardened feat: add vite-dx script 2026-08-13 18:24:27 -05:00
donate.md feat(donate): add donation options and integrate into the About page 2026-04-29 19:30:53 -05:00
eslint.config.mjs feat: add vue/no-v-html rule to ESLint configuration for improved security 2026-08-14 12:12:55 -05:00
FAQ.md docs(FAQ): update AI usage section 2026-07-12 17:30:57 -05:00
knip.config.js refactor(knip.config): clean up entry points and dependencies by removing legacy files and unused dependencies 2026-07-04 17:07:06 -05:00
LEGAL.md fix(legal): format 2026-04-16 23:33:54 -05:00
LICENSE chore(docs): update licensing terms to 0BSD for project-owned portions and maintain MIT for upstream Reticulum MeshChat; add legal inquiries section and clarify contribution licensing in CONTRIBUTING 2026-04-16 18:11:49 -05:00
Makefile feat: update Makefile and docs 2026-07-13 14:10:38 -05:00
MANIFEST.in feat: integrate RNS FileSync functionality, including handler setup, API endpoints, and frontend components for file synchronization 2026-07-19 13:46:43 -05:00
meshchatx.rsm Update CHANGELOG 2026-08-15 17:36:52 -05:00
package.json chore: bump version to 4.8.4 and update related documentation 2026-08-14 17:29:34 -05:00
playwright.config.js fix(e2e): update default backend port to avoid conflicts and ensure consistent configuration across files 2026-03-31 17:42:12 +03:00
pnpm-lock.yaml chore: update Babel dependencies to version 7.x and adjust Python dependency overrides 2026-08-14 16:16:30 -05:00
pnpm-workspace.yaml chore: update Babel dependencies to version 7.x and adjust Python dependency overrides 2026-08-14 16:16:30 -05:00
pyproject.toml chore: bump version to 4.8.4 and update related documentation 2026-08-14 17:29:34 -05:00
pyrightconfig.json feat: implement PWA app-shell caching with service worker for improved offline experience and faster UI loading 2026-07-24 07:09:19 -05:00
pytest.ini feat: introduce Extended Edge Case Tester (EECT) and Live Validation (LV) with new testing scenarios and log redaction improvements 2026-07-18 04:54:41 -05:00
README.md Update README 2026-08-15 16:44:26 -05:00
requirements.txt chore: update LXMF dependency to version 1.1.1 and adjust related documentation 2026-08-13 12:31:34 -05:00
SECURITY.md chore: standardize placeholder values in various components and documentation, replacing "—" with "-" for consistency 2026-07-22 16:18:22 -05:00
Taskfile.yml feat: fix pycodec2 for macos and improve CI 2026-08-15 14:10:49 -05:00
tsconfig.json feat(ci & deps): update rns and lxst. 2026-07-04 17:06:44 -05:00
uv.lock chore: bump version to 4.8.4 and update related documentation 2026-08-14 17:29:34 -05:00
vite.config.js feat: integrate Vue DevTools for local development and improve debugging capabilities with debugpy 2026-08-13 16:35:41 -05:00
vitest.config.js feat(micron): implement SRI verification for WASM assets and generate integrity.json 2026-05-02 16:22:29 -05:00
vitest.electron.config.js chore(ci): update pnpm version, add offline build support to wasm fetch, fix electron coverage 2026-05-18 05:10:53 -05:00

Reticulum MeshChatX

Русский | Deutsch | Italiano | 中文 | 日本語

Fork of Reticulum MeshChat by Liam Cottle. MeshChatX adds LXST voice calls, RRC relay chat, Nomad map overlays, plugins, raw SQLite (no Peewee), and Electron 41 desktop builds.

This project is independent from the original Reticulum MeshChat project and is not affiliated with it.

Get it on Obtainium

rngit NomadNet Node: 132f67e79d9b24aad014e93015fb858f:/page/index.mu

git clone rns://06a54b505bb67b25ef3f8097e8001edc/public/MeshChatX

Changes from Reticulum MeshChat

  • LXST for calls
  • RRC relay chat
  • More tools, panes, and tabs
  • Map with MBTiles, plus remote KMZ/KML/GeoJSON overlays (NomadNet /file/ and RNGit sparse fetch)
  • Raw SQL instead of Peewee
  • Native fetch instead of Axios
  • Electron 41.x (bundled Node 24)
  • Wheels ship with the web server and built frontend assets
  • i18n
  • pnpm and UV for dependencies

Requirements

  • Python 3.11 or newer
  • Node.js 24 or newer
  • pnpm 11.1.2
  • UV

The bundled web UI needs Safari 16.4, Chrome 111, or Firefox 128 or later.

Install methods

Method Frontend assets Architectures Best for
Docker image Yes linux/amd64, linux/arm64 Linux servers
Python wheel Yes Any Python-supported arch Headless/web install without a Node build
Linux AppImage Yes x64, arm64 Portable desktop
Debian package Yes x64, arm64 Debian/Ubuntu
RPM package Yes CI-runner dependent Fedora/RHEL/openSUSE
From source Built locally Host arch Development and custom builds

Tagged releases build Linux wheel/AppImage/deb/rpm, Windows, macOS, Flatpak, and Android APKs (when the tag is on dev or master) in build-release.yml. The container image is docker.yml. Branch and PR Android CI is android-build.yml. Linux x64 and arm64 AppImage + DEB are built on GitHub. RPM is uploaded when the job produces one.

Docker

  • Docker Hub: quad4io/meshchatx
  • GHCR: ghcr.io/quad4-software/meshchatx
  • Default tags (for example :latest) are Alpine. Use -hardened for Chainguard/Wolfi, or -extra for Alpine plus i2pd and yggdrasil (:latest-extra, same Dockerfile with VARIANT=extra).
docker compose up -d
docker run -d --name reticulum-meshchatx \
  --restart unless-stopped \
  --init \
  --user 1000:1000 \
  --security-opt no-new-privileges:true \
  --cap-drop ALL \
  --read-only \
  --tmpfs /tmp:noexec,nosuid,size=256m \
  --tmpfs /home/meshchat:nosuid,size=64m \
  --cpus=2.0 \
  --memory=1g \
  --memory-reservation=256m \
  --pids-limit=512 \
  -p 127.0.0.1:8000:8000 \
  -v meshchatx-config:/config \
  ghcr.io/quad4-software/meshchatx:latest

Swap in quad4io/meshchatx:latest if you prefer Docker Hub.

Default compose mapping: host 127.0.0.1:8000 to container port 8000, named volume meshchatx-config to /config. That volume works with the image meshchat user (UID 1000) without bind-mount permission fixes.

To bind a host directory instead, use -v "$(pwd)/meshchat-config:/config" (or the same path in Compose volumes). The container runs as UID 1000, so that directory must be writable by uid 1000:

sudo chown -R 1000:1000 ./meshchat-config

Create the directory first if it is empty. Otherwise Docker may create it as root-only.

Inspect or wipe the named volume:

docker volume inspect meshchatx-config
docker rm -f reticulum-meshchatx
docker volume rm meshchatx-config

The last two commands destroy persisted data.

Install from release artifacts

Linux AppImage (x64/arm64)

Download ReticulumMeshChatX-v<version>-linux-<arch>.AppImage from releases, then:

chmod +x ./ReticulumMeshChatX-v*-linux-*.AppImage
./ReticulumMeshChatX-v*-linux-*.AppImage

Debian/Ubuntu

Download the matching .deb, then:

sudo apt install ./ReticulumMeshChatX-v*-linux-*.deb

RPM

Download the .rpm if the release has one, then:

sudo rpm -Uvh ./ReticulumMeshChatX-v*-linux-*.rpm

Python wheel

Release wheels include the built web assets.

pip install ./reticulum_meshchatx-*-py3-none-any.whl
meshchatx --headless

pipx works too:

pipx install ./reticulum_meshchatx-*-py3-none-any.whl

Run from source (web server)

git clone https://github.com/Quad4-Software/MeshChatX.git
cd MeshChatX
corepack enable
pnpm config set verify-store-integrity true
pnpm install --frozen-lockfile
pip install "uv==0.11.15"
uv lock --check
uv sync --group dev
pnpm run build-frontend
uv run python -m meshchatx.meshchat --headless --host 127.0.0.1

pnpm install --frozen-lockfile fails if pnpm-lock.yaml does not match package.json, so an unexpected upstream version cannot land silently. Store integrity is also on in pnpm-workspace.yaml. The extra pnpm config set line hardens the user-level config too.

pnpm v11+ blocks lifecycle scripts by default. Only packages listed under allowBuilds in pnpm-workspace.yaml may run install scripts (electron, electron-winstaller, esbuild). uv lock --check fails if uv.lock is out of date with pyproject.toml. uv sync then installs from the lockfile only. Pin UV with pip install "uv==0.11.15" to match CI.

To update dependencies on purpose, run pnpm update or uv lock in its own commit and read the lockfile diff before you push.

Linux sandbox

Firejail or Bubblewrap (bwrap) can isolate the native meshchatx binary (alias: meshchat) while leaving network access for Reticulum and the web UI. Examples, pip/pipx, Poetry, and USB serial notes: linux-sandbox.md.

That page also shows up in the in-app Documentation list when meshchatx-docs is bundled or synced.

Linux desktop emoji fonts

The emoji picker uses system fonts through Electron/Chromium. Empty squares mean a color emoji package is missing. Install one and restart the app.

Distro Package
Arch, Artix, Manjaro sudo pacman -S noto-fonts-emoji
Debian, Ubuntu sudo apt install fonts-noto-color-emoji
Fedora google-noto-emoji-color-fonts

If glyphs still fail, run fc-cache -fv or wait until the next login. noto-fonts helps on minimal installs that lack other symbol coverage.

Windows microphone (Electron, Windows 10 / 11)

Calls and voice attachments use the mic through Chromium. If the UI has no access or getUserMedia fails, check Windows privacy first. That is a common miss for Win32 apps, Electron included.

  1. Win+R, paste ms-settings:privacy-microphone, Enter.
  2. Turn Microphone access on.
  3. Enable Let desktop apps access your microphone (wording varies by Windows version).
  4. If a per-app list appears, make sure MeshChatX is not denied.

Also check Settings, System, Sound so the app is not muted and a working input device is selected.

Offline builds

Two levels:

  1. Cached: you already ran make install once, so node_modules, .venv, and local caches exist.
  2. Air-gapped: the build machine has never had internet. Build a bundle on a networked machine and copy it over.

Cached offline builds

Set MESHCHATX_OFFLINE_BUILD=1 before any build command. That skips micron-parser-go WASM, the Reticulum manual, and repository wheel fetches, and runs package managers offline. Missing cache files fail the build instead of hanging.

MESHCHATX_OFFLINE_BUILD=1 make install
MESHCHATX_OFFLINE_BUILD=1 pnpm run build:offline
MESHCHATX_OFFLINE_BUILD=1 pnpm run dist:linux:offline
MESHCHATX_OFFLINE_BUILD=1 ./gradlew :app:assembleRelease

Cached mode only skips build-time network. The first make install still needs the network, or pre-populated pnpm and uv caches.

Air-gapped builds

On the online machine:

pnpm run bundle:offline
bash scripts/create-offline-bundle.sh --warm-packaging
tar czf meshchatx-offline-linux-x64.tar.gz -C vendor/offline meshchatx-offline-bundle-*/

--warm-packaging is optional. It pre-downloads tools such as appimagetool.

On the air-gapped machine:

tar xzf meshchatx-offline-linux-x64.tar.gz
bash scripts/install-offline.sh
MESHCHATX_OFFLINE_BUILD=1 make build
MESHCHATX_OFFLINE_BUILD=1 pnpm run dist:linux

The bundle is platform-specific (Electron, esbuild, and other native binaries). Create it on the same OS and architecture as the air-gapped host. That host still needs node, pnpm, uv, and python3. The bundle is dependencies and caches, not the toolchain.

Android is separate. The offline bundle does not include Chaquopy wheels. Build those on an online machine with bash scripts/build-android-wheels-local.sh, copy android/vendor/ next to the project, then run Gradle with MESHCHATX_OFFLINE_BUILD=1.

Desktop packages from source

pnpm run dist:linux-x64
pnpm run dist:linux-arm64
pnpm run dist:rpm
task dist:fe:rpm

Windows (x64 and arm64) and macOS (arm64 and universal) scripts are in package.json for local builds.

Container build (wheel, AppImage, deb, rpm)

Dockerfile.build runs the same shell steps CI uses (Poetry, pnpm, task, packaging APT deps). It is aimed at linux/amd64 (NodeSource amd64 tarball, Task amd64 binary).

MESHCHATX_BUILD_TARGETS defaults to all. Other values: wheel, or electron (AppImage + deb for x64 and arm64, best-effort RPM, no wheel).

docker build -f Dockerfile.build -t meshchatx-build:local .
docker build -f Dockerfile.build --build-arg MESHCHATX_BUILD_TARGETS=wheel -t meshchatx-build:wheel .

Copy artifacts off the image:

cid=$(docker create meshchatx-build:local)
docker cp "${cid}:/artifacts" ./meshchatx-artifacts
docker rm "${cid}"

Android

Native APK builds, not only Termux. From the repo root:

bash scripts/build-android-wheels-local.sh
cd android
./gradlew --no-daemon :app:assembleDebug :app:assembleRelease

Offline:

MESHCHATX_OFFLINE_BUILD=1 ./gradlew --no-daemon :app:assembleRelease

That skips the repository wheels fetch. android/vendor/ wheels and meshchatx/public/repository-server-bundled/bundled/ must already be present.

There is one Android variant. Gradle syncs the full meshchatx/ tree into app/src/main/python/meshchatx/, including the offline repository wheel bundle. Published builds are universal: one debug APK and one release APK per run, with the native ABIs from android/app/build.gradle.

  • Debug: android/app/build/outputs/apk/debug/app-debug.apk
  • Release: android/app/build/outputs/apk/release/ReticulumMeshChatX-v*-android-universal-unsigned.apk
  • GitHub release: ReticulumMeshChatX-v-android-universal.apk

Release APKs are unsigned unless you configure signing (scripts/sign-android-apks.sh). Native ABIs follow android/app/build.gradle, including armeabi-v7a when that ABI is enabled. Building those wheels needs an Android SDK on ANDROID_HOME.

If dist/reticulum_meshchatx-*.whl exists (for example from python -m build --wheel -o dist .), bundled repository refresh prefers that wheel over PyPI. CI builds that wheel before the Android Gradle step.

More: android-termux.md, android/README.md.

Configuration

CLI args and matching env vars:

Argument Environment variable Default Description
--host MESHCHAT_HOST 127.0.0.1 Web server bind address
--port MESHCHAT_PORT 8000 Web server port
--no-https MESHCHAT_NO_HTTPS false Disable HTTPS
--ssl-cert / --ssl-key MESHCHAT_SSL_CERT / MESHCHAT_SSL_KEY (none) PEM cert and key. Both must be set. Overrides auto-generated certs under the identity ssl/ directory.
--rns-log-level MESHCHAT_RNS_LOG_LEVEL (none) RNS log level: none, critical, error, warning, notice, verbose, debug, extreme, or a number. CLI wins if both are set.
--headless MESHCHAT_HEADLESS false Do not auto-launch a browser
--auth MESHCHAT_AUTH false Enable basic auth
--reset-password MESHCHAT_RESET_PASSWORD false Clear the stored password hash so a new one can be set in the UI
--storage-dir MESHCHAT_STORAGE_DIR ./storage Data directory
--public-dir MESHCHAT_PUBLIC_DIR auto/bundled Frontend files. Needed for source installs without bundled assets.

Branches

Branch Purpose
master Stable releases
dev Active development. May be incomplete or breaking.

Development

task install
task format
task lint
task test
task build

Makefile targets call the same Taskfile commands:

Command Delegates to Description
make install task install Install pnpm and UV dependencies
make run task run Run MeshChatX via UV
make build task build Build frontend and backend artifacts
make format task format Format frontend and backend
make lint task lint ESLint, vue-tsc, knip, Ruff, basedpyright
make test task test Frontend and backend tests
make clean task clean Remove build artifacts and node_modules
make tree-rsm-verify (shell) Verify meshchatx.rsm signature and hashes
make tree-rsm-sign (shell) Sign tree inventory (needs RNS_ID_PATH)
make hooks-install (shell) Enable tracked pre-commit RSM resign hook

Versioning

Current version is 4.8.4.

Edit the version field in package.json, then run pnpm run version:sync (also the first step of pnpm run build). That copies the number into pyproject.toml, the Python version modules, Android Gradle, electron/app-version.json, this README and the translated READMEs, the Raspberry Pi pipx example, Arch PKGBUILD helpers, third-party notices, and GitHub issue-template placeholders.

Changelog entries are still written by hand when you cut a release. meshchatx.version is read from meshchatx/src/version.py without importing meshchatx.src, so import meshchatx stays lightweight.

Database corruption and data reset

If MeshChatX fails to start with errors such as database disk image is malformed, DatabaseError, or corrupted ratchet data, the desktop crash screen offers:

  • Restore latest backup from database-backups/ or snapshots/ inside the MeshChatX storage folder
  • Choose backup file for a zip you saved elsewhere
  • Try auto-repair (--auto-recover: SQLite checkpoint / integrity pass)
  • Emergency mode, which opens the app without the database so you can export from About when possible
  • Copy reset instructions with the folders to delete for a clean reinstall

Storage locations

Platform MeshChatX storage Reticulum network stack
Linux / macOS ~/.reticulum-meshchatx/ ~/.reticulum/
Windows %USERPROFILE%\.reticulum-meshchatx\ %USERPROFILE%\.reticulum\
Windows portable <MeshChatX.exe folder>\.reticulum-meshchatx\ <MeshChatX.exe folder>\.reticulum\

Legacy Reticulum MeshChat data may still exist at ~/.reticulum-meshchat/ (or the Windows equivalent). Automatic database backups go to database-backups/ inside the MeshChatX storage folder after a successful run.

Complete removal

Quit MeshChatX. On Windows, also end ReticulumMeshChatX.exe in Task Manager if it is still running. Then delete the MeshChatX storage folder and the Reticulum config folder for your install type. That removes the local identity, messages, contacts, path cache, and ratchet state. The next launch creates a new identity unless you restore a backup first.

Linux / macOS:

rm -rf ~/.reticulum-meshchatx ~/.reticulum ~/.reticulum-meshchat

Windows PowerShell:

Remove-Item -Recurse -Force "$env:USERPROFILE\.reticulum-meshchatx", "$env:USERPROFILE\.reticulum", "$env:USERPROFILE\.reticulum-meshchat" -ErrorAction SilentlyContinue

If you pass --storage-dir or --reticulum-config-dir, delete those directories instead.

Command-line restore

When the backend can start briefly, or you run from source:

meshchatx --storage-dir /path/to/storage --restore-db /path/to/backup.zip

Security

  • SECURITY.md
  • LEGAL.md
  • Built-in integrity checks and HTTPS/WSS defaults at runtime
  • CI and release builds on GitHub Actions

Adding a language

My workflow: ArgosTranslate, then a local LLM (Qwen 3 + Gemma 4).

People are welcome to send fixes via LXMF (f489752fbef161c64d65e385a4e9fc74) or however you can reach me.

Locale discovery is automatic. Add a file under meshchatx/src/frontend/locales/ (for example xx.json) with the same keys as en.json and a top-level _languageName string for the selector label. Copy en.json and translate the values. Machine-assisted generation is optional.

For a machine-generated first draft from en.json, use scripts/argos_translate.py. It keeps interpolation variables such as {count} intact.

pipx install argostranslate
python scripts/argos_translate.py --from en --to xx --input meshchatx/src/frontend/locales/en.json --output meshchatx/src/frontend/locales/xx.json --name "Your Language Name"

After a machine pass, have an LLM or a human check grammar, context, and tone.

pnpm test -- tests/frontend/i18n.test.js --run

That checks key parity with en.json. No other code changes. The app, language selector, and tests pick up locales from meshchatx/src/frontend/locales/ at build time.

Donation

Donations are voluntary. They help fund time spent on this app.

Ways to give: donate.md (Monero, Ko-Fi, Buy Me a Coffee).

Credits

License

Project-owned portions are 0BSD. Original upstream portions from Reticulum MeshChat remain MIT. Full text: LICENSE.