Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 11 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,29 +137,13 @@ iPhone-style dark look (status bar, battery glyph, grouped settings cards).
- **Local app platform** - scan local app manifests from `/sd/limitlezz/apps`,
`/sd/apps`, `/appfs/apps`, and simulator data dirs, then show accepted apps
across paged Home launcher screens and App Store detail shells. Home can open
accepted apps in a safe SDK 0.1 foreground shell that reads bounded display
metadata plus up to two bounded foreground actions from the entry file and
terminates on exit. Storage-enabled actions can increment a safe counter in
the app's scoped `data/` directory, unsupported action effects fail closed,
and apps with matching permissions can use read-only `{time}` / `{battery}`
tokens in foreground text. Loaded entry source plus app-controlled foreground
metadata are charged against a 704-byte resident runtime budget. SDK
apps with matching permissions can use read-only `{time}` / `{battery}`
tokens in foreground text, and apps with `notifications` can request a
feedback-service notification through a bounded `notify:` action effect. SDK
`api_version` and permission metadata are parsed fail-closed, with rejected
package diagnostics visible in Developer Mode. Apps that request `storage`
get a scoped package `data/` directory prepared with a 64 KB launch-time quota
guard, and the App Store detail screen can clear only that app's scoped data.
Script execution, richer API injection, downloads, and updates are still TODO.
tokens in foreground text. SDK `api_version` and permission metadata are
parsed fail-closed, with rejected package diagnostics visible in Developer
Mode. Apps that request `storage` get a scoped package `data/` directory
prepared with a 64 KB launch-time quota guard, and the App Store detail screen
can clear only that app's scoped data. The future network catalog now has a
bounded `index.json` schema validator and serial `app catalog status|test`
diagnostics. Script execution, richer API injection, catalog fetch, downloads,
and updates are still TODO.
accepted apps in a safe SDK 0.1 foreground shell with bounded actions,
permission-gated `{time}` / `{battery}` tokens, scoped storage, notification
effects, rejected-package diagnostics, and a 704-byte resident runtime budget.
The network catalog path now validates the documented `index.json` schema and
can refresh a bounded metadata cache with `app catalog fetch`; script
execution, richer API injection, package downloads, installs, and updates are
still TODO.
- **App flash (`appfs`)** - T-Deck builds mount the FAT `appfs` partition at
`/appfs` without formatting, expose it beside SD/local storage in Files, and
scan `/appfs/apps` even when the SD card is absent.
Expand Down Expand Up @@ -406,16 +390,10 @@ for local apps and read-only inspection when present.
Signal Scope, LoRa Chess, and APRS Bridge; CI validates that each package
stays inside the firmware's bounded manifest, permission, token, action, and
scoped-storage rules.
and scoped storage counters plus read-only `{time}` / `{battery}` tokens. The
foreground shell reports and enforces the 704-byte resident runtime metadata
budget; unsupported action effects launch-block instead of being ignored; the
static catalog remains a prototype (GET -> "..." -> OPEN).
unsupported action effects launch-block instead of being ignored; network
catalog schema validation exists, while fetch/download/install remains ahead;
the static catalog remains a prototype (GET -> "..." -> OPEN).
unsupported action effects launch-block instead of being ignored; the network
catalog has a CI-validated `index.json` schema, while fetch/download/install
are still prototype/future work (GET -> "..." -> OPEN).
- **Network app catalog** - CI validates the documented HTTPS `index.json`
schema, and serial `app catalog fetch|status|clear|test` can refresh and
inspect a bounded metadata cache. Package download/install/update remains
future work, so the static catalog UI is still prototype-only.
- **Contacts / detail** — unified directory with network dots; detail page
with Message (jumps into the bound conversation) and spec table.
- **Settings** — airtime scheduler bar that rebalances live when the
Expand Down
54 changes: 36 additions & 18 deletions docs/tdeck-app-catalog-schema.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
# T-Deck App Catalog Schema

This is the first Network App Store increment. It defines and validates the
future `index.json` shape, but it does not fetch, download, install, update, or
uninstall packages yet.
`index.json` shape and can refresh a bounded catalog cache over Wi-Fi, but it
does not download, install, update, or uninstall packages yet.

Catalog indexes are expected at:
Catalog indexes can be loaded from:

- `/sd/limitlezz/catalog/index.json`
- `/appfs/catalog/index.json`
- the refreshed cache file, `app_catalog.json`, written by `app catalog fetch`

The index must fit in `4096` bytes and use this top-level shape:

```json
{
"schema": "limitlezz.app_catalog.v1",
"updated": "2026-06-18T00:00:00Z",
"schema": "limitlezz.app.catalog.v1",
"generated_at": "2026-06-18T00:00:00Z",
"apps": []
}
```
Expand All @@ -27,16 +28,28 @@ Each app entry is bounded and fail-closed:
"name": "Weather Mesh",
"version": "0.1.0",
"author": "Limitless",
"summary": "Local weather dashboard",
"description": "Local weather reports",
"icon": "weather",
"hue": 48,
"api_version": "0.1",
"compatibility": "tdeck",
"permissions": ["display", "network_wifi"],
"download_url": "https://apps.example.invalid/weather.mesh.zip",
"sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
"size": 32768,
"screenshots": ["https://apps.example.invalid/weather.bmp"]
"package_url": "https://apps.example.invalid/weather.mesh.zip",
"package_sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
"package_bytes": 32768,
"compatibility": {
"min_os": "0.95.0",
"api_versions": ["0.1"],
"targets": ["tdeck", "sim"]
},
"screenshots": [
{
"url": "https://apps.example.invalid/weather.bmp",
"width": 320,
"height": 240,
"sha256": "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789"
}
]
}
```

Expand All @@ -45,10 +58,12 @@ Validation rules:
- `id` uses the same safe token rules as local app manifests.
- `api_version` must be supported by the local SDK compatibility gate.
- `permissions` must use the existing allowlist.
- `download_url` and optional `screenshots` must be `http://` or `https://`
URLs without whitespace or control characters.
- `sha256` must be exactly 64 hex characters.
- `size` must be nonzero and no more than `2 MB` for this first package path.
- `package_url` and screenshot URLs must be HTTPS in published catalogs.
- `package_sha256` must be exactly 64 lowercase hex characters.
- `package_bytes` must be nonzero and no more than `2 MB` for this first
package path.
- `compatibility.api_versions` must include the entry's `api_version`, and
`compatibility.targets` must include `tdeck` or `sim`.
- `hue`, if present, must be `-1` or `0..359`.
- The catalog can list up to `24` apps.

Expand All @@ -57,9 +72,12 @@ Serial diagnostics:
```text
app catalog status
app catalog test
app catalog fetch https://example.invalid/limitlezz/catalog/index.json
app catalog clear
```

