Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Seedance 2.0 video & image generation via LibTV Gateway - AI text-to-video, image-to-video, video continuation, style transfer, and text-to-image using Seedance 2.0 model. Also supports Kling 3.0, Wan 2.6, Midjourney, Seedream 5.0. Trigger phrases: seedance, generate video, make a video, generate image, make an image, draw, libtv, liblib.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-09 | ✗→✓ | ▲ Improved | 195% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 219% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 105% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 318% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 99% | 0% |
Generate AI images and videos through one bundled LibTV skill, powered by Seedance 2.0. Supports text-to-image, image-to-image, text-to-video, and image-to-video workflows, via both Nexu-managed Seedance execution and direct LibTV execution with a user-owned sk-libtv-... key.
Key routing:
mgk_... keys use Nexu-managed Seedance through https://seedance.nexu.io/sk-libtv-... keys use direct LibTV OpenAPI through https://im.liblib.tvDelivery architecture (currently Feishu only):
create-session captures OPENCLAW_CHANNEL_TYPE + OPENCLAW_CHAT_ID,persists them as the session's delivery block, forks a detached wait-and-deliver background process via subprocess.Popen(..., start_new_session=True), and returns immediately with a single-line JSON submit confirmation on stdout.
direct LibTV) and, on terminal success, shells out to feishu_send_video.py — the same proven helper used by medeo-video — which downloads each result URL, uploads it to Feishu's file API, and posts a native media message to the originating chat.
$NEXU_HOME/libtv-waiter-<id>.logfor post-hoc debugging. A delivered_at timestamp is persisted when the Feishu helper reports success, so re-invoking wait-and-deliver on a delivered session is a safe no-op.
No sessions_spawn, no subagent model-speech contract, no HTTP notification callback, no stale routing fields. Delivery is a direct HTTP call using stable per-user identifiers (open_id / chat_id) that never go stale the way the old account_id did.
Multi-channel support is a follow-up: adding Discord / Slack / WeChat means dropping a new <channel>_send_video.py helper next to feishu_send_video.py and adding one branch in _deliver_results.
apiKey configured in ~/.nexu/libtv.jsonvideoRatio configured in ~/.nexu/libtv.json or implicit default 16:9mgk_... keys target https://seedance.nexu.io/sk-libtv-... keys target https://im.liblib.tvIf the user has not configured an API Key, guide them to:
mgk_...sk-libtv-...python3 scripts/libtv_video.py setup --api-key <your_key> --video-ratio 16:9python3 scripts/libtv_video.py check to confirm the configuration is correctTo change only the default ratio later:
bashpython3 scripts/libtv_video.py update-ratio --video-ratio 9:16
python3 scripts/libtv_video.py checkYou are a messenger, not a creator. The backend agent handles model selection, prompt engineering, and workflow orchestration. Your job is three things only:
upload to get OSS URLcreate-sessionNever do these:
--channel and --chat-idBefore running create-session you must extract the originating channel and the user's stable identifier from the inbound message metadata block and pass them as CLI args. Without these the background waiter cannot deliver the finished video back to the user automatically; the user will have to ask for the result manually.
untrusted metadataJSON block containing sender_id. That value is the stable open_id (always starts with ou_). Pass it as --chat-id and pass --channel feishu.
Example extraction and invocation:
textConversation info (untrusted metadata): { "message_id": "om_x100...", "sender_id": "ou_33314772052f837a3cb2f919aa4605de", ... }
becomes:
bashpython3 scripts/libtv_video.py create-session "user's video description" \ --channel feishu \ --chat-id ou_33314772052f837a3cb2f919aa4605de
The stdout JSON returned by create-session includes a deliverable flag. If it is false, your --channel / --chat-id were missing and the user will have to ask you for the result later.
bashpython3 scripts/libtv_video.py create-session "user's video description" \ --channel feishu --chat-id <ou_xxx from inbound metadata>
Message rules:
mgk_... mode appends the Seedance 2.0 hint unless the user already chose a modelsk-libtv-... mode follows the upstream relay discipline and does not add the Seedance model hint16:9bash# 1. Upload the image first python3 scripts/libtv_video.py upload --file /path/to/image.png # Output: url=https://libtv-res.liblib.art/... # 2. Create session with the image URL in the message python3 scripts/libtv_video.py create-session "user's description reference: {oss_url}"
bashpython3 scripts/libtv_video.py create-session "new description" \ --session-id SESSION_ID \ --channel feishu --chat-id <ou_xxx from inbound metadata>
create-session returns immediately without blocking and prints asingle-line JSON {"status":"submitted", "sessionId", "projectUuid", "projectUrl", "channel", "deliverable", "note"} to stdout.
note field as a hint:"Your video task has been submitted and is now generating. I'll notify you when it finishes."
create-session has forked a detached wait-and-deliverbackground process that polls the upstream API for you.
as a native video message directly to the originating Feishu chat via feishu_send_video.py. You do not need to speak the result yourself.
deliverable is false (no channel context captured), the user willneed to ask for the result explicitly via query-session or recover.
python3 scripts/libtv_video.py query-session SESSION_IDpython3 scripts/libtv_video.py recover to see all sessionsIf you don't remember whether a video was previously generated:
python3 scripts/libtv_video.py recoverWhen generation completes, show both:
Do NOT show the project canvas link while generation is in progress.
The valid result URL prefixes are:
https://libtv-res.liblib.art/sd-gen-save-img/https://libtv-res.liblib.art/claw/Any other domain (for example medeo-res.liblib.art) is not a final result URL and must be ignored.
Always present the URL exactly as extracted by the script. Do not:
The extract_result_urls() function in the script extracts only valid libtv-res.liblib.art result URLs. Trust its output.
When running multiple video generations concurrently, you MUST follow these rules strictly:
Maintain a clear mapping for each generation request:
create-session)create-session)Before presenting results, always verify:
When presenting results from multiple concurrent sessions, always label which result belongs to which request:
Scene 1 (palace): [video URL from session A]
Scene 2 (garden): [video URL from session B]If some sessions complete before others:
When any command returns an error:
| Error keyword seen | Suggested action | |---|---| | "Invalid API Key" | Run check, contact admin to confirm key | | "Free trial uses exhausted" | Contact admin for a new key | | "Key expired" | Contact admin for a new key, run update-key | | "Service temporarily unavailable" | Wait a few minutes and retry | | "File too large" | Suggest the user send a smaller file (max 200MB) | | "Unsupported file type" | Only image and video files are supported | | "Cannot connect to gateway" | Check network connectivity |
This skill has a hard anti-hallucination rule. The model must verify each step before it can describe that step as successful.
Submit step checks:
~/.nexu/libtv.json exists and contains a non-empty apiKeymgk_ or sk-libtv-mgk_... keys target https://seedance.nexu.io/ unless a deliberate local test override is setsk-libtv-... keys target https://im.liblib.tv unless a deliberate local test override is setsk-libtv-... key through the Nexu Seedance gateway16:9create-session returns a real sessionIdcreate-session returns a real projectUuidsession_id, project_uuid, status=submittednote field from create-session stdout to acknowledge the submission to the userBackground delivery checks (handled by the detached waiter, not by the model):
delivered_at after feishu_send_video.py returns success; re-running wait-and-deliver on a delivered session is a safe no-opfeishu_send_video.py fails, the error is logged to $NEXU_HOME/libtv-waiter-<session-id>.log; the result URLs remain persisted locally so the user can ask query-session to retrieve themstatus is set to timeout; the user will have to ask later via query-session or recoverOutput rule:
| Scenario | Command | Blocking? | |---|---|---| | First-time setup | setup --api-key <mgk_xxx|sk-libtv_xxx> | No | | Check status | check | No | | Update key | update-key --api-key <mgk_xxx|sk-libtv_xxx> | No | | Update ratio | update-ratio --video-ratio 9:16 | No | | Remove key | remove-key | No | | Upload file | upload --file /path/to/file | No | | Create session / send message | create-session "description" | No | | Query session | query-session SESSION_ID | No | | Download results | download-results SESSION_ID | No | | Wait and deliver | wait-and-deliver --session-id ID --project-id UUID | Yes | | List all tasks | tasks | No | | Recover sessions | recover | No | | Change project | change-project | No |
Script path for all commands: scripts/libtv_video.py
Other measured skills in the registry, with their headline benchmark lift.