Contributor workflow: install, format, lint, test, version bumps, and adding locales. Runtime install paths are in Installation and setup. Packaging is in Building from source and packaging.
| Branch | Purpose |
|---|---|
| master | Stable releases |
| dev | Active development. May be incomplete or breaking. |
task install
task format
task lint
task test
task buildMakefile 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) |
Two paths work without internet access:
Dev container. docker/Dockerfile.dev bakes the toolchain (Python, Node,
uv, pnpm, go-task) plus warmed uv and pnpm caches for the locked
dependency graphs:
docker build -f docker/Dockerfile.dev -t meshchatx-dev .
docker run --rm -it -v "$PWD":/src -w /src meshchatx-dev bashInside the container task lint, task test:backend, and
task test:frontend run without PyPI or npm access (UV_OFFLINE and
PNPM_OFFLINE are set). The bind mount gives live edit/test cycles.
Local caches. With a warm uv cache and pnpm store you can also stay
offline on the host:
uv sync --frozen --group dev # or: uv pip install --no-index --offline
pnpm install --frozen-lockfile --offlineFor fully air-gapped artifact builds use the vendor bundle path described in
Building from source and packaging (pnpm run bundle:offline,
MESHCHATX_OFFLINE_BUILD=1). Android wheels need a one-time online pass:
bash scripts/build-android-wheels-local.sh then copy android/vendor/.
For a Vite HMR loop, use task dev as described in Installation and setup.
From a clean clone:
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.1pnpm 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.
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, Arch PKGBUILD helpers, and third-party notices. Docs, READMEs and issue templates do not carry the version.
pnpm run version:sync also runs scripts/bake_build_meta.js, which writes gitignored _build_meta_baked.py with commit, product channel (testing / beta / stable / local), and release/channel_prompt.json. Override channel with MESHCHATX_BUILD_CHANNEL.
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.
For rngit releases, scripts/rngit_release.py builds the wheel and pyz into python-dist/, signs and uploads them to the release remote, and verifies the manifest afterwards. Run python3 scripts/rngit_release.py --help for the commands (list, view, fetch, verify, create, delete, release) and the environment overrides.
| Channel | Tags | How to cut |
|---|---|---|
| Testing | nightly-* (also testing-*) | Daily cron / Testing Release workflow from dev |
| Beta | beta-* (also preview-*) | Beta Release workflow_dispatch (CI must be green on that SHA) |
| Stable | vX.Y.Z | Promote Release to Stable, or tag vX.Y.Z on the same SHA Beta tested |
| Local | (none) | Source checkout / unset bake |
Before a Testing or Beta cut, edit release/channel_prompt.json (focus_areas, notes). Bug reports go to bug_report_lxmf in that file (swap later for an issues bot destination). The app shows that copy once per build on Testing/Beta and always on About.
- Edit release/channel_prompt.json if you want focus areas for testers.
- Cut Testing (automatic) or Beta (Beta Release / Promote Release).
- For Stable, promote the same SHA that shipped as Beta (rebuild is required so channel bake flips to stable. Do not copy Beta assets onto a Stable release).
- Review the Stable draft GitHub release (assets, SLSA, cosign), then publish. Immutable releases cannot gain assets after publish.
- Rollback: publish a new Stable from a known-good prior SHA. Do not rewrite a published release.
- Users see the channel badge in the sidebar and About. Testing/Beta also get a one-time prompt.
- Flatpak: the tag's
flatpak-ostreejob publishes tohttps://cdn.quad4.io/flatpak/on branchtesting,beta, orstable. Keep that OSTree tree underflatpak/only. After the first good CDN publish, disable GitHub Pages if it still hosts the old Flatpak tree. - Bunny pull zone (
cdn.quad4.io): long cache on/flatpak/repo/objects/*and/deltas/*. No cache or must-revalidate onsummary*,refs,config, and*.flatpakref/*.flatpakrepo.
Hard rule for CI speed: cache toolchains and downloads only. Tagged release binaries must be built inside that tag's single build-release run_id. Never attach artifacts from another run.
Prerelease retention: keep about 7 Testing and 5 Beta GitHub prereleases (scripts/ci/github-prune-channel-prereleases.sh). Stable releases are never auto-deleted.
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 any offline-capable tool you prefer and keep interpolation variables such as {count} intact. After a machine pass, have an LLM or a human check grammar, context, and tone.
pnpm test -- tests/frontend/i18n.test.js --runThat 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.
Translation fixes are welcome via LXMF (f489752fbef161c64d65e385a4e9fc74) or a pull request.
In-app MeshChatX guides under docs/en/ are English today. Localized landing pages exist for the Reticulum manual tab.
- Architecture and design for process layout and managers
- Building from source and packaging for offline and APK builds
- .agents/ for contributor agent conventions (not shipped in-app)