`app catalog status` validates a cached index if one exists and otherwise
reports that no cached catalog is present. `app catalog test` runs a built-in
valid/invalid schema selftest so hardware smoke can prove the parser without
requiring Wi-Fi or SD setup.
`app catalog fetch` downloads bounded JSON over Wi-Fi, validates it, and only
then writes the refreshed cache. `app catalog status` validates that refreshed
cache first, then legacy `/catalog/index.json` files if present. `app catalog
test` runs a built-in valid/invalid schema selftest so hardware smoke can prove
the parser without requiring Wi-Fi or SD setup.
7 changes: 1 addition & 6 deletions docs/tdeck-feature-inventory.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,7 @@ Status labels:
| Local app scanner | Partial | `lz_store_scan_apps` scans `/sd/limitlezz/apps`, `/sd/apps`, `/appfs/apps`, simulator `<datadir>/apps`, and simulator `<datadir>/appfs/apps`; accepted apps appear in the paged Home launcher and App Store; rejected packages are exposed through Developer Mode diagnostics; simulator selftest covers appfs-only discovery, valid metadata, storage sandbox prep, quota usage, clear-data behavior, foreground launch metadata/actions, runtime memory-budget enforcement, storage counter persistence, read-only time/battery token gating, unsupported action-effect blocking, oversized entry blocking, and rejected unsafe packages | Add script execution, richer app lifecycle hooks, and broader user-facing data actions once memory profiling picks a runtime. |
| App permissions | Partial | Local manifests can declare allowlisted SDK namespaces (`display`, `input`, `storage`, mesh, time, battery, notifications, Wi-Fi); unknown permission names reject the package before Home/App Store; `storage` prepares a scoped package `data/` directory with a 64 KB launch-time quota guard, SDK action counters require both `input` and `storage`, and `{time}`/`{battery}` tokens require matching `system_time`/`battery` permission before launch | Implement least-privilege API injection when the runtime is selected. |
| Local app scanner | Partial | `lz_store_scan_apps` scans `/sd/limitlezz/apps`, `/sd/apps`, `/appfs/apps`, simulator `<datadir>/apps`, and simulator `<datadir>/appfs/apps`; accepted apps appear in the paged Home launcher and App Store; rejected packages are exposed through Developer Mode diagnostics; simulator selftest covers appfs-only discovery, valid metadata, storage sandbox prep, quota usage, clear-data behavior, foreground launch metadata/actions, storage counter persistence, bounded launch/action fault snapshots, read-only time/battery token gating, unsupported action-effect blocking, oversized entry blocking, and rejected unsafe packages | Add script execution, richer app lifecycle hooks, and broader user-facing data actions once memory profiling picks a runtime. |
| Network app catalog | Planned | Wi-Fi service notes; design spec | Fetch `index.json`, verify TLS/metadata, cache results. |
| Network app catalog | Partial | `docs/tdeck-app-catalog-schema.md`; bounded `limitlezz.app_catalog.v1` validator plus serial `app catalog status\|test` diagnostics | Fetch `index.json` over Wi-Fi, verify TLS/source metadata, cache results, and feed validated entries into App Store state. |
| Network app catalog | Planned/Partial | Wi-Fi service notes; design spec; Settings persists an App source selector with Official, Community, and Local only modes, and App Store reflects the selected source while keeping catalog examples hidden in local-only mode. | Fetch `index.json`, verify TLS/metadata, cache results. |
| Network app catalog | Planned/Partial | Wi-Fi service notes; bounded catalog JSON cache APIs | Fetch `index.json`, verify TLS/metadata, parse schema, and render cached results. |
| Network app catalog | Planned/Partial | Wi-Fi service notes; bounded T-Deck HTTP/HTTPS fetch transport foundation | Fetch `index.json` into the parser/cache flow, verify TLS/metadata, and render cached results. |
| Network app catalog | Partial | `docs/tdeck-network-app-catalog.md`, `docs/examples/app-catalog-index.json`, and `scripts/validate_app_catalog.py` define and CI-validate the first HTTPS `index.json` contract with SDK compatibility, permissions, package hash/size, and screenshots | Fetch `index.json` over Wi-Fi, verify TLS/metadata on-device, and cache results. |
| Network app catalog | Partial | `docs/tdeck-network-app-catalog.md`, `docs/examples/app-catalog-index.json`, `scripts/validate_app_catalog.py`, firmware validator/cache APIs, T-Deck HTTP/HTTPS fetch transport, and serial `app catalog fetch\|status\|clear\|test` diagnostics | Feed refreshed catalog metadata into App Store browsing, pin/verify production catalog TLS/source metadata, then download/install/update packages. |
| App download/install/update | Planned | App Store prototype only | SHA256 verify, extract, version updates, rollback failed installs. |
| App download/install/update | Planned/Partial | App Store prototype plus bounded package-file SHA256 helper | Wire the verifier into download/staging, then extract, version updates, and rollback failed installs. |
| Optional map app | Planned | Store data includes maps; maintainer notes prefer maps as optional | Keep maps out of the base firmware. |
Expand Down
20 changes: 11 additions & 9 deletions docs/tdeck-firmware-roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -364,16 +364,18 @@ Goal: let users install and update apps from a repository.

