One line of curl owns a card
The simplest way to put something on my desk panel is not a plugin. It is a program that draws a 448×368 PNG and posts it:
curl -X POST --data-binary @panel.png \
-H 'Content-Type: image/png' \
https://deskmate.rodi.one/v1/images/YOUR_TOKEN
That is the whole integration surface. No SDK, no manifest, nothing to install and nothing to submit for review. The card on the panel now shows your picture, and keeps showing it — the server stores the decoded frame as a durable asset, so when the loop comes back around to your card no image bytes move at all.
The rules are short enough to list completely:
- Exactly 448×368. Anything else is refused at ingest with a 422. There is no scaling contract to get wrong.
- 8-bit, RGB or RGBA. The panel has no alpha channel; RGBA is composited over black.
- At most 1 MiB, which is the device’s own asset-byte limit.
- PNG only. SVG stays server-authored, because accepting untrusted SVG would buy us external references, entity expansion and font loading, and we would like none of those.
- The token goes in the path or in an
Authorization: Bearerheader — your choice. Path tokens show up in access logs. The token is write-only, scoped to one source, and revocable on its own.
Pushing a byte-identical picture is a no-op: nothing is transferred again. The push still counts as liveness and still updates the source’s observed cadence, so a producer that has nothing new to say can keep saying it.
The honest limitation. A pushed picture does not respond to a tap. A producer posts a frame and declares no views, so there is nothing for the firmware to switch to. The cards that answer a finger are the ones the server itself draws: the built-in faces — weather, Hacker News, RSS, a token chart — and the sandboxed plugins that declare a tap in their manifest. A plugin is the stricter, reviewed thing: a function the server runs in a sandbox, which only declares the requests it needs and never performs one itself, and that is what lets it live on hosted infrastructure next to strangers’ plugins. The curl line is the floor underneath all of it, and the floor needs nothing from me.
There is a real one in the tree to copy:
tools/picture-producers/claude_limits_png.py
reads a usage feed, draws the bars itself with Pillow, and posts the bytes. Under 200
lines, one dependency, no framework. It is drawing the card in the photograph on
deskboy.sh. The full rules, with every status code, are in the
producer guide.