keryx media¶
Description¶
Sync a reel workspace's media with the configured object store (spec 0039).
A workspace is two kinds of state: small, diffable authored state
(storyboard, meta, social copy, ledger) that belongs in the owning project's git
repo, and large binary media (VO takes, illustrations, cover art, music
beds, the rendered reel) that would bloat git permanently. keryx media moves
the media through a versioned object store instead: files upload to stable
keys (<prefix>/reels/<slug>/…), the bucket's own versioning keeps the history,
and a per-workspace media.lock manifest — committed to git — pins each
file's content hash and object version, so any git commit can reproduce its
exact media.
Configure the store in the project's .keryx.yaml (top-level storage:
section). Credentials are never in config — each backend resolves them from
its own environment chain (AWS default chain, Google ADC, Azure default
credential), which is exactly what CI federated identity expects.
storage:
provider: s3 # s3 | gcs | azure | file
prefix: blog # this project's namespace in the store
s3:
bucket: pbs-prod-reel-media
region: eu-west-2
profile: "" # optional AWS named profile; blank = default chain
endpoint: "" # optional — set for MinIO/R2 (S3-compatible)
Backends¶
storage.provider |
Config block | Notes |
|---|---|---|
s3 |
s3.{bucket,region,profile,endpoint} |
AWS and every S3-compatible store — MinIO, Cloudflare R2, Backblaze B2, Wasabi, DigitalOcean Spaces, Ceph — via endpoint. |
gcs |
gcs.bucket |
Google Cloud Storage; credentials via Application Default Credentials / Workload Identity. |
azure |
azure.{account,container} |
Azure Blob Storage; credentials via the Azure default credential chain / Managed Identity. |
file |
file.dir |
Local filesystem — a zero-dependency backend for self-hosted or offline use. |
The non-S3 backends run through one portable adapter over
gocloud.dev/blob, so keryx carries no
per-cloud storage code.
With no storage.provider configured keryx stays local-only — media commands
say so, and the studio's Commit & push simply skips the sync.
Subcommands¶
keryx media push— upload changed media, bump versions, and re-pinmedia.lock.keryx media pull— hydrate missing media at the pinned versions (fresh clones, CI, point-in-time restore).keryx media versions— list a file's version history.keryx media rollback— repoint a file at an earlier version.keryx media migrate— convert a pre-0040 workspace to the content-addressed layout.keryx media gc— reclaim blobs no workspace references.
Versions (spec 0040)¶
Media is stored content-addressed — each blob lives at blobs/<sha256>, so
identical content is stored once and integrity is verifiable on read. The store
therefore needs no versioning of its own.
Human version numbers are keryx's, kept in git:
media.lock— the current promoted state: each file's{v, sha256, size}.media.log— the append-onlyV1 → V2 → V3ledger, with timestamps.
So "roll back to V3" is a real operation (media rollback), the history is
diffable in review, and it travels with the repo — independent of which backend
holds the bytes.
See also¶
- How-to: set up the media object store — bucket setup, local auth, GitLab CI OIDC.
- Spec:
docs/development/specs/0039-media-object-store.md - The studio's Commit & push runs the same sync automatically before each
commit, so
media.lockrides in the same commit as the board.