Media generation
A lot of what a brand agent makes is visual: covers, pins, thumbnails, ad creative, short video, voice-over. Generation is easy to do badly — off-brand, untracked, paid for twice, lost on a laptop. WilsonOS makes it hard to do badly by routing every render through one door.
One door
Section titled “One door”Every generation — image, video, audio — goes through a single gateway. Skills call the gateway; nothing calls a provider directly. The gateway:
- Applies the brand. Reference images and brand elements are looked up and passed explicitly by the calling skill; the render is grounded in the brand’s visual rules rather than a bare prompt.
- Names the skill. Every call carries the skill making the render, so the result is attributable (Skills).
- Enforces spend caps. A render outside the allowed model and provider set is refused with an error naming what is missing, never silently rerouted.
- Writes the receipt first. See below.
The same rule covers editing and importing. A derivative pass — an audio swap, a caption burn, a compression for a chat preview — goes through the editing door and is registered. A file made by another engine, or uploaded by hand, is registered on the way in. Nothing leaves the pipeline unregistered — not to a shared drive, not to chat, not to an ad platform.
The receipt is written before the render finishes
Section titled “The receipt is written before the render finishes”Everything a receipt needs — the exact request, the prompt, the references, the model, the cost estimate — is known the moment a provider accepts the job. Only the outcome is not. So the receipt is opened at submit and closed when the result arrives. A killed process, a poll that times out, a ten-minute clip that finishes after the agent has moved on: none of them lose the receipt for a render that was already paid for.
Two consequences: the request stored is the verbatim one the tool sent, written by one writer; and reference paths are recorded as our stable paths, not the provider’s temporary upload links, which expire.
Identity: the registry owns it, storage holds bytes
Section titled “Identity: the registry owns it, storage holds bytes”flowchart LR ID["Asset<br/>a stable identity"] --> B["Blob<br/>the bytes, by content hash"] ID --> L["Label<br/>a name or path — can change"] B --> P["Primary copy<br/>durable object storage"] B --> K["Backup copy"] ID --> R["Receipt<br/>what made it, what it cost"]
An asset is identified by a stable id; its bytes are a blob identified by content hash; a name or path is a label that can change without breaking anything that points at the asset. That is what lets a deliverable be renamed or reorganised while every chat card, task, and calendar entry keeps resolving — and what lets the same bytes appear under two names without being stored twice.
Bytes live in durable object storage with a backup copy; local disk is a disposable cache. Every serving route checks brand access before bytes move.
The publish gate
Section titled “The publish gate”A task cannot be flipped to review or done while a media file in it has no completed publish. The gate names the files, moves nothing, and tells you what to do. It means “approved” always refers to a version that is registered, durable, and addressable — never a file that happens to be on someone’s disk.
What this makes possible
Section titled “What this makes possible”- “What did this task cost?” — sum the receipts.
- “Which skill earns stars and which burns spend?” — join receipts to ratings by skill.
- “Show me the approved v3, not the v2 I commented on.” — versions are identities, not file names.
- “Where did this image come from?” — the receipt: prompt, references, model, skill, run.
live The one-door rule, receipt-at-submit, the asset/blob/label model, durable primary storage with backup, brand-checked serving routes, and the publish gate are live (the gate warns today and will refuse after sign-off). Retention and cleanup follow the same registry.
Related
Sources: docs/architecture/media.md, AGENTS.md § Media Generation Gateway, docs/DECISIONS.md (ADR-019, ADR-023) · Last verified 2026-09-15