HivemindOS manual

Generated media signing

When you generate an image or video from your phone, the hub saves the result and sends your phone a short-lived signed link. The media only travels from your hub to your phone, inside your private Tailnet.

Why it’s needed

Connected image apps (ComfyUI, Image Studio, Z-Image, LocalAI, and others) usually return a link that only works on the hub itself, such as http://127.0.0.1:7860/…, or an inline data: payload. The dashboard runs on the hub, so it can open those directly. A phone can’t. Native image loaders on the phone also can’t send the dashboard session cookie or device token, so they can’t pass normal dashboard auth.

HivemindOS solves this in two steps: it caches the file on the hub, then signs a link to it.

Step 1: cache on the hub

The hub copies each result to ~/.hivemindos/cache/generated-media/. It accepts hub-local files, data:image/… payloads, and HTTP(S) links the hub can reach.

  • Images are checked by their file signature (magic number) and capped at 64 MB.
  • Videos are streamed to disk under a 1 GB cap. A partial download is deleted and never served. The container (MP4, M4V, MOV, or WebM) is checked from the file’s first bytes, so a file that is only named like a video is never signed.

The phone gets a link in this form:

/api/chat/generated-media?path=<absolute path>&exp=<epoch ms>&sig=<hex hmac>
sig = HMAC-SHA256(secret, "generated-media.v1\n<path>\n<exp>")
  • Scope: one file and one expiry time. A leaked link exposes exactly one already-generated file until it expires. Links last 1 hour by default.
  • Checking: signatures are compared in constant time, and malformed exp or sig values are rejected.
  • Secret: the hub uses HIVEMINDOS_DASHBOARD_AUTH_SECRET when it’s set. Rotating it invalidates every outstanding link. A hub without dashboard auth creates a random per-install secret at ~/.hivemindos/generated-media-signing.secret, readable only by your user.

The media route accepts a valid signature or normal dashboard auth. The signature is an alternative for native loaders, not a replacement. Either way, the route only serves image and video files, and caps each at 64 MB for an image or 1 GB for a video. It checks an image’s file signature when serving it. It streams a video by extension, with byte-range support, without inspecting its bytes, which is why the cache checks the video container before anything is signed.

How a phone request runs

HivemindOS Mobile’s /image-gen command and Generate menu send an image or video generation request to the hub’s phone API.

  1. Read the request. A prompt is required. A model picked on the phone arrives in the same shape the dashboard uses. Anything present but unreadable is refused, never dropped, so a request never silently falls back to an automatic choice you didn’t make. A starting picture is accepted inline only, never as a file path.
  2. Resolve the model against the live model list, the same way the dashboard does. A model picked for a published privacy claim is refused if that claim no longer holds.
  3. Generate with the same logic as the dashboard. Spending rules are decided in one place, so they are identical from the phone and the dashboard. An agent’s own image or video tool runs as that agent is set up on this hub.
  4. Cache the result on the hub: every image, or one clip.
  5. Reply with signed links, the app, model, and machine that produced them, and the selection that ran.

Each hub publishes which models its phone path can run, next to its model list. The phone only offers a hub’s models when the hub says it can run them. That matters because an older hub ignores a model selection and picks for itself instead of refusing it.

The phone should download each file once, promptly, and keep its own copy. Signed links are for transport, not storage, and they expire quickly on purpose.

The result: the image or clip crosses one network boundary, from hub to phone, inside the WireGuard-encrypted Tailnet. The phone never talks to the app that made the media, and no third-party service carries it on the way.

Expanded image Scroll to pan · Esc to close
100%