# Media Bridge: working contract for an agent

1. Run `media doctor` / `media_health`. Exit 0 means authenticated and a worker is
   online; exit 2 means authenticated but the home worker is offline or paused. Jobs can
   still queue. Exit 1 is a setup/auth/network failure. Health never generates.
2. Read `media capabilities` / `media_capabilities`, then the relevant guide.
   The live schema is authoritative. Readiness does not promise artistic quality.
3. Clarify the intended shot, duration, aspect ratio, input image and audio role.
   Use one request per clip. Avoid spending GPU time on an ambiguous brief.
4. Upload local files with `media upload FILE` / `media_upload`. Paths belong to
   the client computer. Put returned `id` values under `assets`; never put URLs,
   local/server paths or base64 in a generation request.
5. Write UTF-8 JSON. Validate with `media jobs validate --file request.json` or
   `media_validate`; inspect the resolved model, dimensions, frame count and seed.
6. Submit with a stable, unique idempotency key for this exact request. Record the
   returned job ID immediately. If a network response is lost, repeat the same
   request with the same key. Never invent a new key just to retry transport.
7. Poll status or use CLI wait. A timeout/disconnection does not cancel work.
   Reconnect to the original job. Submit a new key only for a deliberately new take.
8. On success download `result.assets.output`. CLI `jobs download` resolves this
   automatically. MCP `media_download` takes an asset ID and client output path.
   A completed job may also provide preview/manifest assets. Downloads check SHA256.
9. Inspect/play the actual result. Technical validity and artistic acceptance are
   separate. Report the job ID, resolved model/seed, result path and quality issues.
   Do not report a submitted/queued job as a finished video.

## Operations and audio modes

| Intent | Request |
| --- | --- |
| Text → silent video | `video.generate`, `audio_mode: none` |
| First image + text → video | Same, plus `assets.image` |
| Let LTX generate video and sound/dialogue | `audio_mode: generate` |
| Supplied audio should influence motion/mouth | `audio_mode: condition`, `assets.audio`; image optional |
| Supplied audio is only the soundtrack | `audio_mode: attach`, `assets.audio`; image optional |
| Text → local speech | `speech.generate`, `profile: omnivoice` |
| Add/replace soundtrack of an existing clip | `media.audio_attach`, `assets.video` + `assets.audio` |

`condition` is a generative constraint, not a guarantee of exact lip sync.
`attach` does not synchronize a mouth. Attachment replaces the video's audio;
it does not mix the existing soundtrack. `audio_gain_db`, `audio_offset_seconds`
and `audio_fit` (`pad`, `loop`, `trim`) control the supplied audio.

Music, SFX, concatenation and effects are in development and rejected before
queuing. No paid provider is enabled. There is no arbitrary shell, model-install
or server-file access through these tools.

## Limits and practical behavior

- Video 1–12 seconds, 24 fps, each dimension 256–1280 in multiples of 64, at most
  983040 pixels. Use 1280×704 landscape or 704×1280 portrait as starting points.
- Native frame counts round to 8n+1; actual duration can slightly exceed the request.
- Prompt ≤8000 characters; speech text ≤1000. Upload ≤100 MiB. Inputs ≤120 seconds.
- Queue ≤20 active jobs per owner, storage quota 2 GiB per owner, one GPU executor.
- Home may sleep/be offline. Do not rapidly submit repeated jobs while waiting.
- Failed/interrupted GPU work needs inspection and an explicit new take. The
  service reconnects delivery; it does not resume interrupted GPU computations.
- Cancellation is asynchronous. Check terminal status before replacement work.
- Keep keys in the configured private file, out of prompts, URLs, screenshots,
  repository files and logs. A separate key belongs to each client identity.

## Minimal first shot

```json
{
  "operation": "video.generate",
  "profile": "ltx25",
  "prompt": "A ceramic teapot on a wooden table beside a rain-streaked window. Steam rises in a thin curl. The camera slowly moves closer. Soft overcast daylight, calm naturalistic cinematography. No captions or visible text.",
  "duration_seconds": 3,
  "width": 1280,
  "height": 704,
  "audio_mode": "none",
  "seed": 41001
}
```

During onboarding, validate this request without submitting. Actual generation
should follow the user's creative request, not an automatic installation test.
