aigc-video — AI Video Generation (Doubao Seedance 2.0)
Create a short video (4–15 s) from a text prompt or from a still image, via
Volcengine Ark Doubao Seedance 2.0. The skill drives the asynchronous ARK
tasks API: it submits a task, polls until it succeeds, downloads the
result to a local file, auto-uploads to KB-Server (OSS), and outputs a
Markdown video  for inline chat rendering. Falls back to
a raw URL on upload failure.
This skill is asynchronous end-to-end: typical wall-clock time is
30–120 s per video.
🚨 Agent output rules (CRITICAL)
Interpreter
Always invoke scripts with python3, never bare python.
Local save path (CRITICAL)
Always pass --out under the workspace (session project root), never
/tmp/.... Recommended:
aigc_outputs/<short-name>.mp4
Create the directory if needed (mkdir -p aigc_outputs). Use the stderr line
[seedance] saved local copy: ... and convert it to a workspace-relative
path for the reply link (e.g. aigc_outputs/corgi.mp4).
Chat reply
When create_task.py (or poll_task.py) completes successfully, its last stdout
line is a Markdown video . You MUST include this line
verbatim in your chat reply immediately — do NOT just describe the result
in text and wait for the user to ask. The Markdown will be rendered as an inline
<video> player by the frontend.
Also add a Markdown workspace file link (must be [label](path), not a bare
path) so the user can one-click open the local mp4 in the Files panel.
Correct reply after script succeeds:
视频已生成!

5 秒,1080p。
[打开本地文件](aigc_outputs/corgi.mp4)
Wrong — bare path (not clickable):
视频已生成,本地文件:aigc_outputs/corgi.mp4
Wrong — do NOT do this:
视频已生成完毕,URL 是 https://kb-server.../clip.mp4,你可以点击查看。
> If the script prints URL: <temp url> (fallback because OSS upload failed),
> you MUST still output it visibly. In that case use a clickable link:
> [点击播放视频](<url>), and still include [打开本地文件](aigc_outputs/...)
> when a local copy was saved.
When to use
| Want | Use |
|---|---|
| New video clip from a text prompt | scripts/create_task.py |
| Animate an existing image (image-to-video) | scripts/create_task.py --image <url-or-path> |
| Just check a previously created task's status | scripts/poll_task.py <task_id> |
The single-shot "submit and wait" path (recommended) is create_task.py
without --no-wait — it submits, polls every 5 s, downloads the video, and
prints the final URL when the task succeeds.
Required environment
The skill ships with a working API key built in, so no configuration is
required. To use your own Volcengine Ark key, override it:
export ARK_API_KEY=ark-xxxxxxxxxxxxxxxx # or VOLCENGINE_API_KEY (synonym)
# Optional — override the Ark base URL (the script appends /contents/generations/tasks):
# export VOLCENGINE_BASE_URL=https://ark.cn-beijing.volces.com/api/v3
Models
--variant |
Model id | Notes |
|---|---|---|
standard |
doubao-seedance-2-0-260128 |
Doubao-Seedance-2.0 (default) |
fast |
doubao-seedance-2-0-fast-260128 |
Doubao-Seedance-2.0-fast |
fast trades some fidelity for speed and lower cost. Iterate on fast, then
re-render the keeper on standard.
Quick recipes
1. Text → video (most common)
mkdir -p aigc_outputs
python3 ${CLAUDE_SKILL_DIR}/scripts/create_task.py \
"A corgi sprinting along a sunset beach, slow-motion, golden-hour light" \
--ratio 16:9 \
--resolution 1080p \
--duration 5 \
--out aigc_outputs/corgi.mp4
The script blocks for ~30–120 s and prints progress to stderr:
[seedance] task created: cgt-20260615-abcdef
[seedance] status=queued elapsed=2s
[seedance] status=running elapsed=18s
[seedance] status=succeeded elapsed=47s
[seedance] video url: https://ark-content-generation-v2-cn-beijing.tos-cn-beijing.volces.com/...
[seedance] saved local copy: aigc_outputs/corgi.mp4
[seedance] uploaded to OSS: https://kb-server.caryscloud.com/.../clip.mp4

The last stdout line is a Markdown video  — react-markdown
renders it as an inline <video> player in the chat. The OSS URL is permanent;
the local file (--out) is also kept for local use.
On OSS upload failure the script gracefully falls back to
URL: <temporary video URL> (the Volcengine CDN link, valid ~24 h).
Use --no-upload to skip upload entirely.
2. Image → video (animate a still)
python3 ${CLAUDE_SKILL_DIR}/scripts/create_task.py \
"Camera slowly orbits around the subject, gentle wind moves the leaves" \
--image /path/to/photo.jpg \
--ratio 16:9 \
--duration 5 \
--out aigc_outputs/animated.mp4
--image accepts a public URL or a local file path. Local files are
base64-inlined into the request automatically (no upload service needed).
Supported formats: jpeg / png / webp / bmp / tiff / gif; keep a single image
under ~30 MB (for larger files prefer a public URL).
3. Generate with native audio (Seedance 2.0 feature)
python3 ${CLAUDE_SKILL_DIR}/scripts/create_task.py \
"Rain falling on a quiet city street at night, neon reflections" \
--generate-audio --duration 5 \
--out aigc_outputs/rain.mp4
--generate-audio enables Seedance 2.0's synchronized audio (ambience / SFX).
Off by default.
4. Submit, then poll later (long-running, async pipelines)
TASK_ID=$(python3 ${CLAUDE_SKILL_DIR}/scripts/create_task.py \
"fireworks bursting over a harbour at night, cinematic" \
--ratio 16:9 --duration 5 --no-wait | awk '/^TASK_ID:/{print $2}')
# ...some time later, possibly in a different shell:
python3 ${CLAUDE_SKILL_DIR}/scripts/poll_task.py "$TASK_ID" --out aigc_outputs/clip.mp4
poll_task.py blocks until the task finishes, downloads the video, and prints
URL: <video URL> exactly the same way create_task.py does.
5. Use the faster / cheaper model
python3 ${CLAUDE_SKILL_DIR}/scripts/create_task.py \
"a paper crane folding itself" \
--variant fast --duration 5 \
--out aigc_outputs/crane.mp4
CLI reference
create_task.py (text-to-video / image-to-video)
| Flag | Default | Notes |
|---|---|---|
prompt (positional) |
— | English or Chinese |
--image |
— | Optional public URL or local path. Presence switches mode to image-to-video |
--ratio |
16:9 |
One of 16:9 / 9:16 / 4:3 / 3:4 / 21:9 / 1:1 / adaptive |
--resolution |
1080p |
One of 480p / 720p / 1080p / 2K |
--duration |
5 |
Seconds, 4–15 |
--variant |
standard |
standard (Seedance 2.0) or fast (Seedance 2.0 fast) |
--model |
(resolved from variant) | Override the model id directly |
--out |
./aigc_video_<ts>.mp4 |
Local download path — prefer aigc_outputs/<name>.mp4 (workspace) |
--seed |
random | Reproducibility |
--generate-audio |
off | Generate native audio |
--watermark |
off | Set to enable Volcengine watermark |
--no-wait |
off | Submit and exit; print TASK_ID: <id> for later polling |
--no-download |
off | Skip local save; print the temp URL only |
--no-upload |
off | Skip OSS upload; output raw URL instead of Markdown video |
--poll-interval |
5 |
Seconds between status polls |
--max-wait |
600 |
Hard ceiling for polling (seconds) |
--timeout |
120 |
Per-HTTP-request timeout |
poll_task.py (resume / follow an existing task)
| Flag | Default | Notes |
|---|---|---|
task_id (positional) |
— | The id printed by create_task.py --no-wait |
--out |
./aigc_video_<ts>.mp4 |
Local download path — prefer aigc_outputs/<name>.mp4 (workspace) |
--no-download |
off | |
--no-upload |
off | Skip OSS upload; output raw URL instead of Markdown video |
--poll-interval |
5 |
|
--max-wait |
600 |
|
--timeout |
120 |
Exit codes for both: 0 success, 1 runtime error (network, ARK error,
download failure, task failed/cancelled), 2 configuration error.
Output & the temporary URL
On success the skill downloads the video to --out (the durable artifact),
auto-uploads to KB-Server (OSS), and prints a Markdown video
 as its last stdout line. The OSS URL is permanent.
On OSS upload failure (KB-Server unreachable, network error, etc.), the script
falls back to URL: <temporary video URL>. That URL is a Volcengine CDN link
that expires ~24 h after the task succeeds. Use --no-upload to skip the
upload and always output the raw URL.
Aspect-ratio / resolution / duration
| Parameter | Supported values |
|---|---|
--ratio |
16:9, 9:16, 4:3, 3:4, 21:9, 1:1, adaptive |
--resolution |
480p, 720p, 1080p, 2K |
--duration |
4–15 seconds |
See references/video-params.md for a full
discussion. In practice --ratio 16:9 --resolution 1080p --duration 5 is the
sweet spot for cost/quality and is close to the default.
Prompt-writing tips for video
See references/prompt-formula-video.md. Short version:
[subject doing action] , [camera motion] , [lighting / time of day] , [style] , [pacing/mood]
The single most important new dimension over still-image prompts is
camera motion. Always specify one of: static, slow pan, slow
push-in, dolly, orbit, tracking shot. Without it, Seedance picks
something erratic.
A corgi sprinting along a sunset beach, slow tracking shot from the
left, golden-hour sunlight, photorealistic, joyful and energetic
Failure modes & recovery
| Symptom | Likely cause / fix |
|---|---|
exit 2 "API key not set" |
Export ARK_API_KEY or VOLCENGINE_API_KEY (a default ships built in) |
ARK error model not found / 403 |
The key lacks access to Seedance 2.0, or the model id's date suffix changed — see scripts/ark_client.py |
Task status failed with policy_violation |
The prompt or input image hit a content filter; rewrite |
Task stuck in queued for >10 min |
ARK is overloaded; cancel & retry, or wait — queued time does not count toward generation |
--max-wait exceeded |
Bump --max-wait, or run with --no-wait and resume via poll_task.py |
download failed, only URL printed |
Network issue downloading the CDN file; the printed URL is still valid for ~24 h |
| OSS upload failed, falling back to temp URL | KB-Server unreachable or auth issue; local file is still saved and CDN URL is printed |
Internals (for maintainers)
scripts/
├── __init__.py
├── create_task.py # POST task + (default) wait + download → OSS
├── poll_task.py # GET status until done + download → OSS
├── ark_client.py # ARK contents/generations/tasks client (models, request shape, key)
├── download.py # stream the result video to a local file
└── url_utils.py # tiny URL helpers (http(s) detection)
The skill is fully self-contained: no sibling skills, no external upload
service. See README.md for maintainer notes.
After saving locally, both scripts import upload_file() from the sibling
upload-oss-direct skill and upload to KB-Server. Upload is graceful:
failure never causes the script to exit non-zero — the local file is always
available as a fallback.