Skip to content

LatticeNetEvery privileged change has a visible plan.

A self-hosted control plane for small fleets. Nodes dial out, never in. Firewall, DNS, WireGuard, proxy-core and subscriptions all move through the same review gate — and the approval hashes what you were actually shown.

Architecture

Three layers, one rule: nothing reaches a host without a plan someone approved.

The server is the only component that holds state. Nodes run an agent that opens outbound connections and leases work. Plugins extend the server, but they are verified before they load and hold no durable storage of their own.

Architecture
TLS terminates here/sub/…Operatorbrowser sessionProxy clientno sessionReverse proxyTLSlattice-server127.0.0.1:8088Dashboardserved by the serverstate.jsonsealed at reststate-hot.dbrecord-level writesaudit WALappend-only trailmaster.keyback this up
reviewed pathordinary traffictrust boundarydeliberately not wired
The server is a container with a bind-mounted state directory. It listens on loopback and is reached through a reverse proxy that terminates TLS — the only surface deliberately exposed without a session is the public subscription route.

First install

Bind to loopback, terminate TLS at a proxy you trust, then add privileges deliberately.

The recommended start is a server on 127.0.0.1:8088 behind a reverse proxy, TOTP on the first admin, and one node-agent enrolled with host mutation still switched off. Execution is opt-in per node, so an enrolled agent that nobody has authorised can report but cannot change anything.

State lives in a bind-mounted directory: the image carries none of it. Back up state.json, the hot store, the audit WAL and master.key together — losing the key makes stored credentials unrecoverable.

lattice — first run
$ git clone https://github.com/LatticeNet/lattice.git
$ cd lattice/compose
$ cp .env.example .env
$ $EDITOR .env
$ mkdir -p data plugins
$ docker compose up -d

The bootstrap admin password is printed once, to the container log.

Control loop

The gate is a hash of the plan you read, not of the plan the server meant.

Firewall rules, DNS records, WireGuard topology, proxy-core deployment and agent updates all travel the same path. Only one stage stops for a human, and it is the same stage every time.

Control loop
  1. 01

    Configure

    Intent is set in the dashboard or through the API.

    server
  2. 02

    Render

    The server builds a review plan with secrets stripped.

    server
  3. 03

    Approve human gate

    The dashboard sends the SHA-256 of the plan actually shown.

    server
  4. 04

    Queue

    The agent leases a bounded task over outbound HTTPS.

    node
  5. 05

    Apply

    The node validates artifacts before it mutates anything.

    node
  6. 06

    Audit

    Result and actor trail land in the server log.

    server
The approval stage hashes what the operator was shown, not what the server intended to do — so a plan that changed between render and approval fails the comparison instead of applying quietly.

Status

What is running, at which version, and what is deliberately not built yet.

Lattice is early. It is usable for private fleets with a hardened perimeter, and it is honest about the parts that are not finished — those sit in the same table as the parts that are.

What is live
ComponentStateVersionWhat it does
lattice-serverprereleasealpha-0.2.2a6The control plane. Holds all state; serves the dashboard.
lattice-agentstablev0.3.3The host binary. Dials out, leases tasks, applies and reports.
lattice-sdkstablev0.2.18Shared models and the plugin protocol. Versioned contract.
@latticenet/plugin-bridgeprereleasev0.1.0-alpha.1The sandboxed postMessage channel a plugin UI uses to reach its own backend.
Sub-Storelatticenet.sub-storelive0.5.0-alpha.1A native subscription platform: store, fetch, process, publish.
VPN Corelatticenet.vpn-corelive0.8.0-alpha.7VLESS + REALITY profiles, lines, users, and usage reporting.
NetGuardlatticenet.netguardlive0.1.0-alpha.9Reviewed firewall zones, groups and bindings with an adopt path.
WireGuardlatticenet.wireguardlive0.1.0-alpha.9WireGuard topology and device peers, planned before applied.
Arbitrary community plugin executionnot enabledThe bounded runner is for trusted system plugins. Running unreviewed third-party code against host capabilities is not a switch that is off — it is a design that is not finished.
Remote marketplace installnot enabledThe plugin index is a read-only draft catalogue. Installing from it is a separate trust decision that still belongs to the operator, by hand.
Versions come from one file the release check verifies against the GitHub releases API, so a stale number here fails the build rather than quietly misinforming a reader.

Plugin trust

A bundle is refused unless its bytes and its publisher both check out.

The capability list lives inside the signed payload. A plugin cannot quietly ask for more privilege than it was signed for, because asking for more changes the signature.

Plugin trust chain
Because the capability list lives inside the signed payload, a plugin cannot quietly acquire a new privilege: changing what it asks for changes the signature, and an unsigned change fails at the publisher check.

Security-first, self-hosted, and release-gated.