Linux desktop app for a pocket AI box
open-tiiny
An unofficial Linux app and CLI that drives the Tiiny Pocket Lab over USB, no vendor app needed.
The Tiiny Pocket Lab is a pocket-sized box that runs language models on its own NPU. open-tiiny lets me watch the hardware, manage models, chat and run on-device agents from Linux, talking to the box directly over USB or LAN.
01 / 05 · device comes alive
Motivation
The vendor ships TiinyOS tooling but no Linux desktop app. I wanted to use the device from my own machine, so the goal became Linux first, with full parity against the vendor tools.
The vendor CLI also has bugs the app has to route around. It always prints Activated: False, dies silently when the network report lacks wlan0, and stores a Go duration in nanoseconds in a field called timeoutSeconds.
One standing rule shaped everything. The project documents wire shapes only and never copies vendor code, strings or assets.
Capabilities
- Dashboard with memory, NPU utilization and allocation, CPU, storage, Wi-Fi, firmware and a per-source read status grid.
- Model management with installed, running, catalog and import views, search, download with progress, pause, resume, load and unload.
- Streaming chat against the device's OpenAI-compatible endpoint, with reasoning disclosure, branching, export, image input and an opt-in Use my documents retrieval.
- Knowledge retrieval and indexing schedule, connectors for email and messaging, text to speech and transcription.
- Device agent services, local assistants and desktop or editor clients, alongside Wi-Fi, account, backup and remote access settings.
- A typed CLI with the same services, covering
models,chat,backup,firmware,knowledge,connectors,apiandmcp. - Eight UI locales, light and dark themes, and AppImage,
.deb, Arch and portable CLI builds.
Key decisions
A protocol core with zero dependencies
Why
The device protocol uses Node built-ins only, and a boundary check in lint keeps it that way. It runs directly under Node and could move to a future Tauri shell.
What it cost
Two styles of code in one repo. The core can't use the Effect tooling everything above it relies on.
Effect services shared by desktop and CLI
Why
One typed service graph, built on Effect 3.22 and @effect/rpc, serves the Electron app, the CLI and an embedded local API.
What it cost
A steep learning curve, and Effect is pinned on purpose with no v4 migration.
The device token never leaves the main process
Why
The renderer talks to main only through RPC on a loopback listener with a per-launch session capability. That keeps the renderer sandboxed with no Node or device access.
What it cost
An extra hop and a custom host to maintain. The mock preview reuses that same host.
Typed approval gates on every device write
Why
Model downloads, Wi-Fi changes and firmware actions each carry a capability gate, and the main process owns approval.
What it cost
Every write flow needs a confirm step and its own test approval plumbing.
A mock device everywhere
Why
Synthetic fixtures let UI and end-to-end work run without touching real hardware.
What it cost
Mock success doesn't count as parity, and the docs have to keep saying so.
Architecture
The desktop app and the CLI share one Effect service layer. Every device call passes a capability gate, then goes through the dependency-free core to one of 14 nginx services picked by Host header.
Limits and what's next
- Parity stands at 58 of 61 source families and 11 of 16 acceptance gates as of 2026-10-12.
- Linux first. macOS and Windows builds are planned.
- There's no public release channel yet. Builds are unsigned and picked by checksum.
- Offline checks cover the protocol. Live device runs and a firmware-recovery run are next.
- The vendor cloud blocks agent installs on the firmware versions I tested, which is outside the app's control.
- Device traffic is plain HTTP on the local link, because that's what the device speaks.