Skip to content

← Firmware Downloads

Post-install setup · Reborn (Y2Linux) · Y2

Plugins: one kind of package for everything optional

Debian-based Linux with a fast clickwheel interface for the Innioasis Y2.

Instructions published by the project, shown here word for word.

Plugins: one kind of package for everything optional

Status: plan, 2026-10-31. Nothing here is built yet. Applies to Y2Linux (platform) and Y2Reborn.

1. Why, and the owner's decisions

Users asked for Navidrome sync. It does not belong in Y2Linux, Reborn or the platform, and neither do the next ten requests like it. The answer is plugins: optional packages that users install from a store (or build themselves), so the core stays small, stable and testable.

Decided by the owner (2026-10-31):

  1. One unified kind of package. A skin, a set of headphone profiles, internet radio, Last.fm and Navidrome

    sync are all the same thing: a signed package that contributes to fixed extension points. One format, one installer, one store, one Add-ons screen, one permission model.

  2. Every plugin with code is WebAssembly. No native plugins: not as .so files, not as separate native

    processes, not even for our own. Plugins are written in Rust (or any language that compiles to WebAssembly) and run in a sandboxed runtime. Plugins without code (skins, profiles, fonts) carry no module at all.

  3. Rust everywhere: the host, the contract, the SDK and our plugins.
  4. The coding standard (CODING-STANDARD.md) and its ratchet apply from the first commit.

Still open, with a recommendation: who may publish in the store (§8), whether CJK fonts leave the image (§6).

2. The model

A plugin is a package with a manifest, an optional WebAssembly module and optional assets. The manifest declares which extension points it contributes to and which permissions it needs. Reborn and the platform know only the extension points, never a particular plugin.

