Short-form, explainer, and demo video generation via a key-optional 3-tier router. Composes scripts, oma-voice narration, oma-image/oma-slide/stock visuals, key-free captions, and a vendored Remotion compositor into reproducible run directories. Routes three modes — shorts/reels (9:16), explainer (16:9 README/code/data), and demo/walkthrough (screen capture, incl. supervised headed web-app capture of any URL). Use for video, shorts, reels, short-form, demo, explainer, walkthrough, screencast, web capture, video generation, 영상, 숏폼, 쇼츠, 릴스, 데모, 설명 영상.
npx skills add https://github.com/first-fluke/oh-my-agent --skill oma-video
Generate finished .mp4 videos through a key-optional, 3-tier (CLI-first / MCP / guided) provider router while preserving deterministic asset buses (script -> timing -> render-spec), reproducible manifests, cost controls, and capture-path safety.
--mode shorts, 9:16)--mode explainer, 16:9 / 9:16)--mode demo --source file, 16:9)--mode demo --source web --url <url>) — a human drives the on-screen flow; the tool only opens a headed browser and records. Example categories are equal and illustrative only: demo, walkthrough, onboarding clip, bug repro, app-review screencast.render-spec.json--format json)oma-imageoma-slide (this skill calls it internally for explainer frames)oma-voice--source web); live streaming is out of scopeoma-explainerdemo --source file: a screen-capture file path (--capture) or Cap availabilitydemo --source web: a target --url (any URL — local/staging/prod), optional --device/--ready-selector/--show-cursor/--polish/--capture-timeout; capture size is derived from --aspect/--device (no hardcoded size); a resolvable Playwright + an interactive TTY (else the run falls back to the guided protocol).agents/results/videos/<timestamp>-<shortid>-<mode>/script.json, timing.json, render-spec.jsonaudio/, visuals/, captions.srt / captions.vtt, the rendered <mode>-<slug>.mp4manifest.json with providers, asset hashes, cost breakdown, and exit codeoutputs:
- name: video
description: rendered <mode>-<slug>.mp4 in the run directory
artifact: ".agents/results/videos/*/*.mp4"
required: true
- name: manifest
description: reproducibility record (providers, asset sha256 hashes, cost breakdown, exit code)
artifact: ".agents/results/videos/*/manifest.json"
required: true
- name: render-spec
description: deterministic compute boundary consumed by `oma video render <runDir>`
artifact: ".agents/results/videos/*/render-spec.json"
required: true
- name: captions
description: key-free caption tracks aligned to timing.json
artifact: ".agents/results/videos/*/captions.srt"
required: false
oma video generate CLI + central error module (exit codes aligned with oma search fetch)resources/remotion/ (compositor)resources/vendor-matrix.md, resources/execution-protocol.md, resources/prompt-tips.md, config/video-config.yamldemo, confirm a capture path exists (or Cap is available); otherwise enter the guided protocol.config/video-config.yaml -> env vars -> CLI flags; check output path safety and limits.demo --source web has a --url, dispatch the headed web-capture path (human-driven flow, ENTER to stop); if Playwright is unresolvable OR there is no interactive TTY, fall back to the guided protocol (no hang).demo --source file has no capture and Cap is unavailable, emit the guided capture protocol and stop (exit code maps to capture-required).order; only chain exhaustion is a stage failure.oma video doctor --install (one-time: deps + headless shell + Pretendard font); fall back to the MPT compositor where applicable (MPT itself needs a one-time oma video doctor --install-mpt).TODO(oma-deferred): whisper-cpp).<mode>-<slug>.mp4 and manifest.json exist in the run directory; all schemas validate.| Action | SSL primitive | Evidence |
|--------|---------------|----------|
| Validate brief + mode | VALIDATE | Clarification protocol, mode inference |
| Select provider strategy | SELECT | Vendor matrix, providers.*.order, availability |
| Read brief / capture | READ | Brief text, --capture path |
| Generate script | CALL_TOOL | AgentScriptProvider -> script.json |
| Synthesize narration + timing | CALL_TOOL | oma-voice -> audio/*.wav + timing.json |
| Produce visuals | CALL_TOOL | oma-image / oma-slide / stock -> visuals/* |
| Build captions | WRITE | key-free captions.srt / .vtt from timing |
| Compose render-spec | WRITE | render-spec.json (determinism boundary) |
| Render video | CALL_TOOL | Remotion / MPT compositor -> <mode>-<slug>.mp4 |
| Validate result | VALIDATE | Schema parse, manifest hashes, exit code |
| Report output | NOTIFY | Run-dir + mp4 path summary |
oma video generate, oma video doctor, oma video list-providers, oma video renderresources/remotion/), prompt tips, vendor matrix, video configoma video doctor
oma video generate "<brief>" --mode shorts --aspect auto --captions tiktok --format json
Explainer from a README, with a deterministic seed:
oma video generate "explain this project" --mode explainer --aspect 16:9 --seed 42 --out ./out
Demo from a screen capture:
oma video generate "feature walkthrough" --mode demo --capture <absolute-path>.mp4
Deterministic re-render from an existing run:
oma video render .agents/results/videos/20260603-143052-ab12cd-shorts
| Scope | Resource target |
|-------|-----------------|
| LOCAL_FS | Briefs, captures, assets, render-spec, run dir, manifests |
| PROCESS | oma-image / oma-slide CLIs, Remotion / MPT, Cap CLI, Playwright web-capture driver (subprocess) |
| NETWORK | Voicebox MCP (localhost), oma-image vendor APIs, the user-supplied --url for web capture (masked in logs/manifest), optional Pexels / Pixelle / RunningHub |
| CREDENTIALS | oma-image vendor auth, optional PEXELS_API_KEY / RUNNINGHUB_API_KEY. Web capture handles NO credentials — a human logs in if the flow needs it; nothing is stored or printed. |
$PWD (or --allow-external-out is set).demo --source file: the capture path exists, is absolute/$PWD-guarded, and is a valid format.demo --source web: a --url is supplied (else SchemaValidationError); a resolvable Playwright + an interactive TTY exist (else the run falls back to the guided protocol).Clarification Protocol below.cost.guardrail_usd ($0.20, configurable) or --max-usd. --yes / OMA_VIDEO_YES=1 bypass. Local/free paths carry zero cost.$PWD require --allow-external-out. --capture is absolutized, $PWD-guarded, and format-validated; external assets are copied into the run dir and hashed (no URL refs).render-spec.json + asset files (+ seed + embedded Pretendard font) are the determinism boundary. oma video doctor --install fetches the Pretendard woff2 once; if offline, the render gracefully falls back to system fonts, and byte-identical output across machines is only guaranteed once the font is present. Re-rendering the same render-spec is byte-stable; OMA_VIDEO_MOCK=1 replays golden fixtures.limits.max_duration_sec = 180, limits.max_scenes = 40 (wall-time + memory bound).--max-usd.--source file the skill guides but does not screen-record autonomously; for --source web the tool only opens a headed browser and records while the human drives the entire on-screen flow (interactive ENTER to stop). The mechanism prescribes nothing about what the flow is or what the recording is for.10. Web-capture security: NO credential automation of any kind — if a flow needs a login, a human performs it. The driver runs as a subprocess under the resolved Playwright (never imported into the CLI). The --url and any query tokens are masked in logs and in manifest.json; credentials are never stored or printed. Recording and all outputs are confined to the run dir. On-screen sensitive input is captured as-is — the user controls the flow. Multi-page navigation (popup / new tab / redirect) is recorded generically, with no assumption about the flow's shape.
11. Web capture is key-optional + non-blocking: web capture is the real branch; the guided protocol is the fallback when Playwright is unresolvable OR there is no interactive TTY (CI / -y / no stdin) — the run falls back to guided and never hangs. Live capture is outside the determinism boundary, so the manifest records nondeterministic: true.
12. Headed capture needs a display: web capture launches a headed Chromium so the human can drive the flow. On display-less hosts (CI / Linux without X), pass --capture-stop duration:<sec>|selector:<css> — the driver then runs headless (resources/playwright/record.mjs --headless 1) — or expect a capture error / guided fallback.
13. Run-dir retention: .agents/results/videos/<run>/ accumulates one directory per run (assets + mp4 + manifest) and is never auto-pruned; the user deletes old run directories manually.
14. Exit codes align with oma search fetch (0 ok, 1 generic, 2 safety, 3 not-found, 4 invalid-input, 5 auth-required, 6 timeout).
Before invoking oma video generate, the calling agent runs this checklist. If any answer is "no / unknown", clarify or infer-and-confirm with the user first.
Required signal (must be present or inferable):
demo --source web — a --url)demo: --source file (a --capture path) or --source web (a --url)? For --source web, state up front that a human drives the on-screen flow and that the tool never automates any login.Strongly recommended (ask if absent AND not inferable):
9:16 (shorts/reels), 16:9 (explainer/demo), 1:1, or auto (snaps to the mode default).tiktok (centered, static windowed cues), lower-third, or none.auto (derived from the script).none; music upbeat / calm / none. The default voice is none → a silent video with estimated caption timing. Pass --voice <profile> (a Voicebox profile) whenever narration is expected. Music is rendered offline by Strudel and mixed at −18 dB; it needs a one-time oma video doctor --install-strudel and degrades to no music without it.Amplification shortcut. For a one-line brief (e.g. "shorts about Jeju coffee"), do not pop a questionnaire if the request is genuinely simple. Instead amplify inline and show the user the inferred plan before invoking:
> User: "make a short about Jeju coffee"
> Agent: "I'll generate this as: *mode shorts, 9:16, ~30s, oma-image stills with Ken Burns, TikTok captions, locale en, calm music*. Proceed, or adjust mode/aspect/voice?"
Skip clarification when the user authored a full brief (mode + topic + aspect + captions). Respect their flags verbatim.
Output language. Narration and on-screen text are authored in the requested locale. Image-generation prompts passed to oma-image are sent in English (image models are trained predominantly on English captions); translate the user's request and show the translated version during amplification.
| Mode | Aspect | Source | Default visual | Compositor | Output |
|------|:---:|--------|----------------|------------|--------|
| shorts | 9:16 | synthetic (topic) | oma-image stills + Ken Burns; Pexels (key) · Pixelle AIGC (key) opt | Remotion · MPT alt | shorts-<slug>.mp4 |
| explainer | 16:9 / 9:16 | README · code · data | oma-slide frames + oma-image diagrams + code | Remotion (deterministic) | explainer-<slug>.mp4 |
| demo | 16:9 | --source file (Cap / capture file) · --source web (headed browser at --url) | raw footage (default) · Remotion intro · zoom · callouts (--polish) | Remotion polish | demo-<slug>.mp4 |
| Tier | Surface | Providers | Trigger |
|:---:|---------|-----------|---------|
| 1 | CLI-first (subprocess, deterministic) | Remotion render, MPT, oma-image, oma-slide, oma-voice | always available (key-free defaults) |
| 2 | MCP | Voicebox MCP (voice/timing), Pixelle-MCP (AIGC, off by default) | MCP server reachable; Pixelle needs explicit consent + key |
| 3 | Guided (human-in-the-loop) | Playwright headed web capture (--source web, human drives the flow), Cap (capture), guided protocol fallback | demo mode; web capture needs a resolvable Playwright + a TTY (else guided protocol) |
/oma-video make a 30s short about Jeju coffee
/oma-video --mode explainer --aspect 16:9 explain this project from the README
/oma-video --mode demo --source file --capture ~/recordings/walkthrough.mp4 feature demo
/oma-video --mode demo --source web --url http://localhost:3000 record my app flow
/oma-video --mode demo --source web --url <url> --ready-selector "#app" --polish onboarding clip
oma video generate "<brief>" [--mode shorts|explainer|demo] \
[--aspect 9:16|16:9|1:1|auto] [--locale <lang>] \
[--captions tiktok|lower-third|none] \
[--visual auto|generate|stock|aigc|slide] \
[--voice <profile>|none] [--music upbeat|calm|cinematic|lofi|piano|none] \
[--duration <sec>|auto] [--compositor remotion|mpt] \
[--capture <path>] \
[--source file|web] [--url <url>] [--device <name>] \
[--ready-selector <css>] [--show-cursor] [--polish] \
[--capture-timeout <sec>] [--capture-stop duration:<sec>|selector:<css>] \
[--out <dir>] [--allow-external-out] \
[--max-usd <n>] [--seed <n>] [--timeout 600] [-y] \
[--dry-run] [--script <path>] \
[--format text|json] [--no-brief-in-manifest]
# --script: inject the agent-authored script.json (agent-as-key). Without it the
# CLI builds its own skeleton script from the brief — always pass the script
# the agent wrote so narration/on-screen text/visual prompts are honored.
# --source web: headed browser at --url; capture size derived from --aspect/--device (no hardcoded size).
# A human drives the on-screen flow; press ENTER to stop. NO credential automation. --url/tokens masked.
# Non-interactive (CI / -y / no TTY) or unresolvable Playwright -> falls back to the guided protocol (no hang).
# --capture-stop gives CI a non-interactive stop (duration / selector) in place of the ENTER prompt.
oma video doctor # readiness report only (no install): Node/Chromium/FFmpeg · Remotion project · Pretendard font · MPT · Playwright · Voicebox MCP · oma-image vendors · Pixelle-MCP · Cap
oma video doctor --install # one-time: vendored Remotion deps + Chrome Headless Shell + Pretendard font fetch (offline -> warn, system-font fallback)
oma video doctor --install-mpt # one-time: MoneyPrinterTurbo checkout (clone + venv + deps) for --compositor mpt
oma video doctor --install-playwright # one-time: npm i playwright + chromium (web capture)
oma video list-providers # availability + key/fallback status
oma video render <runDir> # re-render from render-spec.json (deterministic)
Other skills call oma video generate --format json and parse the JSON envelope ({exitCode, runDir, manifestPath, scriptPath, renderSpecPath, warnings, error}) from stdout. There is no outputs key — read output/asset paths from the manifest at manifestPath. The deterministic boundary is render-spec.json + assets, so a downstream consumer can re-render via oma video render <runDir> without re-running script/voice/visual generation.
.agents/results/videos/
└── 20260603-143052-ab12cd-shorts/ # {timestamp}-{shortid}-{mode}
├── script.json # determinism boundary start
├── timing.json
├── render-spec.json # deterministic compute boundary
├── audio/
│ └── narration-01.wav # single narration track (ALL lines joined — not per-scene)
├── visuals/
│ └── scene-01.jpg …
├── captions.srt
├── captions.vtt
├── shorts-<slug>.mp4
└── manifest.json # reproducibility record
audio/narration-01.wav, referenced by render-spec.audio.narration. There are no per-scene narration-NN.wav files.timing.json (voicebox-stt -> estimated; the tts-native and whisper-cpp source values are reserved but not yet wired — TODO(oma-deferred): whisper-cpp); scene boundaries and caption cues are derived from it..srt (+ .vtt) built from timing.json; render-spec.captions.file points at the .srt. The compositor renders static windowed cues — the cue active at the current frame, CSS-wrapped (no per-word animation).--music <preset> renders a BGM bed with Strudel and mixes it under narration at render-spec.audio.musicGainDb (default −18 dB). The bed is generated offline (headless Chrome + OfflineAudioContext), so it needs no key, no network, and no audio device — a 30s bed renders in well under a second.calm (sustained pad + arpeggio), upbeat (bright plucks), cinematic (drone build to a lead), lofi (warm chords, swung ticks), piano (neoclassical arpeggio). Each preset picks its key and mode from the run seed, so the same preset sounds different run to run without a second pattern.music/bgm.wav (mixed by the compositor), music/bgm.mp3 (preview), music/bgm-raw.wav (pre-master), and music/pattern.strudel — the source that produced them, editable and re-renderable by hand.musicGainDb means the same thing for every preset. Normalisation is deliberately *not* loudnorm's one-pass mode, which flattens the arrangement arc.@strudel/* is AGPL-3.0-or-later while the oma CLI is MIT, so the deps are never bundled and never installed implicitly. Run oma video doctor --install-strudel once. The CLI never imports Strudel — it spawns resources/strudel/render.mjs as a subprocess, the same boundary the Remotion / Playwright projects use.audio.music stays unset (never a dangling staticFile() ref).white / pink / brown) draw from Math.random() and would break that, so the templates avoid them.Follow resources/execution-protocol.md step by step.
See resources/vendor-matrix.md for provider precheck + fallback-chain rules.
Author --script files against resources/script-schema.md (full field reference + example; schemaVersion: "1.0" is required).
Use resources/prompt-tips.md for writing effective briefs per mode.
Before submitting, run resources/checklist.md.
The vendored Remotion compositor lives at resources/remotion/ (see its README.md).
The web-capture driver lives at resources/playwright/record.mjs (runs as a subprocess under the resolved Playwright; never imported into the CLI).
The MPT fallback compositor driver lives at resources/mpt/driver.py (consumed by the CLI's mpt-project internals).
Project-specific settings: config/video-config.yaml.
Env vars: OMA_VIDEO_DEFAULT_MODE, OMA_VIDEO_DEFAULT_OUT, OMA_VIDEO_YES, PEXELS_API_KEY, RUNNINGHUB_API_KEY (+ POLLINATIONS_API_KEY via oma-image), OMA_VIDEO_MOCK, OMA_VIDEO_PLAYWRIGHT_DIR (web-capture Playwright override), OMA_VIDEO_PWTEST (opt-in web-capture e2e).
resources/execution-protocol.mdresources/vendor-matrix.mdresources/prompt-tips.mdresources/checklist.mdresources/remotion/README.md../_shared/core/context-loading.mdCreate beautiful visual art in .png and .pdf documents using design philosophy. You should use this skill when the user asks to create a poster, piece of art, design, or other static piece. Create original visual designs, never copying existing artists' work to avoid copyright violations.
Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.
Improves the quality of images, especially screenshots, by enhancing resolution, sharpness, and clarity. Perfect for preparing images for presentations, documentation, or social media posts.
Downloads videos from YouTube and other platforms for offline viewing, editing, or archival. Handles various formats and quality options.
Lightweight WSI tile extraction and preprocessing. Use for basic slide processing tissue detection, tile extraction, stain normalization for H&E images. Best for simple pipelines, dataset preparation, quick tile-based analysis. For advanced spatial proteomics, multiplexed imaging, or deep learning pipelines use pathml.
Microscopy data management platform. Access images via Python, retrieve datasets, analyze pixels, manage ROIs/annotations, batch processing, for high-content screening and microscopy workflows.
Python library for working with DICOM (Digital Imaging and Communications in Medicine) files. Use this skill when reading, writing, or modifying medical imaging data in DICOM format, extracting pixel data from medical images (CT, MRI, X-ray, ultrasound), anonymizing DICOM files, working with DICOM metadata and tags, converting DICOM images to other formats, handling compressed DICOM data, or processing medical imaging datasets. Applies to tasks involving medical image analysis, PACS systems, radiology workflows, and healthcare imaging applications.
This skill should be used when working with pre-trained transformer models for natural language processing, computer vision, audio, or multimodal tasks. Use for text generation, classification, question answering, translation, summarization, image classification, object detection, speech recognition, and fine-tuning models on custom datasets.
Take first-fluke/oma-video from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference npm.
Without those the skill loads but fails at the first command.