Deliverables:

- Define catalog `index.json` schema: app id, name, version, author, description, icon id/color, permissions, download URL, SHA256, size, compatibility, screenshots if desired. Implemented: a bounded `limitlezz.app_catalog.v1` validator rejects unsafe IDs, unsupported permissions/SDK versions, non-HTTP package URLs, bad SHA256 values, oversize packages, and malformed optional screenshots; serial `app catalog status|test` exposes the result without requiring Wi-Fi.
- Define catalog `index.json` schema: app id, name, version, author, description, icon id/color, permissions, download URL, SHA256, size, compatibility, screenshots if desired. Implemented in `docs/tdeck-network-app-catalog.md` with `docs/examples/app-catalog-index.json`, `scripts/validate_app_catalog.py`, and a Firmware CI validation step.
- Fetch catalog over Wi-Fi.
- Cache catalog for offline browsing. Initial implementation: bounded atomic
catalog JSON cache save/load/clear service APIs with native simulator coverage.
- Define catalog `index.json` schema: app id, name, version, author, description, icon id/color, permissions, download URL, SHA256, size, compatibility, screenshots if desired.
- Define catalog `index.json` schema: app id, name, version, author,
description, icon id/color, permissions, package URL, SHA256, size,
compatibility, screenshots if desired. Implemented in
`docs/tdeck-network-app-catalog.md` with `docs/examples/app-catalog-index.json`,
`scripts/validate_app_catalog.py`, Firmware CI validation, and matching
firmware validation for `limitlezz.app.catalog.v1`.
- Fetch catalog over Wi-Fi. Initial implementation: bounded T-Deck HTTP/HTTPS
catalog fetch transport gated on connected Wi-Fi, with native simulator stub
coverage for URL/buffer errors.
- Cache catalog for offline browsing.
catalog fetch transport gated on connected Wi-Fi, plus serial
`app catalog fetch <url>` / `refresh <url>`.
- Cache catalog for offline browsing. Implemented: validated refresh writes a
bounded atomic metadata cache, `app catalog status` validates that refreshed
cache first, and `app catalog clear` removes it.
- Download app zip/package.
- Verify SHA256 before install. Initial foundation: reusable package-file SHA256
hashing and expected-hash verification helpers with native simulator coverage.
Expand Down
17 changes: 15 additions & 2 deletions docs/tdeck-network-app-catalog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

This is the V0.95/V0.96 bridge contract for turning the App Store from local
manifest scanning into a downloadable catalog. It defines the first
`index.json` shape only; firmware download, install, update, and rollback are
still later work.
`index.json` shape and the firmware can refresh a validated cache over Wi-Fi;
package download, install, update, and rollback are still later work.

The catalog is intentionally stricter than a web store feed. Every app entry
must expose enough metadata for the T-Deck to show permissions, check SDK
Expand Down Expand Up @@ -94,3 +94,16 @@ python scripts/validate_app_catalog.py docs/examples/app-catalog-index.json

Firmware CI runs the same validator against the checked-in example catalog so
schema drift is caught with the normal simulator and T-Deck build gates.

On device, the serial console exposes the first refresh path:

```text
app catalog fetch https://example.invalid/limitlezz/catalog/index.json
app catalog status
app catalog clear
```

The refresh command fetches a bounded JSON body, runs the same fail-closed
firmware validator, and saves the cache only after validation succeeds. The
cache is for browsing metadata; package download and installation remain future
work.
Loading