A small, fast gemtext browser and publisher for Urbit.
Think Gemini, but the pages live on the Urbit network: every page is addressed
as urb://~ship/path and travels peer-to-peer between ships — no DNS, no web
server, no host in the middle. Native on Android, Linux, macOS, and Windows.
lattice has two parts:
desk/— the%latticeGall agent. It publishes the gemtext files in your ship's/pubdirectory to the Urbit namespace, serves them to other ships over remote scry, and follows remote files so you get notified when they change.app/— a Kotlin Multiplatform (Compose) browser/editor that talks to your ship over its local HTTP API.
You run the desk on your ship and point the app at it.
- Browse
urb://— fetch and read gemtext published by any ship, peer-to-peer over Urbit's remote scry. Browser-style tabs (Ctrl+T), bookmarks, and history. - Publish — anything you drop in
/pub/*.gmion your ship is instantly readable by anyone asurb://~you/that/path. Edit it from inside the app. - Editor — a built-in gemtext editor for your pages, with optional vim keybindings (off by default — it edits like a normal textarea otherwise).
- Follow & subscribe — follow ships to discover what they publish; subscribe to a specific file and get a live notification the moment it changes (pushed over an Eyre SSE channel).
- Discovery — find other lattice publishers among your
%contactsvia a small published manifest. - Copy to your ship — like a bookmark, but real: copy a remote file onto your own ship at a path of your choosing.
- Fully themeable — colors and fonts are configurable; ships with several built-in themes (Lattice Dark/Light and more).
Build the desk with build.sh and commit it to your ship. It
vendors the standard kernel deps via peru
(so make sure peru --version works), assembles a complete desk under dist/,
and — with -p — copies it into a mounted desk:
|new-desk %lattice
|mount %lattice
./build.sh -p ~/path/to/your-ship/lattice|commit %lattice
|install our %lattice
Once installed, the agent binds an HTTP endpoint at /apps/lattice and begins
publishing whatever is in /pub.
Letting others install it from your ship. The desk ships a docket, so you can distribute it over the network:
:treaty|publish %lattice
Anyone can then install it with |install ~your-ship %lattice (or |ally ~your-ship and find it in the App Store search). It shows up as a "Lattice"
tile in their Landscape; the tile links to this repo (the real UI is the
native app).
Endpoints are access-controlled: only your own ship can poke or subscribe to the agent, and the HTTP API requires a valid ship session. Anything you put in
/pub/*.gmiis public by design (that's the point — it's a publishing tool); nothing else leaves your ship.
Grab your platform from the latest release:
| Platform | File | How to install |
|---|---|---|
| Android | lattice-X.Y.Z.apk |
Tap to install; you may need to allow "Install unknown apps". Android 8+ (API 26). |
| Linux (any) | lattice-x86_64.AppImage |
chmod +x lattice-x86_64.AppImage && ./lattice-x86_64.AppImage. Needs FUSE 2 (default on most desktops). |
| Debian / Ubuntu | lattice_*_amd64.deb |
sudo apt install ./lattice_*_amd64.deb |
| macOS | lattice-*.dmg |
Open the DMG, drag lattice to Applications. First launch: right-click → Open → Open (unsigned, so Gatekeeper blocks a plain double-click). |
| Windows | lattice-*.msi |
Double-click. SmartScreen may warn — "More info" → "Run anyway". |
Desktop builds bundle their own JRE, so you don't need Java installed.
Open the app, enter your ship's URL and +code, and you're browsing. New to
Urbit? urbit.org/overview/running-urbit
walks you through booting a ship.
Connecting to a remote ship: lattice refuses to send your
+codeor session cookie in cleartext, so a non-local ship must be reached overhttps(loopbackhttpis fine for a ship on the same machine or a tunnel).
- Not a host. Bring your own ship — yours, a friend's, or a hosted one.
- Not the HTTP web. Pages are Urbit-native (
urb://~ship/path) and move between ships over remote scry, not over DNS/HTTP. - Not on the app stores. Sideload the APK / installers from GitHub Releases.
- Desktop builds are unsigned for now — your OS will warn on first launch.
Gradle lives in app/ (the repo root also holds the Urbit desk/). A
full JDK 17 is required — note that some distros ship java-17-openjdk as a
JRE without javac; JDK 21 also works.
cd app
./gradlew :composeApp:run # run the desktop app
./gradlew :composeApp:assembleDebug # debug APK
./gradlew :composeApp:assembleRelease # release APK (signed if keystore set)
./gradlew :composeApp:packageReleaseDeb # desktop installer (host OS only)
# Portable Linux AppImage (from the repo root):
./scripts/build-appimage.shThe Hoon agent has unit tests under desk/tests/; the app has a
JVM test suite (./gradlew :composeApp:desktopTest). CI runs both on every PR.
Tagging v* triggers .github/workflows/release.yml, which builds the desktop
installers (.deb/.dmg/.msi/.AppImage) and — when signing secrets are set
— the Android APK, then publishes a GitHub Release. See RELEASE.md.
desk/ the %lattice Gall agent (app/ lib/ sur/ mar/ tests/)
app/ Kotlin Multiplatform Compose app (Android + desktop)
web/ marketing pages (HTML + a gemtext page, fittingly)
scripts/ build helpers
PolyForm Noncommercial 1.0.0. Free to use, modify, and share for any noncommercial purpose; commercial use requires a separate license.
© lattice — built by ~nisfeb. PolyForm Noncommercial 1.0.0 licensed.