Skip to content

Install and try Arveil

Español.

Were you simply invited to someone's realm? The website has a shorter guide written for you: Install Arveil. This page is the complete reference, including running a relay and building from source.

Current availability (October 1, 2026): beta 6, 0.1.0+27 provides macOS ARM64 ZIP and Android ARM64 APK, checksums, metadata and signed announcement sequence 8. Homebrew distributes 0.1.0-beta.6,27. Google Play provides build 27 in internal testing, without production review. Update through the same channel without uninstalling or clearing data.

Server compatibility. Public relay/CLI v0.1.0 binaries predate CredentialGet and personal invitations. This beta needs relay revision e4011f3f2781aa48888d7da35114aa475d6ff71e or a later compatible, tested revision. The test deployment is already updated; versioned relay/CLI distribution and the complete compatibility matrix remain in #133. Take consistent backups before migration. Do not open relay schema 5 or profile schema 8 with older binaries.

Personal invitations in beta 6

Invite someone combines admission and contact in one private link/QR. The issuer needs the owner role, granted by the host operator to their existing identity. The recipient installs the app, returns to the link (or scans/pastes), reviews and accepts. This creates an independent identity and conversation; existing same-server members retain their identity. No history is copied and no contact is automatically verified. Legacy server/token enrollment remains available.

Invitations explains permission, migrations and recovery. The first chat reaches the issuing device when it synchronizes again. An invitation does not grant access to Play internal testing: the recipient must also be a tester. Return to the original link after installation.

Packages remain experimental, without an independent audit. Camera, clean-installation and notification acceptance on real devices remain in #134 and #140. See the platform record.

Choose your starting point

I want to… Available path Remaining acceptance
Run a relay Build compatible beta 6 source with Docker Compose/Podman Record installation and upgrade on a clean supported host; a source client needs a matching newer relay
Try the macOS app Beta 6 ZIP or Homebrew Fresh downloaded installation on another Mac and VoiceOver
Try the Android app Beta 6 APK or internal Play (authorized tester) Physical-phone installation/update, camera, links, TalkBack and Doze/reconnect
Use an iPhone Separate, later milestone Native acceptance and supported signing/distribution

Relay: first local start with Docker Compose

Prerequisites: Git, Docker and the Docker Compose plugin. Run from the repository root after cloning:

git clone https://github.com/Ulzuhan/arveil.git
cd arveil
docker compose -f relay/compose.yaml up -d --build
docker compose -f relay/compose.yaml ps
docker compose -f relay/compose.yaml exec arveil-relay /arveil-relay healthcheck -admin http://127.0.0.1:9090

A working relay answers ok to the health check. Get its connection data and create a one-use invitation for a test profile:

docker compose -f relay/compose.yaml logs --no-log-prefix arveil-relay
docker compose -f relay/compose.yaml exec arveil-relay /arveil-relay invite -data-dir /data

invite prints the invitation token, then a link: line: one https link that carries the relay's details and the invitation together (ADR-012). On a terminal it also draws that link as a QR code. Give the link to the intended person privately; pasted into the app's enrollment form, or opened on a phone with the app installed, it fills both fields. The invitation travels after the #, which browsers never send to the web page, so it reaches no web server log.

-link-base changes the page the link opens (default https://arveil.kaicorplabs.com), -url the endpoint it names (default: the first one the running relay advertises) and -qr whether the QR is drawn (auto, always, never). The older way still works: the bootstrap: line of the log and the invite: token, sent together in one message and pasted whole into the server details.

This default is local-only. The published port and advertised address use loopback. On a phone, 127.0.0.1 means the phone itself. Before testing from another device, configure a reachable endpoint using Running a realm. The private-network route with authenticated SSH, Tailscale and persistent rootless Podman is described step by step in Podman staging. All participating devices must be able to reach the chosen network. An optional Cloudflare Tunnel deployment gives invited users a public WSS endpoint without joining the operator's tailnet. Its private hostnames and credentials are deployment inputs, not repository configuration.

Stop the local relay with docker compose -f relay/compose.yaml stop; start it again with up -d. Its named volume holds persistent data. Follow the backup and upgrade instructions before replacing a version. Backups contain private realm keys.

Install an experimental app package

Client releases use tags named clients-v… and include BUILD-macos.json, BUILD-android.json and SHA256SUMS-clients.txt. A single-platform local candidate instead includes BUILD.json and SHA256SUMS.txt. Download the ZIP or APK from beta 6. Installing these packages does not require Flutter, Rust, Xcode or Android Studio.

macOS: Apple silicon, macOS 12 or newer

  1. Open the macos-arm64.zip archive and drag arveil.app to Applications.
  2. Open Arveil. This experimental build has an ad-hoc signature and is not notarized by Apple. If macOS blocks a trusted download, use the per-app Open Anyway option in System Settings → Privacy & Security, following Apple's instructions.
  3. Select Abrir perfil. macOS stores its key in the login Keychain. If it asks, authorize this app's access; a rebuilt app may ask again. A locked or denied Keychain is reported by the app, with no plaintext fallback.
  4. Paste the relay connection data and one-use invitation, then complete enrollment.

Update: quit Arveil, replace the app in Applications with the newer version, and reopen it. Keep the existing profile and Keychain entry. Do not use an app cleaner to remove its data. If the key cannot be accessed, preserve the profile and resolve Keychain access before continuing. Do not replace the app with an older version: newer builds may change the profile in ways an older one cannot read. Builds after 0.1.0+11 detect a profile from a newer version and refuse to open it without changing it; earlier builds do not check.

The classic login Keychain does not provide the same device-binding protection as the iOS Data Protection Keychain. It is not synchronized by Arveil, but manual Keychain backups/migration are outside the app's control. Existing profiles made with the former Data Protection backend are not automatically migrated. See platform behavior and acceptance.

Android: ARM64, Android 7.0 / API 24 or newer

The APK contains ARM64 code only. Android refuses it on 32-bit-only phones and x86-64 emulators; clients-v0.1.0-beta.1 installs there anyway and closes at launch.

  1. Download the android-arm64.apk file on the phone and open it.
  2. If prompted, permit Install unknown apps for the browser or file manager used to open this APK. Install Arveil; you can turn that permission off afterward.
  3. Open Arveil, select Abrir perfil, then Unirme con una invitación, and enter the server (relay) data and then the invitation. If both came in one message, paste it whole in the first step. A private relay requires the phone to be connected to its network.

Update from the app: builds that include a configured update channel offer Settings → Updates and an update icon on the closed-profile screen. Choose Check for updates, download the verified package and press Install update. If Android asks for Arveil's permission to install packages, grant it and return to press Install again. Confirm Android's update prompt. Automatic foreground checks are optional and initially off; there is no silent installation. See signed updates and privacy.

Manual update: older or unconfigured builds can open the newer APK and choose the update/install option over the existing app. It must use the same signing certificate and a higher build number. Do not uninstall or clear app storage to update: that deletes the local profile/key. An APK signed with another key (including a developer's debug build) cannot update this installation. Preserve the current installation if Android reports a conflict. Check BUILD.json for version and certificate details.

First use and limits

The interface follows the system language (English when the system prefers it, Spanish otherwise) unless you choose one in Ajustes → Apariencia, which also sets the theme, accent, conversation background and text size; the button names below are the Spanish ones. A completed enrollment opens Chats, with Contactos and Ajustes in the bottom bar on a phone or in the side rail on a wide window. On a connection failure, close/reopen and retry with the same relay and invitation; successful enrollment does not need another invitation on reopen. Current source also supports pairing, recovery kits and conversations.

To try conversations with disposable profiles on the same relay using the current source or a package containing it:

  1. In Contactos, select Tu ruta de contacto to share this device's route privately with your contact. Each person can obtain their route here.
  2. Open Contactos → Añadir contacto, paste a route, give it an optional local name and choose Preparar contacto. Compare the full safety number through an independent channel; both people can preview the other's route.
  3. Choose Coinciden when the numbers match, then Guardar contacto; if they differ, choose No coinciden and do not verify. You can also save it unverified and choose Coinciden in its details later. A name never verifies an identity. Guardar nombre edits the alias locally; an empty name removes it. Import another route through Añadir contacto; an empty name preserves an existing alias.
  4. Open Nueva conversación → Elegir contactos guardados. Select verified contacts and choose Usar contactos to create the group with their saved, non-revoked devices (up to 16). Your contact uses Sincronizar to receive it. The original route-paste and comparison flow remains available.
  5. Open the conversation and send text. Offline messages remain saved locally; Sincronizar retries publication. Relay acceptance does not confirm reading.

Automatic sync runs while Arveil is in the foreground. The source increment described below adds opt-in Mac background sync; Android push and general group membership controls are still pending. The existing experimental packages may precede these source changes; check their recorded revision before expecting these screens.

Attachments (available since 0.1.0+7)

In a conversation, choose Adjuntar archivo (the paperclip), select a file smaller than 25 MiB, and confirm. The private queued copy survives restart. If offline, use the file's Enviar / reanudar button when connectivity returns; reattaching would create another message. Incoming files download only when you choose Descargar. Use Guardar copia… to choose an external destination explicitly. That exported copy is outside Arveil's encrypted profile and may be backed up by its destination. Cancelling an unfinished transfer discards its local data; it does not recall a sent message. Request another copy if the relay reports expiry.

File viewing and notifications (source increment, not in build 25)

In a client built with this increment, choose Download and open for an incoming attachment or Open for a local file. PNG/JPEG/WebP images display inside Arveil with zoom, including offline after reopening the profile. PDF and other files offer Open with…: confirm the temporary decrypted copy shared with the selected application. No manual visit to Downloads is needed. Save copy… remains a separate export. An external viewer may retain copies; Arveil cleans its expired temporary copies while running or on the next launch.

On Mac, Settings → Notifications offers generic alerts and an independent Keep Arveil running in the background option. Enabling alerts requests system permission; a denial does not affect messaging. The background option keeps the profile unlocked, hides the window when closed, and provides menu-bar actions to reopen or quit. Quit, profile closure and Mac sleep stop local alerts. If permission is denied, enable Arveil in macOS notification settings and retry.

Android adds an experimental Settings → Notifications page. It requires ntfy's F-Droid app configured with your own HTTPS server; enter the same base address in Arveil and grant notification permission. The public ntfy.sh server is rejected. Notices are generic and can arrive with the profile closed; they never unlock it. Disable the option to stop them. Keep Arveil open online to finish pending registration/removal. Force-stop and battery restrictions can prevent or delay delivery.

Debug builds, native Android receiver instrumentation and disposable Mac attachment acceptance have run. Mac debug notification-center delivery and removal also passed with system permission enabled. The official ntfy F-Droid Android app passes a separate emulator delivery test against a disposable local server. Full relay-to-phone acceptance, packaged Mac banners and physical Android behavior remain release gates; see scope and evidence. No permanent notification server is deployed by these tests. No profile migration or reinstall is required by these changes. Keep the existing profile and Keychain when upgrading through the normal release path.

Build from source

The Flutter README and platform matrix describe the native build and its tested scope. Building currently requires Flutter, Rust and the platform SDKs; downloadable app packages must remove that requirement for end users.

  • macOS: from clients/flutter, run flutter pub get and flutter run -d macos. A local build does not require a paid Apple account to launch and open a profile: it uses the classic login Keychain described above. Xcode must have its license accepted to compile.
  • Android: enable USB debugging for development, connect and authorize the phone, then run flutter devices and flutter run from clients/flutter. Install the platform SDK/NDK required by the project first. Select the Android device if Flutter asks. Emulator acceptance has passed; physical-device acceptance remains pending. This development route is not the planned download-and-install APK experience.
  • iOS: a runnable Flutter source tree is not an accepted iPhone release. Follow the separate milestone in the client plan.

Keep invitations, endpoints, signing material and test output out of Git and public screenshots. The repository provides generic examples, never the maintainer's machine configuration.

Installation is part of the deliverable

Every user-facing release must provide an English and Spanish route from the README to the correct artifact and guide:

  1. Server: a recommended Docker/Podman path, explicit prerequisites, versioned x86-64 and ARM64 images, persistent storage, reachable endpoint, invitation, health check, startup after reboot, backup, update and recovery.
  2. macOS: a packaged app such as a ZIP/DMG, supported systems/architectures, documented first launch and signing/notarization status, encrypted profile reopening and an update that preserves access. The initial development path must work without purchasing Apple Developer membership. Do not claim classic Keychain has the same device-binding guarantees as Data Protection Keychain; record the behavior actually verified.
  3. Android: an installable APK, supported Android versions/ABIs, clear installation permissions, a stable private release signing key and a tested update over the previous version. Debug signing is only for development.
  4. First use: create/join a test profile from the GUI using the relay data and invitation, show understandable errors, and link to recovery guidance.
  5. Verification: a person starting with a clean machine/phone follows only the published guide, installs, enrolls, restarts and updates successfully. Record the release, OS, architecture and blockers. Ordinary app installation must not require Flutter, Rust, Xcode or Android Studio.

Publish version identifiers, checksums and release notes with those artifacts. CI must verify what it packages. Private configuration stays outside the repository. These are delivery requirements, not claims that the packages or all acceptance runs already exist; see phase 3b.

On the administrator device, open Settings → Link another device → Show code. On the phone, choose Link with my other device → Scan the code, keep the whole QR inside the frame and hold steady. Compare the numbers and approve on the administrator device. A pasted or externally opened link also requires confirming the number on the phone. Linking preserves identity; it does not copy old history.

Contact QR codes, shared contact links and restored server details also use the preferred non-admin endpoint from the stored signature-verified list. Sync before creating a contact card after the operator changes the relay's addresses; cards can still be created offline from the last verified list. Existing shared links keep their original payload, so create and share a new link after such a change. Private-only realms remain supported: a public route must be configured and preferred by the operator before a code works outside its private network.

The linking code uses the preferred non-admin endpoint from the relay's verified signed list. If the administrator originally enrolled through a private network, the relay must now advertise a route reachable by the phone. A public WSS route should have the highest priority when phones will connect without the private network. Update the administrator app to pick up the corrected route selection; updating only the phone cannot change an already generated code.

Expired codes are replaced with Show a new code. Do not reuse an earlier link. The scanner shows a frame and activity indicator; if permission is refused or the camera is unavailable, paste the link instead. Physical-camera acceptance remains necessary even when automated linking and camera lifecycle tests pass. Update over the existing installation to preserve the profile and its key.

Manage your devices (available since 0.1.0+8)

Open Gestionar dispositivos in Ajustes. Compare the full device ID with the other device before revoking it. Only the administrator can revoke another device; the current device cannot revoke itself. A linked profile may show a partial inventory because it has not learned the other device IDs.

Sincronizar dispositivos resumes confirmed revocations after a network failure or restart. Until the relay accepts the manifest, the device may still connect; conversations also need to remove its MLS membership. The screen reports those stages separately. Revocation does not erase copies/history or prove that other participants received the notice. See the implementation and limits.

Update the relay from the same source revision when trying this feature. Older relays return 409 on repeated manifest publication; this relay accepts an identical retry and commits revocation with the manifest atomically.

Save and recover history (available since 0.1.0+9)

  1. In Ajustes, open Historial cifrado, acknowledge that this copy can reveal past messages and select Guardar historial cifrado. If the native dialog returns before the app regains focus, select Mostrar clave del archivo guardado after returning (fixed in 0.1.0+10). Save its key separately, for example in a password manager. The key disappears when you leave or switch apps; export again if you lose it. Review the count of files without a copy: pending downloads and legacy CLI files are not fetched.
  2. After losing a device, first restore the same identity with its latest kit and that kit's separate key. A history archive cannot recover your identity.
  3. Open Historial cifrado, choose the encrypted history file, enter its own key and select Importar como historial. Existing records stay unchanged. Imported attachments stay encrypted in the profile until Guardar copia del adjunto; the chosen destination may keep or back up that readable copy.
  4. Read the imported history on this separate screen. Importing neither resends messages nor rejoins old groups. Exchange the recovered device's route with a contact and explicitly start a new conversation for new messages.

These steps are included in the 0.1.0+10 candidates. Files are limited to 64 MiB and 10,000 records; see implementation limits.

When saving an identity kit, the equivalent action is Mostrar clave del kit guardado. A save completed in the background requires this explicit reveal after returning. Once back in the app, switching away again discards the pending key as well; export another copy if needed. Neither key is stored by Arveil.

If something goes wrong (source after 0.1.0+11)

Open Ajustes → Diagnóstico. It shows a short report (version, commit, system, language, the profile's stage and counts, and codes of recent failures) before anything leaves the device, and Guardar informe saves it as a text file you can attach to a support request. The report holds no keys, identifiers, routes, addresses, invitations, names or message content; read it before sharing it all the same.