Skip to content

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.

Sep to Oct 2026Runs on Linux
opentiiny · Demo Pocket Lab (USB)
opentiiny
USB ·ConnectingDemo Pocket Lab (USB)
Mock deviceDeterministic test data. No device mutations.

Device overview

Demo Pocket Lab

Demo Pocket Lab · USB connection

Device status

Ready

Memory

10.1 GiB used · 29.8 GiB total

NPU utilization

2 used · 6 available

CPU

Demo processor

Storage

476.8 GiB total

Connection

Transport
…
Wi-Fi
…
Signal
…
Firmware
…

Demo language model

demo-language-model

2 NPU

Read status

Sampled 9:20:38 PM
Running modelspending
NPU allocationpending
Installed modelspending
Model catalogpending
Device informationpending
Network interfacespending
Storagepending
Hardware usagepending

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, api and mcp.
  • 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.

Notable

The test suite is bigger than the app

1,442 test files hold about 498k of the repo's 788k TypeScript lines. Unit and property tests sit next to headless browser and offscreen Electron Playwright suites, all against a deterministic mock device, plus a separate project for a real Pocket Lab. Every live device write lands in an approval ledger. All of it came from 1,167 commits in 19 days, a pace that points to heavy agent-driven work under an OpenSpec process.

Stack and numbers

TypeScriptElectron 44Effect 3.22React 19HeroUI 3Tailwind 4Rust Node-APIPlaywrightVitest
Commits
1,167
Days of work
19
Test files
1,442
TS and TSX
788
k lines