Extension pointWhat the plugin providesCode?Examples
Lookskin layouts (today's skin format), colours, icons, fontsnoskins, CJK font
Soundheadphone/EQ profiles (today's ParametricEQ format), DSP presetsnothe 47 headphone profiles
Sourcea browsable catalogue and, per item, something to play or downloadyesinternet radio, Navidrome, podcasts
Listenerreactions to playback eventsyesLast.fm, ListenBrainz, Navidrome play counts
Jobbackground work under constraints (Wi-Fi, charger, interval)yesNavidrome sync, podcast downloads
Settingsa settings schema; Reborn draws the formno (validation optional)every plugin with options

A plugin may combine them: Navidrome is Source + Job + Listener + Settings; Last.fm is Listener + Settings; a skin is Look only.

Plugins never draw UI and never touch real-time audio. A Source's catalogue is data (sections, lists, items with artwork and actions); Reborn draws it with its own components, so every plugin looks right in every skin and works with the wheel, search and Customize. Playback is always the core's: a Source hands back a stream URL or a file, never audio samples.

3. What the core becomes

Core Reborn keeps exactly what a plugin must never be able to break, plus the machinery for the extension points:

  1. Playback engine: decoding (FFmpeg), gapless, crossfade, the EQ/DSP engine, volume, wired and Bluetooth

    output, and the stream player (today's radio stream fetcher: curl, ICY stripping, reconnect; FFmpeg has no network protocols). A Source plugin's URL plays through it.

  2. Local library: scanner, database, queue, history, session, audiobooks (their chapters and speed are

    playback internals). Local music is the one built-in source.

  3. UI framework: navigation, components, renderer, input, the skin engine with one default skin, the generic

    Source browser, the Add-ons screen, settings forms, the QR code sign-in screen.

  4. Device and safety: Wi-Fi, Bluetooth, battery, sleep, storage, updates, diagnostics, error reports (all

    platform-backed).

  5. The plugin client: the contribution registry and the connection to the plugin host.

Leaving the core:

Today in the coreBecomesSize today
Internet radio: radio-browser.info directory, station search, favourites, logosRadio plugin (Source)≈ 1,700 code lines; the stream player stays
Last.fm sign-in, Now Playing, scrobble queueLast.fm plugin (Listener + Settings)≈ 1,300 code lines
Automatic time zone (ipapi.co / ipwho.is)Time zone plugin (Job)≈ 150 lines
16 skinsskin plugins (Look); one default stays3.5 MB
47 headphone profilesprofile plugins (Sound); a neutral setting stays0.2 MB
Noto CJK fontfont plugin (Look), see §615.7 MB

About 7 % of Reborn's code leaves. The bigger gain is that new features never enter the core again, and the core's job becomes a stable, versioned contract instead of an open-ended feature list.

4. Architecture

 Reborn (UI, playback)  ──Unix socket, typed messages──▶  y2-plugin-host (unprivileged user)
        │                                                     └─ WebAssembly runtime: one instance per plugin
        │ install / remove / update (platform command)
        ▼
 y2-platform (root): verify signatures, unpack to /data, store client, rollback

Files

PathWhatOwner
/usr/share/y2/plugins/<id>/preinstalled plugins (in the image, signed like store plugins)image
/data/plugins/<id>/<version>/installed versions (two kept: current and previous)platform
/data/plugin-data/<id>/a plugin's private data (settings, secrets, queues), mode 0700host user
/media/internal/music/<Plugin name>/music a Job downloads (the library scans it)host user

A store version of a preinstalled plugin overrides it; removing it falls back to the preinstalled one.

5. The contract

Interface

Defined in WIT (WebAssembly Interface Types) as the package y2:[email protected]; the SDK generates the Rust bindings on both sides. Versioning as the platform's contract: additive changes raise the minor version, a host runs every plugin of its major version, a plugin declares the oldest minor it needs.

Exports a plugin may implement (by extension point):

Host functions a plugin may import, each gated by a manifest permission:

ImportPermissionRules
http.requestnetwork with fixed hosts, or network:user-hostsHTTPS; plain HTTP only to user-configured LAN hosts (Navidrome at home), with a warning; size, time and rate limits
files.*storage:own-musiconly below its music folder, openat without following symlinks (as y2p-core does for the SD card); quota
data.*, secrets.getalways (own only)its own key-value store and secrets
library.rescanlibraryasks Reborn to scan its music folder
status.reportalwaysprogress and messages shown in the Add-ons screen
time.now, logalways—

Package

<id>-<version>.y2plugin: a tar archive with manifest.json, an optional plugin.wasm, assets/, and signature (Ed25519 over the manifest, which lists every file's SHA-256).

Manifest fields: id (reverse DNS, e.g. org.y2linux.radio), name, version, api (y2:plugin version), author, license, description, contributions, permissions, limits (memory, at most the host's cap), settings, min_platform.

6. The core after the move, and the CJK question

Reborn ships one default skin, a neutral sound setting, local music, and the preinstalled plugins Radio and Last.fm (preinstalled so an update from 9.x loses nothing; users can remove them).

CJK font (open): track titles in Chinese, Japanese or Korean need the font in the core UI. Recommendation: make it a plugin, and when the library scan finds a title the default font cannot draw, Reborn offers to install it (with a fallback that shows the title as a code-point box until then). Alternative: keep it in the image.

7. Security model

Threats: a malicious plugin, a buggy plugin, a hostile or compromised server a plugin talks to, a compromised store. Layers, inside out:

  1. The WebAssembly runtime is the sandbox. A plugin has no system calls, no memory outside its own, no

    threads, no files and no network except through host functions. Per instance: a memory cap (default 16 MB), a CPU budget per call (fuel or epoch interruption), a wall-clock timeout.

  2. Host functions are the attack surface and are written to the coding standard with tests that include

    hostile input (path traversal, symlinks, oversized responses, malformed WIT values) and fuzzing.

  3. The host process is a second wall, with what the kernel offers today (checked on the player

    2026-10-31: no seccomp, no LSM, no cgroups, only mount namespaces; no_new_privs, resource limits and separate users work): its own unprivileged user, no_new_privs, setrlimit (address space, open files, no child processes), low priority, a private mount namespace showing only its own directories.

  4. Kernel hardening later: seccomp for the host, Landlock, cgroup v2 memory/CPU accounting. Kernel

    configuration changes, so after a hardware round (memory, sleep); not a precondition.

  5. The store signs packages with its own key, never the update key (platform-v1-release-* signs only

    system updates). Installing shows the permissions; an update that asks for more asks again.

Battery without cgroups: event-driven host, the CPU budget per call, background Jobs only under their declared constraints (Wi-Fi, charger), low priority.

Known separate risk: Reborn and the four platform daemons run as root (checked 2026-10-31). Dropping root where it is not needed is its own hardening project (§10, P6).

8. The store

9. For plugin authors

10. Phases

Each phase ends with the gate green, the code-quality ratchet not worse, and the listed checks.

PhaseContentExit
P0 Spikechoose the runtime on armv7: wasmtime's portable interpreter (Pulley) with the component model, or wasmi (pure Rust, core modules only); prototype host + a plugin doing HTTP and file writes on the playermeasured binary size, idle and per-instance RAM, CPU for a sync-like workload, component-model support; decision recorded here
P1 Foundationcontract v1 (Look, Sound, Settings), package format and signatures, y2-platform plugins commands, the host process with sandbox layers 1–3, Reborn's Add-ons screen, sideloadingskins and headphone profiles install and remove as plugins; host idle CPU ≈ 0 s/h; application_ready unchanged
P2 Sources and JobsSource, Job, http, files, library.rescan; Reborn's generic Source browser; Radio rebuilt as a plugin (preinstalled)radio parity with 9.x (directory, search, favourites, logos, playback, reconnect); then the directory code leaves the core
P3 ListenersListener with durable queues; Last.fm as a plugin (preinstalled), QR sign-in through Settingsno scrobble lost across restarts and updates; the Last.fm code leaves the core
P4 Navidromethe first plugin outside the core, in its own repository: browse and stream (Source), offline sync (Job), play counts (Listener)works against a real Navidrome server on Wi-Fi; sync only on Wi-Fi and charger
P5 Store and SDKcatalog, store key, review checklist, updates and rollback, SDK, template, CLI, documentationa plugin goes from template to signed store listing end to end
P6 Hardeningkernel features (§7.4) after a hardware round; Reborn and daemons without root where possible—

Moving a feature out of the core (P2, P3) keeps its user data: favourites, Last.fm session and queue migrate into the plugin's data directory on first start.

11. Measurements every phase reports

Idle CPU (s/h) of the host and Reborn, host and per-plugin RSS, application_ready, overnight sleep current with plugins installed, the image size, and the core's code size (tools/development/code-quality.py).

12. Risks and open questions

Published by the schulzcode/y2linux project [1] [3]