Running Rindle Image and AV Profiles

Copy Markdown View Source

Use this guide for host-runtime dependencies before Rindle background jobs process variants. Image processing uses libvips (via Vix). AV processing uses FFmpeg.

Image runtime (libvips)

Image-only adopters need libvips on the host before ProcessVariant jobs run:

  1. install libvips for the target platform
  2. run mix rindle.doctor
  3. only then start background jobs that generate image variants
PlatformInstall
macOS (Homebrew)brew install vips
Ubuntu / Debian (apt)sudo apt-get update && sudo apt-get install -y libvips-dev
Alpine (apk)apk add --no-cache vips-dev
GitHub Actionssudo apt-get install -y libvips-dev (same as CI quality job)

AV runtime (FFmpeg)

Use this section when your adopter app enables video or audio processing. The AV runtime contract is small and explicit:

  1. install FFmpeg >= 6.0 for the target platform
  2. run mix rindle.doctor
  3. only then start background jobs that process AV variants

README stays the narrow quickstart. Getting Started is the canonical deep onboarding guide. This file is the shared install/runtime matrix both of those entrypoints link to.

Maintainer: CI lane severity

Adopters can skip this section. It documents how this repository gates merges and releases.

.github/workflows/ci.yml is the source of truth for job wiring; GitHub branch protection and required-check settings live outside the repo.

Job / stepSeverityWhen it runsNotes
quality — Compile, Check formattingmerge-blockingEvery PR/push; Elixir 1.15/OTP 26 and 1.17/OTP 27 matrixBoth matrix cells must pass
quality — Credo (strict)advisorySame jobStep-level continue-on-error
quality — Doctor (full, raise)advisorySame jobStep-level continue-on-error
quality — Verify AV runtime with public doctor taskadvisorySame jobStep-level continue-on-error
quality — Run tests with coveragemerge-blockingSame jobDefault mix test suite via Coveralls; both matrix cells must pass
quality — DialyzeradvisorySame jobStep-level continue-on-error
integrationmerge-blockingneeds: qualityLifecycle + MinIO adapter tests
contract — Run AV hygiene gatemerge-blockingneeds: qualityscripts/assert_av_hygiene.sh
contract — Run contract testsadvisorySame jobStep-level continue-on-error; job still required in graph
proofmerge-blockingneeds: qualitydocs_parity_test.exs, adoption proof matrix drift gate, batch_owner_erasure_task_test.exs; Postgres only; Elixir 1.17/OTP 27
package-consumer — repo hygiene gatemerge-blockingSame jobscripts/maintainer/repo_hygiene_check.sh --ci
package-consumermerge-blockingneeds: qualityInstall-smoke matrix + release preflight
adoption-demo-e2emerge-blockingneeds: quality; repo szTheory/rindle onlyPlaywright browser proof for examples/adoption_demo (image, tus, stretch journeys)
adoptermerge-blockingneeds: [quality, integration, contract]Canonical adopter lifecycle only (doc parity in proof job)
mux-soaksecret-gated soakLabel streaming on PR; needs: qualityNot in branch protection required checks; fails closed when secrets absent
gcs-soaksecret-gated soakneeds: quality; repo + secretsSkipped when secrets absent; test step advisory when it runs
package-consumer-gcs-livesecret-gated soakneeds: quality; repo + secretsJob-level continue-on-error; live GCS install-smoke when secrets present

Static analysis policy (CI-04)

Decision: Credo (strict) and Dialyzer remain advisory in the quality job. Wiring uses step-level continue-on-error: true in .github/workflows/ci.yml. Making either tool merge-blocking is explicitly rejected for the current release train.

Rationale:

  • Signal value: Static analysis catches style and typespec drift; failures remain visible in CI logs for maintainers without blocking adopter-critical merge lanes.
  • Fork latency: Dialyzer PLT build is slow; merge-blocking would raise contributor and fork PR cost disproportionate to adopter impact.
  • Green-main honesty: Adopter-critical lanes are already merge-blocking (mix coveralls, proof, package-consumer, adopter, integration, contract AV hygiene). Static analysis is maintainer hygiene, not adopter contract.

Doctor and AV doctor steps remain advisory without a separate CI-04 decision record (CI-04 names Credo and Dialyzer only). See matrix rows above.

Release train

.github/workflows/release.yml gate-ci-green waits for ci.yml on the release SHA to finish with conclusion success. When the latest run is not green, or the wait times out, publish fails closed — there is no bypass path.

Branch protection required checks (enforced via scripts/setup_branch_protection.sh) include Quality (both matrix cells), Integration, Contract, Proof, Package Consumer Proof Matrix + Release Preflight, and Adopter.

Verify The Runtime

Run this in the adopter app after mix deps.get and after installing FFmpeg:

mix rindle.doctor

The command must pass before you debug Oban workers, variant failures, or delivery URLs.

FFmpeg Install Matrix

macOS (Homebrew)

brew install ffmpeg
mix rindle.doctor

Ubuntu / Debian (apt)

sudo apt-get update
sudo apt-get install -y ffmpeg
mix rindle.doctor

Alpine (apk)

apk add --no-cache ffmpeg
mix rindle.doctor

Fly.io Dockerfile

Add FFmpeg to the image build:

RUN apt-get update \
 && apt-get install -y ffmpeg \
 && rm -rf /var/lib/apt/lists/*

Run mix rindle.doctor during build or release validation before the app starts workers.

Heroku Aptfile

Add an Aptfile at the app root with:

ffmpeg

Then run mix rindle.doctor as part of release validation.

Render Dockerfile

Add FFmpeg to the Render image build:

RUN apt-get update \
 && apt-get install -y ffmpeg \
 && rm -rf /var/lib/apt/lists/*

Run mix rindle.doctor in the build or pre-deploy command.

GitHub Actions

Use FedericoCarboni/setup-ffmpeg so CI exercises the same runtime posture:

- name: Install FFmpeg
  uses: FedericoCarboni/setup-ffmpeg@v3
  with:
    ffmpeg-version: 6.0

- name: Verify Rindle runtime
  run: mix rindle.doctor

Canonical AV Profile Shape

The onboarding story stays on the stock web_720p plus poster surface. The explicit variant declarations are:

variants: [
  web_720p: [kind: :video, preset: :web_720p],
  poster: [kind: :image, preset: :video_poster_scene]
]

That is the same public posture taught in README and Getting Started.