Skip to content

Optional Mailbox Service

The mailbox is a separate stateful service for short-lived encrypted head hints. It does not run inside the stateless relay/AutoNAT process and does not store vault records, resources, revision manifests, or KDBX files.

Start from packaging/lattice-mailbox.toml, replace the example external addresses, and validate the result:

Terminal window
lattice mailbox config-check --config ./lattice-mailbox.toml
lattice mailbox peer-id

The server listens on TCP and QUIC port 4101 by default. Clients pin the printed Peer ID with one advertised address. Policy discovery is public; deposit, poll, and acknowledgement require scoped bearer capabilities.

The private observability listener defaults to 127.0.0.1:9475:

  • /healthz: the metrics HTTP task is alive.
  • /readyz: both libp2p listeners reached readiness.
  • /metrics: OpenMetrics request, response, error, swarm, and bandwidth data.

Metrics contain no peer IDs, mailbox IDs, capability IDs, or network addresses as labels. Keep this listener on loopback; production config validation rejects public and zero-port metrics addresses.

Each device prints its current epoch-scoped blinded mailbox ID without exposing the repository secret or device encryption key:

Terminal window
lattice vault mailbox-id personal

The mailbox operator issues two least-privilege capability classes while the service is running:

Terminal window
lattice mailbox issue <mailbox-id> receive --config ./lattice-mailbox.toml
lattice mailbox issue <mailbox-id> deposit --config ./lattice-mailbox.toml

receive permits poll and acknowledgement. Give it only to the recipient. deposit permits writes only and can be distributed to authorized senders. Both default to 90 days and accept --valid-days 1..365. Add --peer-id to bind a capability to one libp2p identity. The output is a bearer secret: do not put it in logs, shell history, world-readable files, or the mailbox config.

Membership epoch or recipient-key changes produce a new mailbox ID. Provision new capabilities for the new ID; clients must not treat an empty or stale old mailbox as evidence that no newer revision exists.

Pin the mailbox service by direct TCP or QUIC address and peer ID:

Terminal window
lattice vault mailbox set personal \
/dns4/mailbox.example.net/udp/4101/quic-v1/p2p/<mailbox-peer-id>

Install each issued capability through stdin so the bearer token is never an argument or plaintext config value:

Terminal window
lattice mailbox issue <local-mailbox-id> receive --config ./lattice-mailbox.toml \
| lattice vault mailbox capability personal
lattice mailbox issue <recipient-mailbox-id> deposit --config ./lattice-mailbox.toml \
| lattice vault mailbox capability personal

lattice vault mailbox status personal reports only the pinned server and capability counts. lattice vault mailbox clear personal removes the encrypted tokens before disabling the endpoint. Changing servers requires clearing first, so capabilities issued by one operator cannot silently follow another endpoint.

The daemon deposits only addresses that another device can attempt: concrete TCP/QUIC listeners, configured or AutoNAT-confirmed external addresses, and active relay circuit addresses. The default 0.0.0.0 listeners alone are not valid fetch hints. Configure a stable external address or relay for cross-network mailbox delivery; a concrete private address is sufficient for same-LAN use.

Capabilities are protected entries in credential-cache.kdbx; ordinary vault credential listing omits them. The running daemon retains only the cache master in the Linux process keyring or the local, non-synchronizing macOS login Keychain. The Linux value is process-local; the macOS value persists across LaunchAgent restart and can be removed explicitly with lattice vault credential forget while the daemon is stopped. Systemd credentials, password files, and interactive unlock remain the portable Unix paths for supplying the cache master. The mailbox bearer tokens themselves are never stored directly in an OS credential store or a plaintext file.

The daemon runs a mailbox cycle every 30 seconds. It deposits a signed, recipient-encrypted hint when the authenticated revision head changes and polls both current and retained epoch mailbox IDs. Capability failures are isolated, so one stale or revoked token cannot prevent another valid capability from running.

Outbound encrypted envelopes and completion markers are persisted atomically in the private data directory. A restart or lost response reuses the exact envelope ID, while changing the pinned mailbox server creates a separate outbox entry. The recipient leaves an unknown hint unacknowledged until its revision appears in the locally verified revision graph. Hints contribute only bounded peer addresses to normal membership-authenticated sync; they cannot apply records, advance rollback floors, or replace revision verification.

lattice status reports per-vault deposit, poll, received, and acknowledged counters plus a redacted mailbox error. A configured locked vault remains marked as mailbox-enabled before credential-cache unlock.

Terminal window
install -Dm0755 target/release/lattice ~/.local/bin/lattice
install -Dm0644 packaging/systemd/user/lattice-mailbox.service \
~/.config/systemd/user/lattice-mailbox.service
install -Dm0600 packaging/lattice-mailbox.toml \
~/.config/lattice-mailbox/config.toml
systemctl --user daemon-reload
systemctl --user enable --now lattice-mailbox.service

Verify the rootless service locally with curl --fail http://127.0.0.1:9475/readyz.

State, identity, the capability key, lock, and encrypted envelopes remain under the dedicated lattice-mailbox data directory with private permissions.

These are the privileged installation commands for operator review; Lattice does not run them automatically:

Terminal window
sudo install -Dm0755 target/release/lattice /usr/bin/lattice
sudo install -Dm0644 packaging/systemd/lattice.sysusers.conf \
/usr/lib/sysusers.d/lattice.conf
sudo install -Dm0644 packaging/systemd/lattice.tmpfiles.conf \
/usr/lib/tmpfiles.d/lattice.conf
sudo install -Dm0644 packaging/systemd/lattice-mailbox.service \
/etc/systemd/system/lattice-mailbox.service
sudo systemd-sysusers /usr/lib/sysusers.d/lattice.conf
sudo systemd-tmpfiles --create /usr/lib/tmpfiles.d/lattice.conf
sudo install -Dm0644 packaging/lattice-mailbox.toml \
/etc/lattice-mailbox/config.toml
sudo systemctl daemon-reload
sudo systemctl enable --now lattice-mailbox.service

Verify the system service locally with curl --fail http://127.0.0.1:9475/metrics.

The service runs as lattice-mailbox, not as the vault daemon or relay account. It has an empty capability bounding set and cannot read their private state.

The mailbox product mode is implemented end to end: protocol codec, dedicated server, policy discovery, durable deposit/poll/acknowledgement, operator provisioning, pinned client configuration, encrypted capability storage, automatic daemon delivery, restart-idempotent outbox state, and offline-device E2E coverage. Mailbox-only mode is notification and peer discovery; full catch-up while every user device is offline still requires the object-storage phase.