Apps from the SD card: Lua Apps with an API to our services and widgets #13

Open
opened 2026-10-05 09:59:35 +00:00 by twisla · 0 comments
Owner

Idea

Run extra Apps from the SD card, written in Lua. Each one appears in the Launcher next to the built-in Apps. Through a documented API it can use the firmware's services (storage, clock, network, GNSS…) and widgets (lists, dialogs, Toasts, text entry, the canvas). New Apps no longer need a firmware build.

Why

  • Small tools (a calculator, a timer, a dice roller, a quick HTTP or Gemini check, a game) shouldn't each cost a firmware release and flash space.
  • Others can write Apps without the toolchain.
  • It fits the device: a pocket computer you can program from its own keyboard.

What's known

  • The language.

    • Lua 5.4 is the obvious choice: small (around 100-150 KB of flash with the base libraries), C-friendly, and well proven on microcontrollers.
    • Alternatives:
      • Berry: made for microcontrollers, used by Tasmota, and lighter on RAM.
      • MicroPython: much bigger.
      • WebAssembly (wasm3): any language, but a heavier API to bind.
  • Memory is the main risk, and Lua makes it controllable.

    • lua_newstate takes an allocator, so each App can get a budget, for example 24 KB. The allocator refuses anything that would push the heap below the Q86 floors.
    • When it refuses, the result is a Lua out-of-memory error, not a crash.
    • Only one Lua App runs at a time, and its state is freed when you leave it, unless it has to run in the background.
  • Runaway code.

    • A Lua instruction-count hook (lua_sethook) stops a callback that takes too long, before the main loop's 5 s watchdog fires.
    • Errors are caught with pcall and shown, with the line number, on a screen like Safe Mode's, not as a reboot.
  • How it fits the App model.

    • The firmware's App interface (onEnter, onKey, update, draw) maps to Lua functions.
    • A LuaApp adapter, written in C++, hosts one script and forwards the calls.
    • Drawing goes through the shared canvas and the theme (#10), so Lua Apps look native.
  • The API, by module (to be decided):

    • ui: text, shapes and theme colours on the canvas; lists, dialogs, Toasts, text entry.
    • keys.
    • storage: files limited to the App's own folder (/apps/<name>/), through StorageService's task.
    • settings: per App, in its own NVS namespace or a file.
    • clock.
    • net: HTTP(S) and Gemini fetches through the services, with their floors.
    • gnss: position, behind a permission.
    • irc: send and receive, maybe.
    • sys: version, heap, battery.

    The API needs a version number, and an App says which version it needs.

  • The sandbox and permissions.

    • Lua's io, os and debug libraries aren't loaded. Everything goes through our API.
    • Secrets are never reachable: Wi-Fi passwords, the debug token, the Gitea token (#4), the VPN key (#8), the SSH keys (#2).
    • A manifest declares what an App needs (network, position, IRC), and the user approves that the first time it runs.
  • Packaging.

    • A folder per App: /apps/<name>/ holds app.toml or manifest.lua (name, version, API version, permissions), main.lua, and an icon for the Launcher tiles (#9).
    • Apps can be copied in with the USB drive (#1), the file manager (#3), or the Debug Console's put.
  • Development. In Debug Builds, a Lua REPL over the Debug Console would make writing Apps fast: edit on a computer, push, reload, all without unplugging. That's the same over-the-air spirit as the OTA work.

  • Flash. About 150 KB for Lua and the bindings. The firmware is 1.71 MB of 3.3 MB, so there's room.

Questions for the design round

  1. Lua 5.4, Berry or something else? Measure flash and RAM for "hello world" and for a list App.
  2. What memory budget does an App get? A fixed one, or whatever is above the floors?
  3. Which API modules come first? Probably ui, keys, storage and clock, with network later.
  4. How do permissions work: a manifest plus a prompt on first run, or a trust-all switch for development?
  5. Can Lua Apps run in the background (timers, network), or only while they're on screen?
  6. Should Apps be signed, like Update Files, or is any App on the card trusted because the card is yours?
  7. How are API changes handled: semantic versioning, and refusing Apps that need a newer API?
  8. Where are the API docs: generated from the bindings, and published on the website (#12)?
  9. Should there be a REPL App on the device itself, not only over the console?

Related

lib/core/src/app.h and lib/core/src/app_manager.h (the App interface), src/services/storage_service.cpp, src/ui/theme.h, docs/milestones/G1.md (Q86 floors), and #1, #2, #3, #4, #8, #9, #10, #12.

## Idea Run extra Apps from the SD card, written in Lua. Each one appears in the Launcher next to the built-in Apps. Through a documented API it can use the firmware's services (storage, clock, network, GNSS…) and widgets (lists, dialogs, Toasts, text entry, the canvas). New Apps no longer need a firmware build. ## Why - Small tools (a calculator, a timer, a dice roller, a quick HTTP or Gemini check, a game) shouldn't each cost a firmware release and flash space. - Others can write Apps without the toolchain. - It fits the device: a pocket computer you can program from its own keyboard. ## What's known - **The language.** - Lua 5.4 is the obvious choice: small (around 100-150 KB of flash with the base libraries), C-friendly, and well proven on microcontrollers. - Alternatives: - Berry: made for microcontrollers, used by Tasmota, and lighter on RAM. - MicroPython: much bigger. - WebAssembly (wasm3): any language, but a heavier API to bind. - **Memory is the main risk, and Lua makes it controllable.** - `lua_newstate` takes an allocator, so each App can get a budget, for example 24 KB. The allocator refuses anything that would push the heap below the Q86 floors. - When it refuses, the result is a Lua out-of-memory error, not a crash. - Only one Lua App runs at a time, and its state is freed when you leave it, unless it has to run in the background. - **Runaway code.** - A Lua instruction-count hook (`lua_sethook`) stops a callback that takes too long, before the main loop's 5 s watchdog fires. - Errors are caught with `pcall` and shown, with the line number, on a screen like Safe Mode's, not as a reboot. - **How it fits the App model.** - The firmware's App interface (`onEnter`, `onKey`, `update`, `draw`) maps to Lua functions. - A `LuaApp` adapter, written in C++, hosts one script and forwards the calls. - Drawing goes through the shared canvas and the theme (#10), so Lua Apps look native. - **The API, by module (to be decided):** - `ui`: text, shapes and theme colours on the canvas; lists, dialogs, Toasts, text entry. - `keys`. - `storage`: files limited to the App's own folder (`/apps/<name>/`), through StorageService's task. - `settings`: per App, in its own NVS namespace or a file. - `clock`. - `net`: HTTP(S) and Gemini fetches through the services, with their floors. - `gnss`: position, behind a permission. - `irc`: send and receive, maybe. - `sys`: version, heap, battery. The API needs a version number, and an App says which version it needs. - **The sandbox and permissions.** - Lua's `io`, `os` and `debug` libraries aren't loaded. Everything goes through our API. - Secrets are never reachable: Wi-Fi passwords, the debug token, the Gitea token (#4), the VPN key (#8), the SSH keys (#2). - A manifest declares what an App needs (network, position, IRC), and the user approves that the first time it runs. - **Packaging.** - A folder per App: `/apps/<name>/` holds `app.toml` or `manifest.lua` (name, version, API version, permissions), `main.lua`, and an icon for the Launcher tiles (#9). - Apps can be copied in with the USB drive (#1), the file manager (#3), or the Debug Console's `put`. - **Development.** In Debug Builds, a Lua REPL over the Debug Console would make writing Apps fast: edit on a computer, push, reload, all without unplugging. That's the same over-the-air spirit as the OTA work. - **Flash.** About 150 KB for Lua and the bindings. The firmware is 1.71 MB of 3.3 MB, so there's room. ## Questions for the design round 1. Lua 5.4, Berry or something else? Measure flash and RAM for "hello world" and for a list App. 2. What memory budget does an App get? A fixed one, or whatever is above the floors? 3. Which API modules come first? Probably `ui`, `keys`, `storage` and `clock`, with network later. 4. How do permissions work: a manifest plus a prompt on first run, or a trust-all switch for development? 5. Can Lua Apps run in the background (timers, network), or only while they're on screen? 6. Should Apps be signed, like Update Files, or is any App on the card trusted because the card is yours? 7. How are API changes handled: semantic versioning, and refusing Apps that need a newer API? 8. Where are the API docs: generated from the bindings, and published on the website (#12)? 9. Should there be a REPL App on the device itself, not only over the console? ## Related `lib/core/src/app.h` and `lib/core/src/app_manager.h` (the App interface), `src/services/storage_service.cpp`, `src/ui/theme.h`, `docs/milestones/G1.md` (Q86 floors), and #1, #2, #3, #4, #8, #9, #10, #12.
twisla added this to the P1 Platform milestone 2026-10-05 20:14:11 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: twisla/roro9stack#13