This is where a LocalGhost box gets everything it downloads. Every file here is a copy of something already public, published as it came and with the terms it came under, and listed in a manifest signed with the same key that signs every deploy of this site. A box with this mirror, or a copy of it on a USB disk, never has to ask anyone else for its maps, its models or its engines.
It carries fifteen sets, thirteen of public data and engines and two of LocalGhost's own releases, the box's and the phone app's. A box needs about 12 GB of them to set itself up, and most of that is the chat model. Three sets are big and optional, the road extracts (79 GB), the elevation tiles (around 100 GB) and English Wikipedia (around 60 GB), and a box takes only the parts it asks for, one continent of roads or the tiles around the places it has been. The mirror started in September 2026 with four sets and grew to fifteen by October, the last two LocalGhost's own releases on 2 October, now at wisp 0.0.5. The manifest is the list that counts, and a set is on the mirror once its files are in MANIFEST.txt.
> 1. WHAT IT CARRIES
Files come in sets, and a box asks for a set by name. Each set sits in its own folder with a TERMS file per licence and a NOTICE.txt that says which file is under which terms and where it came from. Under each set's name is its size and how often it changes here. "Monthly" means upstream is checked once a month, "pinned" means the file only changes when I choose a new version, and "by hand" means a set too big to refresh on its own.
| Set | Files | Where it comes from | Terms |
|---|---|---|---|
| Maps and places | |||
| geo | admin1CodesASCII.txt admin2Codes.txt countryInfo.txt allCountries.zip |
The GeoNames data dumps, unmodified. The box uses them for reverse geocoding and to name the places a day happened in. | CC BY 4.0[1] |
| geo | world.geojson world-50m.geojson world-110m.geojson |
Natural Earth's country boundaries at three scales, renamed only (world.geojson is the 10m file, the other two carry their scale in the name). The base of the map. |
Public domain[2] |
| landpolygons | land-polygons-complete-4326.zip |
OpenStreetMap's land polygons from osmdata.openstreetmap.de, unmodified. The box cuts them into its map's coastline tiles. | ODbL 1.0[3] |
| roads | europe-latest.osm.pbf and the other seven continent extracts, named as Geofabrik names them |
OpenStreetMap's roads as Geofabrik's continent extracts, unmodified. A box only fetches the continents it's told to at setup, and cuts them into street tiles itself. | ODbL 1.0[3] |
| tz | timezones-with-oceans-1970.geojson.zip tzdata-latest.tar.gz |
The time zone boundaries of the world, oceans included, from timezone-boundary-builder, and IANA's time zone rules. A box uses them to cut a day at local midnight wherever the photo was taken. | ODbL 1.0 and public domain[10] |
| elevation | about 26,000 Copernicus_DSM_COG_30_*.tif tiles, tileList.txt, the licence |
The Copernicus DEM GLO-90, the height of the world's land every 90 metres, one tile per degree, unmodified. A box takes only the tiles it needs, for hillshading and the climb on a walk. | Copernicus DEM licence[11] |
| Engines a box builds | |||
| go | go1.27.1.linux-amd64.tar.gz |
The official Go release, checked against go.dev's published SHA-256 before it's mirrored. Setup installs it before any Go exists on the box, and a redeploy installs it before it builds when go.mod asks for a newer Go. Go 1.27.1 is the one wisp 0.0.5 is built with. |
BSD 3-Clause[4] |
| llama | llama.cpp-v0.5.0-7fe450e.tar.gz |
GitHub's source archive of llama.cpp release v0.5.0, the inference engine, fetched by commit so the URL can't move. Every box builds this one, and a new pin is a new file name. | MIT[5] |
| whisper | whisper.cpp-v1.9.4-927cfce.tar.gz |
GitHub's source archive of whisper.cpp release v1.9.4, the speech engine, pinned the same way as llama.cpp. A box builds it to transcribe the voice notes in its daily check-in. | MIT[8] |
| Models | |||
| models | gemma-4-12b-it-Q4_K_M.gguf mmproj-F16.gguf |
Gemma 4 12B instruct (Q4_K_M) and its vision projector, the build every box runs, as quantised and published by Unsloth. Unmodified and pinned by SHA-256. | Apache 2.0[6] |
| speech | ggml-large-v3-turbo-q5_0.bin |
OpenAI's Whisper large-v3-turbo, multilingual, in the whisper.cpp maintainers' ggml build quantised to q5_0. Unmodified and pinned by SHA-256. | MIT[9] |
| embeddings | embeddinggemma-300m-qat-Q8_0.gguf |
EmbeddingGemma 300M, Google's embedding model, for search over your own notes. Google's quantisation-aware Q8_0 checkpoint as converted to GGUF by the llama.cpp maintainers. Unmodified and pinned by SHA-256. | Gemma Terms of Use[7] |
| phone | gemma-4-E2B-it-qat-UD-Q2_K_XL.gguf |
Gemma 4 E2B instruct for the phone app, Unsloth's dynamic 2-bit quantisation of Google's quantisation-aware checkpoint. Unmodified and pinned by SHA-256. A phone fetches this set and nothing else. | Apache 2.0[6] |
| Knowledge | |||
| wikipedia | wikipedia_en_all_nopic.zim |
English Wikipedia without pictures, as Kiwix packages it, with its own full-text index, checked against the SHA-256 Kiwix publishes. A box searches it to answer questions without the web. | CC BY-SA 4.0[12] |
| Releases | |||
| server | localghost-server-0.0.5-linux-amd64.tar.gz RELEASE.txt NOTES.md |
LocalGhost's own releases, now wisp 0.0.5 of 5 October 2026, whose bundle sets up a new box on its own, copied from the GitHub release and pinned by the SHA-256 GitHub shows beside each file, the same hashes the release's own signed SHA256SUMS states. The phone offers this set as an update, and the box checks it like any other set before it runs it. |
MIT[13] |
| app | localghost-app-0.0.5.apk localghost-app-0.0.5.apk.asc APP.txt |
The Android app from the same release, signed with the app's own key (certificate SHA-256 3dcc5e35…f0cdf4), the site key's signature over it, and APP.txt with its hash, commit and certificate, copied from the GitHub release and pinned the same way. A phone installs it once by hand, and with it here a USB copy of the mirror sets up the phone as well as the box. |
MIT, Apache 2.0 for the Android libraries inside[13] |
The sizes are what a box would download if it took the whole set. Two of them, elevation and Wikipedia, are estimates until their first build is published, and I'll put the real figures here then.
> 2. WHY A MIRROR
Without it, setting up a box would mean fetching from nine different places on the day (GeoNames, GitHub, the OpenStreetMap data servers, Geofabrik, Google's Go downloads, Hugging Face, IANA, Kiwix and Amazon's open data buckets) and trusting each of them to be up, to serve the same bytes it served last week, and not to keep a record of who asked. Any one of them being slow or down would make setup slow or broken, and none of them owes a LocalGhost box anything.
The mirror doesn't change anything it carries. OpenStreetMap's land polygons are published as osmdata makes them, and each box cuts them into the tiles its map reads, which takes a few minutes and a couple of GB of RAM on the box. The road extracts work the same way, one continent at a time and only when the person setting up the box asks for streets, since Europe alone is 33 GB and cutting it takes hours. Keeping the processing on the box means the web server only ever proxies files it has checked and signed, and anyone can compare a file here with the upstream copy byte for byte.
Pinning matters more for code than for data. A box that builds llama.cpp from whatever master was that morning can end up running something different from the box next to it, so the mirror carries one release, named in the file along with its commit, and a new pin is a new file name that makes boxes rebuild. The model weights are pinned the same way, by SHA-256, so if a file ever changes upstream the publish stops instead of passing it on to a box. Where the upstream publishes a checksum (go.dev, a Hugging Face file page, Kiwix) the check is against that. GitHub publishes none for source archives, so the llama.cpp and whisper.cpp pins are the hash of the first copy the web server downloaded, read off the server and written into the config by hand.
It's also one less set of logs. This site runs with access logging off, the mirror included, so nothing here records the IP address of a box that set itself up. Fetching from each upstream directly would tell every one of them.
> 3. HOW A BOX CHECKS IT
Boxes fetch from here with tools/mirror_fetch.sh in the server repo, a set at a time, and install nothing unless every check passes.
- It downloads
MANIFEST.txtandMANIFEST.txt.ascand verifies the signature againsttools/mirror-key.asc, a copy of this site's key pinned in the server repo (so it's never fetched from the same place as the manifest), in a throwaway gpg home so nothing in your own keyring is involved. - It requires the mirror's own header on the manifest, so another manifest signed by the same key (a release, or a deploy of this site) can't be passed off as a mirror manifest.
- It refuses a build older than the last one that box used (the build name is kept in
/var/lib/ghost/mirror-build), so an old manifest with a perfectly valid signature can't be replayed to roll a box back. - It downloads each file under a temporary name, resuming if the connection drops, and only gives it its real name once its SHA-256 matches the manifest. In a big set it fetches only the files it was asked for, one continent or one tile.
If the mirror can't be reached or a check fails, setup says so and stops. The one way round that is an environment variable an operator has to type, and every file fetched that way is printed as not coming from a signed list. A box with no internet at all can read a copy of this mirror from a USB disk, with the same checks, and GHOST_MIRROR=<url> points a box at a copy you host yourself. sudo ./tools/update.sh on a running box reads the signed list first, then fetches only what changed. Set Up a Box goes through the whole setup in order, mirror included.
The box's own software arrives the same way, and the phone app is published beside it. The phone reads this manifest once a day on Wi-Fi and says when the server set holds a newer release ("wisp 0.0.5 is out"). DEPLOY downloads the set on the phone and hands it to the box, which runs the same mirror_fetch.sh over the local copy, so the signature is checked against the key the box already holds and every file against the manifest. The box keeps the previous build and goes back to it by itself if the first unlock onto the new one fails or a critical daemon keeps falling over in its first ten minutes. Releases are signed by the site key alone for now, the same key that signs this site and the rest of the mirror, and a separate offline release key is planned for a later wisp.[13]
> 4. HOW IT'S BUILT
The mirror is built by a script that sits next to the deploy script in the web repo and is never served. It runs on every deploy of this site, but it asks upstream for changes at most once a month, on the first deploy on or after the 1st. The other deploys that month publish only what the config added or changed (a new set, a new pin, an edited terms file) from the copies it already holds, and usually publish nothing at all, so a box sees a new build about once a month plus whenever a set is added. When it does ask, it downloads a file again only when upstream says it changed, stops if the Go tarball doesn't match go.dev's checksum, and leaves out any set whose terms file isn't finished.
The three big sets are refreshed only by hand. The road extracts change every day upstream, so they're taken about once a month. The elevation tiles are one line in the config that stands for every name in the tile list Copernicus publishes, and they don't change between Copernicus releases, so they're downloaded once. Wikipedia is the newest dump in Kiwix's directory at the time, checked against the SHA-256 Kiwix publishes beside it, and the older dump leaves the cache when a newer one arrives. A release in the server and app sets is pinned to the SHA-256 GitHub shows beside each of its files, and since a release builds reproducibly from its tag, anyone can cut the same version from the repo and compare the bytes.
A publish that changes something goes into a new folder named after the time it was built (20260924T120000Z, say). A folder never changes once it's published. Sets that didn't change are hard-linked from the previous build rather than copied, and the last two builds are kept, so a box halfway through a download when the next build lands still gets the bytes its manifest named. The manifest and its signature are written last and only go live once every file they name is already in place. When nothing changed upstream there's no new build at all.
/mirror/MANIFEST.txt # sha256 of every file, one per line /mirror/MANIFEST.txt.asc # signature, info@localghost.ai /mirror/<build>/<set>/<file> # the files /mirror/<build>/<set>/TERMS-<name>.txt # the terms a file is under /mirror/<build>/<set>/NOTICE.txt # which file, which terms, from where
> 5. CHECK IT YOURSELF
You don't need a box to check any of this. The key is the one published at /.well-known/pgp-key.asc, the same key that signs every deploy of this site, with fingerprint DCE9 A3D1 4EB4 6197 1DD5 F393 706E 4194 F08A 09A0. The publish script refuses to sign the mirror with any other key.
curl -sO https://www.localghost.ai/mirror/MANIFEST.txt
curl -sO https://www.localghost.ai/mirror/MANIFEST.txt.asc
curl -s https://www.localghost.ai/.well-known/pgp-key.asc | gpg --import
gpg --verify MANIFEST.txt.asc MANIFEST.txt
# then any file against its line in the manifest, the Go tarball for example
BUILD=$(sed -n 's/^# Build: //p' MANIFEST.txt)
curl -sO https://www.localghost.ai/mirror/$BUILD/go/go1.27.1.linux-amd64.tar.gz
grep " /$BUILD/go/go1.27.1.linux-amd64.tar.gz$" MANIFEST.txt | sed "s# /$BUILD/go/# #" | sha256sum -c
> 6. TERMS
Every file is published under the terms it came with, and those terms travel with it in the same folder. GeoNames data is CC BY 4.0.[1] Natural Earth is in the public domain.[2] The land polygons and the road extracts are unmodified copies of OpenStreetMap data, published by osmdata.openstreetmap.de and by Geofabrik, under the Open Database License, and the code a box cuts them with is in the LocalGhost repository.[3] Go is BSD 3-Clause[4], and llama.cpp and whisper.cpp are MIT.[5][8] OpenAI released Whisper's code and weights under MIT too, and since the model file carries no licence of its own, the full MIT text with OpenAI's copyright line travels beside it.[9] The time zone boundaries are OpenStreetMap data under the ODbL and IANA's time zone rules are in the public domain.[10] The Copernicus DEM is free to copy and redistribute under its own licence, which asks that everyone who receives it is bound by the same terms, so the licence itself is a file in the set.[11] Wikipedia's text is CC BY-SA 4.0, written by its contributors and packaged by Kiwix.[12] LocalGhost's own releases are MIT, with the licence beside them as TERMS-localghost-mit.txt, and the app also carries AndroidX, Compose and Kotlin under Apache 2.0 and llama.cpp under MIT, all named in its TERMS-localghost-app.txt.[13]
Google released Gemma 4 under Apache 2.0 in April 2026. The Gemma 4 files here, the 12B build every box runs and the E2B build for the phone, are Unsloth's GGUF quantisations of Google's weights, published under the same licence, and the mirror carries them byte for byte.[6] EmbeddingGemma is still under the Gemma Terms of Use (last modified 1 April 2026), which have to be handed to everyone who receives the model, in full, with its use restrictions intact, so the whole agreement sits beside the file as TERMS-gemma-terms.txt.[7] The publish leaves a model out until its terms file is complete.
Two things a box still fetches from elsewhere are the Go modules for its build, which come from proxy.golang.org and are pinned by go.sum, and its Debian packages (Postgres, Redis and the rest), which come from Debian's and upstream's apt repositories. Those are the gaps left between this mirror and a box that never needs anything else. If you maintain one of the sources above and want it handled differently, or you find a file here that doesn't match its manifest, email info@localghost.ai.
> REFERENCES
geo set's place names, publishes its data dumps under the Creative Commons Attribution 4.0 licence. Source for the GeoNames terms. geonames.org and creativecommons.org/licenses/by/4.0cmd/ghost-landtiles and bin/ghost-roadtiles in the LocalGhost repository. osmdata.openstreetmap.de/data/land-polygons.html, download.geofabrik.de, opendatacommons.org/licenses/odbl/1-0 and openstreetmap.org/copyrightvX.Y.Z releases the project recommends for downstream distribution as against its b-numbered builds. Source for the llama.cpp terms and the pin. github.com/ggml-org/llama.cpp and github.com/ggml-org/llama.cpp/releases/tag/v0.5.0tz set and its terms. github.com/evansiroky/timezone-boundary-builder and iana.org/time-zoneselevation set and its terms. registry.opendata.aws/copernicus-dem and dataspace.copernicus.eu (COP-DEM)wikipedia set and its terms. download.kiwix.org/zim/wikipedia and creativecommons.org/licenses/by-sa/4.0v0.0.5 (commit b5ef714) of 5 October 2026, MIT, built with Go 1.27.1, with the server bundle, the signed Android app (signing certificate SHA-256 3dcc5e35718036a26cf36373ee53e79f512bf02d97f7017052996d55ddf0cdf4) and its APP.txt, the source archive and a SHA256SUMS signed by the site key, and wisp 0.0.1's notes, which describe how the phone takes a release from this mirror, how the box checks and rolls it back, and how tools/cut_release.sh builds the same server bytes again from the tag. Both list the known gaps, the site key signing releases alone among them. Source for the server and app sets. github.com/LocalGhostDao/localghost/releases/tag/v0.0.5 and releases/tag/v0.0.1