"Sources/CLibMPV/ — the narrow C module boundary; no product decisions."
Where the Danger Lives
When you embed a C library in a Swift app, all the sharp edges live at the seam: raw pointers, manual memory, NULL-terminated arrays, integer error codes, undefined behavior if you hold a handle wrong. That danger is unavoidable — it's the price of reuse. What you can control is how much of your app has to touch it.
Ashen Reel's answer is a module called CLibMPV: a single, small, boring boundary whose only job is to let Swift call libmpv's C API safely. It maps the C header, wraps the handful of calls the app needs into safe Swift signatures, and stops there. Everything above it speaks Swift and never sees a raw pointer.
No Product Decisions at the Seam
The rule that keeps this boundary healthy: no product logic lives in the C module. Should a seek be exact or fast? Should resume override a deep link? What counts as a successful seek? None of that belongs at the C seam — it belongs in AshenReelCore, in pure, testable Swift. The C module only knows how to say one thing to libmpv and translate the answer back.
Here's the whole philosophy in one function — the only place raw mpv pointers get touched:
Why 'Boring' Is the Goal
A good interop boundary is boring on purpose. It has few functions, each does one call, each cleans up after itself, and none of them make a judgment. When something goes wrong deep in playback, you want to be debugging Swift logic with real types and tests — not bisecting a crash that could be anywhere because pointers and product decisions got tangled together. Boring at the seam buys you sanity everywhere else.