Package: media-use skill · scripts/lib/local-models.mjs, scripts/lib/ltx-video-provider.mjs
Version: hyperframes @ 6eaa2cb64b280c51cadb3843ce190f6f0b7493cc (also hyperframes@0.8.14 from npm)
Environment: macOS 26.5.2, Apple M5 Max, 128 GB, Node v24.18.0, ltx-2-mlx installed and on PATH
Summary
LOCAL_MODELS.videogen's large tier names dgrauet/ltx-2.3-mlx-bf16. That repo is not published — the Hugging Face API returns HTTP 401. Because selectModel chooses a model on RAM/GPU fit alone, any machine with ≥32 GB selects that tier, the download fails inside the provider, and resolve --type video --local-only fails outright.
The tier's own note says it is for "64-128GB Macs for long/HD runs" — so the entry aimed at the largest machines is the one that cannot work.
Reproduction
Two commands. The first needs nothing installed.
# 1. the repo the registry names
curl -s -o /dev/null -w '%{http_code}\n' \
https://huggingface.co/api/models/dgrauet/ltx-2.3-mlx-bf16
# -> 401
# for contrast, the ones that do exist:
for r in q4 q8 ''; do
curl -s -o /dev/null -w "$r %{http_code}\n" \
"https://huggingface.co/api/models/dgrauet/ltx-2.3-mlx${r:+-$r}"
done
# -> q4 200 / q8 200 / (bare) 200
# 2. end to end, on a Mac with >= 32 GB and ltx-2-mlx on PATH
node ~/.agents/skills/media-use/scripts/resolve.mjs \
--type video --intent "a red sports car at night" --local-only --project /tmp/x
Expected: a generated clip, or a clear "install the local model" message.
Actual:
media-use: local video gen (ltx-2.3-mlx-bf16) failed: …
If you are trying to access a private or gated repo, make sure you are authenticated.
error: no provider could resolve video: "a red sports car at night"
Root cause
selectModel (local-models.mjs) does iterate and fall back — but meetsSpecs tests only needs.ramMB and needs.gpu. Model availability is never part of the fit test, so on a 128 GB machine the large entry "fits", is selected, and the failure surfaces later inside ltxVideoGenerate at download time. The provider catches it, logs, and returns null.
Under --local-only, ltx.local is the last provider in the video cascade (heygen.video is skipped as network), so a null there ends the cascade with no provider could resolve video.
Net effect: a model that cannot be downloaded is indistinguishable from a machine that cannot run it, and there is no retry at a lower tier.
Why this survived
hyperframes doctor does not probe videogen at all — it reports heygen, ffmpeg, Chrome, Docker and node. The entry also reads as entirely plausible on inspection. It is only observable by running a local video resolve on a ≥32 GB machine.
Suggested fixes
Either alone resolves it; the first two are worth having together.
- Repoint the
large tier at dgrauet/ltx-2.3-mlx-q8, which exists. Its core subset (transformer-distilled-1.1 20.6 GB + connector 6.3 GB + VAEs + vocoder) is ~29 GB, so sizeMB: 45000 should come down too. This is what I applied locally; resolve --type video --local-only then succeeds.
- Fall back a tier when a provider returns
null for a resolvable reason. A model whose weights 404/401 should demote to the next-smallest entry rather than ending the cascade.
- Add
videogen/imagegen to hyperframes doctor, so a broken registry entry is visible without running a generation.
Second, related finding — resolve cannot set video dimensions
ltxVideoGenerate reads ctx?.width || 512, ctx?.height || 320, ctx?.frames || 33. But resolve.mjs builds ctx from exactly six fields:
const ctx = { entity, projectDir, localOnly, provider: args.provider,
avatarId: args["avatar-id"], voiceId: args["voice-id"] };
There is no --width/--height/--frames flag, and nothing reads canvas size from hyperframes.json. So those fallbacks are unreachable and every locally generated video is 512×320 × 33 frames (1.375 s), with no way to change it through the skill.
Driving ltx-2-mlx directly works fine at full size — 1280×768 × 121 frames took 3m 19s on this machine — so this is a plumbing gap, not a model limitation. Worth splitting into its own issue if you'd prefer.
Notes that may help
- The registry's advice to pull weights with a targeted
--include list does not avoid the large download. The runner fetches what it needs at generate time regardless: the q4 cache ended at 56 GB and q8 at 82 GB, against repo totals of 59.7 GB and 87.5 GB.
ltx.local also silently no-ops when ltx-2-mlx is not on PATH (the provider resolves it with which). The registry's install line ends at uv sync --all-extras, which leaves the entry point inside .venv/bin. Adding a "symlink onto PATH" step would save the next person some time — codex-provider.mjs already documents exactly this lesson for the codex binary.
Package:
media-useskill ·scripts/lib/local-models.mjs,scripts/lib/ltx-video-provider.mjsVersion: hyperframes @
6eaa2cb64b280c51cadb3843ce190f6f0b7493cc(alsohyperframes@0.8.14from npm)Environment: macOS 26.5.2, Apple M5 Max, 128 GB, Node v24.18.0,
ltx-2-mlxinstalled and on PATHSummary
LOCAL_MODELS.videogen'slargetier namesdgrauet/ltx-2.3-mlx-bf16. That repo is not published — the Hugging Face API returns HTTP 401. BecauseselectModelchooses a model on RAM/GPU fit alone, any machine with ≥32 GB selects that tier, the download fails inside the provider, andresolve --type video --local-onlyfails outright.The tier's own note says it is for "64-128GB Macs for long/HD runs" — so the entry aimed at the largest machines is the one that cannot work.
Reproduction
Two commands. The first needs nothing installed.
Expected: a generated clip, or a clear "install the local model" message.
Actual:
Root cause
selectModel(local-models.mjs) does iterate and fall back — butmeetsSpecstests onlyneeds.ramMBandneeds.gpu. Model availability is never part of the fit test, so on a 128 GB machine thelargeentry "fits", is selected, and the failure surfaces later insideltxVideoGenerateat download time. The provider catches it, logs, and returnsnull.Under
--local-only,ltx.localis the last provider in thevideocascade (heygen.videois skipped as network), so anullthere ends the cascade withno provider could resolve video.Net effect: a model that cannot be downloaded is indistinguishable from a machine that cannot run it, and there is no retry at a lower tier.
Why this survived
hyperframes doctordoes not probevideogenat all — it reports heygen, ffmpeg, Chrome, Docker and node. The entry also reads as entirely plausible on inspection. It is only observable by running a local video resolve on a ≥32 GB machine.Suggested fixes
Either alone resolves it; the first two are worth having together.
largetier atdgrauet/ltx-2.3-mlx-q8, which exists. Its core subset (transformer-distilled-1.1 20.6 GB + connector 6.3 GB + VAEs + vocoder) is ~29 GB, sosizeMB: 45000should come down too. This is what I applied locally;resolve --type video --local-onlythen succeeds.nullfor a resolvable reason. A model whose weights 404/401 should demote to the next-smallest entry rather than ending the cascade.videogen/imagegentohyperframes doctor, so a broken registry entry is visible without running a generation.Second, related finding —
resolvecannot set video dimensionsltxVideoGeneratereadsctx?.width || 512,ctx?.height || 320,ctx?.frames || 33. Butresolve.mjsbuildsctxfrom exactly six fields:There is no
--width/--height/--framesflag, and nothing reads canvas size fromhyperframes.json. So those fallbacks are unreachable and every locally generated video is 512×320 × 33 frames (1.375 s), with no way to change it through the skill.Driving
ltx-2-mlxdirectly works fine at full size — 1280×768 × 121 frames took 3m 19s on this machine — so this is a plumbing gap, not a model limitation. Worth splitting into its own issue if you'd prefer.Notes that may help
--includelist does not avoid the large download. The runner fetches what it needs at generate time regardless: the q4 cache ended at 56 GB and q8 at 82 GB, against repo totals of 59.7 GB and 87.5 GB.ltx.localalso silently no-ops whenltx-2-mlxis not onPATH(the provider resolves it withwhich). The registry'sinstallline ends atuv sync --all-extras, which leaves the entry point inside.venv/bin. Adding a "symlink onto PATH" step would save the next person some time —codex-provider.mjsalready documents exactly this lesson for thecodexbinary.