App Store & Catalog
The ThistleOS app store is decentralized — anyone can host a catalog. The device fetches JSON over HTTPS, filters entries by chip architecture and detected hardware components, verifies SHA-256 checksums and Ed25519 signatures, then downloads and installs entries onto the SD card.
✎ Edit on GitHubtk_appstore) built on thistle-tk. It shows ratings, download counts, categories, and changelogs. Component-level driver detection ensures only compatible entries are offered for your hardware.
Catalog format
A catalog is a single JSON file. The top-level object contains metadata and an array of entries:
{
"catalog_version": 2,
"name": "ThistleOS Official",
"url": "https://wan0net.github.io/thistle-apps/catalog.json",
"updated": "2026-03-22",
"entries": [
{
"id": "com.example.chat",
"name": "LoRa Chat",
"version": "1.2.0",
"type": "app",
"arch": ["xtensa", "riscv"],
"url": "https://example.com/apps/chat-1.2.0.app.elf",
"sha256": "a3f1b29c...",
"sig_url": "https://example.com/apps/chat-1.2.0.app.elf.sig",
"size_bytes": 48320,
"permissions": ["radio", "ipc"],
"description": "Send and receive LoRa messages with nearby devices.",
"author": "Example Dev",
"min_os": "0.2.0",
"category": "communication",
"rating": 4.7,
"download_count": 1204,
"changelog": "v1.2.0: Group chat support, RSSI display",
"compatible_boards": ["tdeck_pro", "tdeck", "t3s3"],
"detection": {
"requires_i2c": [],
"requires_hal": ["radio"]
}
}
]
}
Entry field reference
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | Reverse-DNS identifier. Must be globally unique. |
name | string | yes | Human-readable display name. |
version | string | yes | Semantic version (MAJOR.MINOR.PATCH). |
type | string | yes | "app", "driver", or "firmware". |
url | string | yes | HTTPS URL to the binary. |
sha256 | string | yes | Hex SHA-256 of the binary at url. |
sig_url | string | no | URL to the .sig file (Ed25519 signature). |
size_bytes | number | no | Download size hint for progress display. |
permissions | array | no | Permission strings the app declares it needs. |
description | string | no | Short description shown in the store UI. |
author | string | no | Author name or organization. |
min_os | string | no | Minimum ThistleOS version required. |
arch | array | no | Target architectures: "xtensa", "riscv". Omit = all. |
category | string | no | App category for store browsing (e.g. "communication"). |
rating | number | no | Average star rating (0.0–5.0). |
download_count | number | no | Total install count shown in the store UI. |
changelog | string | no | Short description of changes in this version. |
compatible_boards | array | no | Board IDs this entry is compatible with. Used by Recovery for driver matching. |
detection | object | no | Component-level hardware detection hints. requires_i2c: I2C addresses; requires_hal: HAL interface names. |
Entry types
app — A .app.elf file. Downloaded to /sdcard/apps/. The kernel's ELF loader runs it. Must implement thistle_app_t.
driver — A .drv.elf file. Downloaded to /sdcard/drivers/. Loaded on next boot, before app loading. Must export driver_init().
firmware — A full .bin firmware image. Downloaded to /sdcard/update/thistle_os.bin. The OTA subsystem picks it up on next boot and flashes it to ota_1. This is how ThistleOS updates itself over the air.
Hosting your own catalog
A catalog is just a static JSON file served over HTTPS. GitHub Pages is the easiest option:
- Create a GitHub repo (e.g.,
myname/thistle-apps) - Enable GitHub Pages from the
docs/directory or root - Add your
catalog.jsonand binary files to the repo - Your catalog URL is
https://myname.github.io/thistle-apps/catalog.json
The device will periodically fetch this URL (configurable in /sdcard/config/system.json) and check for newer versions of installed entries.
chat-1.2.0.app.elf) so that multiple versions can coexist in the same directory.
Catalog caching
The device caches the last-fetched catalog on the SD card at /sdcard/data/catalog_cache.json. This allows the app store UI to show available apps even when WiFi is not connected. The cache is invalidated when the device successfully fetches a newer version (determined by the updated field).
Download and verification flow
Publishing apps: step by step
- Build your
.app.elf— see Building Apps - Compute the SHA-256:
sha256sum my_app.app.elf - Sign the binary:
thistle-sign --key dev_key.pem my_app.app.elf— producesmy_app.app.elf.sig - Upload both files to your HTTPS host (GitHub Pages, S3, Cloudflare Pages, etc.)
- Add an entry to your
catalog.jsonwith the correct URL and SHA-256 - Commit and push — devices will find the new entry on their next catalog refresh
Firmware updates via the app store
Firmware updates work exactly like app downloads, but with "type": "firmware" and a .bin extension. The update flow:
- User opens App Store → sees "ThistleOS vX.Y.Z available"
- User taps "Update" — firmware binary downloaded and verified
- Binary written to
/sdcard/update/thistle_os.bin - Device reboots — Recovery OS checks SD card, finds the binary, flashes to
ota_1 - Device boots into new firmware —
ota_mark_valid()called to confirm success
If the firmware entry's sig_url is present and the signature does not verify, the download is rejected before the file is written to the SD card.
Adding the official catalog
The official ThistleOS catalog is pre-configured in /sdcard/config/system.json:
{
"app_store": {
"catalogs": [
"https://wan0net.github.io/thistle-apps/catalog.json"
],
"refresh_interval_hours": 12
}
}
To add a third-party catalog, append its URL to the catalogs array. The device merges entries from all catalogs. If two catalogs provide the same id, the entry with the higher version wins.