Skip to content

Development

afmpeg follows spec-driven development: no implementation change without a spec it implements. The specs are the authoritative decision record; the code is downstream of them.

Picking up implementation? Start at the implementation roadmap — the phased build order across all specs (0013–0034) with dependencies and prerequisites, and its Pick-up menu of the remaining trigger-gated work. Phases 0–4 are shipped (through vocab v9 — job progress), and Phase 5 (the native backend + matrix, HEVC/AV1, perf) is largely shipped too. Current anchors: afmpeg v0.11.2 (plus 0034 on main, unreleased), ffmpeg-wasi n8.1.2-11. What remains is all optional/trigger-gated — 0009 CLI, 0030 WASM threads, arm64/darwin native, HW-accel encode, 0025/0026.

Contributor docs

  • CI security scanning — how the MR security gate works (govulncheck / osv-scanner / trivy / gitleaks), and the recorded decisions behind the osv-scanner ignore + job overrides (incl. the unfixable, unreachable x/crypto advisory).

Specs

The source of truth. They live in the project wiki — see the register for all of them, in number order, with their current status.

Start with 0001-afmpeg, the thesis; it decomposes into the component specs.

They moved out of docs/ because a spec is a point-in-time decision record: read for the conclusion it reached, not kept true as the code changes. docs/ holds only what does change with the code.

Also Scope
external review — validation & disposition The commissioned external review + our per-finding validation verdicts and spec mapping

Method

  • Spec first. Get a spec to APPROVED, then implement against it test-first. New specs claim the next number from the register and are published to the wiki as specs/NNNN-<slug>, not committed to this repository.
  • Library before CLI. Logic lives in pkg/; any command layer is a thin adapter.
  • Test-first from the spec's contracts, table-driven with t.Parallel(); the per-package coverage bar is ≥90% on new pkg/ code.
  • Every package carries a doc.go. The package-level documentation lives in a dedicated doc.go (not scattered above a random file's package clause), so the package's purpose is discoverable in one place and on pkg.go.dev.
  • Docs land with the code, not after. A change that adds or reshapes a component ships its Diátaxis documentation in the same MR — an explanation page for a new component, a how-to for a new task, reference for a new config/CLI surface. Docs are part of "done", never an afterthought.
  • Verify before PR: just ci (tidy, generate, test, race, lint).

Local workflow

just            # build (tidy + generate + CGO_ENABLED=0 build)
just test       # unit tests with coverage
just test-race  # race detector
just lint       # golangci-lint
just ci         # the full local gate
just docs-serve # preview this site

Integration test (real ffmpeg)

The runtime has a gated integration test that loads a real ffmpeg-wasi module and transcodes in memory. It skips unless pointed at a module:

AFMPEG_TEST_FFMPEG_WASI=/path/to/ffmpeg-wasi.wasm go test ./pkg/afmpeg/ -run Integration -v

The runtime provides the env setjmp/longjmp host module and the WebAssembly feature set a real FFmpeg build needs (spec 0004 R-0004-9), so a released ffmpeg-wasi engine (spec 0007) loads and runs.