Config options
| Option | Default | Meaning |
|---|---|---|
recordStore | d1 | Where media records live. d1 makes transcriptions and extracted text queryable; kv is key lookup only |
| Enrichment toggles | off | Alt text, transcription, text extraction — each independent |
| Backend per type | — | Which store handles images, video, audio and documents |
Pick d1 unless you are certain you will never want to search the text. Enrichment produces text so that something can read it, and kv closes that door.
The choice also changes what provisioning creates: the KV namespace exists only in kv mode, and in d1 mode the binding is dropped rather than pointed at a namespace that never existed.
Bindings
| Binding | Type | Written by |
|---|---|---|
DB | d1 | pithy add |
MEDIA_BUCKET | r2 | pithy add |
MEDIA_IMAGE_TO_TEXT | workflow, optional | pithy media provision |
MEDIA_AUDIO_TRANSCRIBE | workflow, optional | pithy media provision |
| The video Workflow | workflow, optional | pithy media provision |
The Workflow bindings are declared optional so an app still boots before provisioning has deployed the host — which is what makes a first pithy dev work on a project that has never reached an account.
Secrets
One of these is read by storage, not by media.
Two, because there are two owners.
| Secret | Belongs to |
|---|---|
media-storage-credentials | Media’s own token for minting direct-upload URLs |
media-r2-credentials | The object store media presigns through — and whose key pair media never sees |
Neither is minted. There is no API for creating an S3 access-key pair, and the permission catalog carries no keys for the image or video stores. You make them by hand.
Backends per type
Why each type resolves the way it does is a backend per media type; the calls are in Using Media; standing them up is pithy media.
| Type | Typically |
|---|---|
| Image | The image store, for variants and transformation |
| Video | The streaming store, for adaptive playback |
| Audio, documents | R2, through the object-store seam |
Ownership is metadata, not a name
An asset in the image or video store is keyed by an id the store mints, so there is no name to put a project segment into.
Every asset is stamped with the project and the environment, the same two keys in both stores, so one query answers what does this project own across them.
The stamp is merged last, so a caller’s own metadata cannot displace it. A Worker that cannot name its project refuses to mint.
What it does not inherit from storage
It presigns through the object-store seam, against its own bucket and credential name — and inherits none of that capability’s tables, routes, quotas or share links.
So composing both gives you two independent products rather than one with two front doors.
Peer capabilities
Required: secrets.
Optional: auth — effectively required, since an upload belongs to somebody.
Composes naturally with vector, whose corpus is the obvious destination for extracted text.
Provisioning
pithy media provision creates the bucket and the namespace, writes both credential secrets, and deploys the host that runs the enrichment Workflows.
Each environment’s deploy needs the app database id and that environment’s secrets database, and both are refused rather than deployed around.