Nerd start from here

No toolkit.
No cgo. Just Go and X11.

Most desktop toys drag in a GUI framework measured in hundreds of megabytes. This one doesn't. It speaks the X11 wire protocol directly, and every pixel of Onidia is drawn by code at runtime.

Youtype, or speak into the mic
→
onidia-chatpure Go, raw X11
UI thread never blocks
→
The modelGemini / Bedrock
Ollama / OpenRouter
→
Speech pipea named FIFO per display
/tmp/desktop-pet--0.say
→
Onidiaspeaks it, with the
matching expression
~0%IDLE CPU
~3 MBRESIDENT MEMORY
0IMAGE ASSETS
0CGO DEPENDENCIES
112×160AUTHORING GRID
5×7BITMAP FONT
Written, designed and tested on a Pi 5

Sixty-four bits, end to end.

Onidia and onidia-chat are pure Go, so a build is a single static arm64 binary — nothing to cross-compile on the Pi, nothing to install beside it. The release artifact is exactly that: one arm64 .deb that carries both halves. A Raspberry Pi 5 is what they were written against, designed around and tested on.

The more interesting half is what that Pi can be as the machine. On a AI HAT+ 2 — the Hailo-10H board, 40 TOPS of INT4 inference and 8 GB of RAM living on the card itself — Hailo's hailo-ollama speaks the very same ollama /api/chat dialect onidia-chat already speaks to the network. Point the provider at localhost and the model stops being someone else's computer.

arm64BUILD TARGET
40 TOPSINT4 INFERENCE
8 GBON-BOARD MODEL RAM
0 BLEAVES THE PI
private by default
# Hailo's ollama-compatible server. Listens on :8000.
hailo-ollama

# 8000 is already the default - this is the whole switch:
./onidia-chat -provider ollama -model qwen2:1.5b

# Qwen2 1.5B, Llama 3.2 1B, Qwen2.5-Coder, DeepSeek-R1
curl localhost:8000/api/tags
Nothing leaves the Pi. No key, no account, no request to a vendor you cannot audit — pull the network cable and it behaves identically. One honest footnote: hailo-ollama rejects the tools field, so onidia-chat retires tool calling after the first reply and carries on in plain text.

How a frame is made

A tiny state machine — idle, walk, hop, drag, throw — runs a few physics steps a frame and produces a pose: bob, leg swing, foot lift, blink, arm flags, expression. The pose is rendered procedurally onto a supersampled canvas and downsampled for smooth edges, the speech bubble is composed above it, and the whole image is uploaded with a single PutImage. The window itself just moves to follow her.

Because the character is code and not a sprite sheet, adding a personality means writing a Go package: its own palette, drawing functions and phrase list, registered at startup and picked with -character. Two characters can never collide, because they share nothing but the pose contract.

XShape is deliberately not used: under XWayland, shrinking a shaped window's region can stop updates from being presented, so the plain transparent window composites correctly everywhere instead.

Worth knowing

characters/One self-contained package per personality — onidia, kama, and a template for yours.
behavior.goThe buddy brain: idle / walk / hop / drag / throw FSM plus the throw and parachute physics.
bubble.goComic speech-bubble rendering, word wrapping, and the scene layout that reserves headroom for the cloud.
events*.goThe celebration framework: hearts, confetti, floating Zs, the lightbulb, the robot suit-up.
internal/fxShared supersample compositing, the built-in bitmap font, alpha and easing maths.
single instanceA kernel flock per display, so a second launch exits and names the pid holding it.
Get in touch

Questions, ideas,
or a new character?

Found a bug, want a feature, or fancy writing your own personality? The repositories are the fastest way in — and issues are genuinely read. If you'd rather just say hello, the form works too.