Skip to content

Local video generation is broken on every Mac with ≥32 GB RAM (videogen large tier points at an unpublished repo) #3508

Description

@jdstark4

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.

  1. 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.
  2. 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.
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions