Agent skill

Media Gen

by clacky-ai in clacky-ai/openclacky

Generate or edit images, videos, or audio in the current task.

MITAuto-check passedMedia & Creative

Install Media Gen

skills CLI
$ npx skills add clacky-ai/openclacky --skill media-gen -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install clacky-ai/openclacky media-gen --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/clacky-ai/openclacky.git skills-src && mkdir -p .claude/skills && cp -r skills-src/lib/clacky/default_skills/media-gen .claude/skills/media-gen && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
media-gen
GitHub stars
1.2k
Token cost
~7.5k tokens
SKILL.md length
3,112 words
Files
2 (incl. scripts)
Skills in repo
20
Repo updated
First seen
Licence
MIT

At a glance

Generate or edit images, videos, or audio in the current task.

  • Works in 3 steps: Verify a backend is configured → Generate the image → Show the image
  • The user asks to create/generate/produce
  • SKILL.md covers Endpoint, Step 1 — Verify a backend is…, Step 2 — Generate the image and Step 3 — Show the image, plus 5 more sections
  • Runs Shell scripts from its folder; calls curl and magick; reaches api.openai.com

What it does

Media Gen is an agent skill from clacky-ai/openclacky. Generate or edit images, videos, or audio in the current task. Use whenever the user asks to create/generate/produce or edit/modify a picture / image / illustration / cover / poster / icon / artwork, a video / clip / animation, or speech / voiceover / narration / TTS / ambient audio / soundscapes — e.g. generate image, draw, design a cover, edit this image, change the background, text-to-video, generate speech; 画一张, 配图, 编辑图片, 改图, 换背景, 做个视频, 配音, 文字转语音, 环境音. Also use when a document (slides, poster, README hero)…

Its SKILL.md is about 7.5k tokens, which your agent loads only when the skill is triggered. The skill folder holds 2 other files, including scripts (for example `scripts/video_seq.sh`).

It sits in Media & Creative, covering Text to speech and voice, Image generation and Image editing. The repository describes itself as: The most Token-efficient open-source AI Agent. The licence is MIT.

When your agent uses it

  • The user asks to create/generate/produce
  • Edit/modify a picture / image / illustration / cover / poster / icon / artwork
  • A video / clip / animation
  • Speech / voiceover / narration / TTS / ambient audio / soundscapes — e.g

Example prompts

  • “/media-gen”

Requirements

  • A Bash shell

Workflow steps

3 steps, taken from the step headings in SKILL.md.

  1. Verify a backend is configured
  2. Generate the image
  3. Show the image

What it can do on your machine

Read from SKILL.md and the folder at commit 7e41f3a. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Ships 1 file in scripts/ (Shell), which the agent can run.

    Shell commands in SKILL.md call:

    • curl
    • magick

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Hosts in commands or code, which the agent is likely to contact:

    • api.openai.com

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Media Gen loads about 7.5k tokens when it runs. Until then it costs about 137 tokens; SKILL.md has 3,112 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~137
When it runs · the whole SKILL.md, loaded when a task matches
~7.5k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); the scripts in this folder are not scanned.

SKILL.md

The full file from clacky-ai/openclacky at commit 7e41f3a, republished under its MIT licence (© clacky-ai). 3,112 words, ~7,490 tokens.

Download SKILL.mdSave it as .claude/skills/media-gen/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.
name
media-gen
description
Generate or edit images, videos, or audio in the current task. Use whenever the user asks to create/generate/produce or edit/modify a picture / image / illustration / cover / poster / icon / artwork, a video / clip / animation, or speech / voiceover / narration / TTS / ambient audio / soundscapes — e.g. generate image, draw, design a cover, edit this image, change the background, text-to-video, generate speech; 画一张, 配图, 编辑图片, 改图, 换背景, 做个视频, 配音, 文字转语音, 环境音. Also use when a document (slides, poster, README hero) needs an inline image.
name_zh
媒体生成
description_zh
生成或编辑图片、视频和音频,适用于封面、海报、插画、配音、环境音等。
disable-model-invocation
false
user-invocable
true
always-show
true

media-gen

Generate and edit images on demand by calling the local Clacky HTTP server, which dispatches to whichever image-generation model the user configured (type=image in their model settings). Editing (image-in → image-out) works with any image model that accepts image input — most current ones do.

Endpoint

POST http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/media/image
GET  http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/media/types

Step 1 — Verify a backend is configured

Before generating anything, confirm the user has a type=image model set up:

bash
curl -s http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/media/types

If the response shows image.configured = false, stop and tell the user:

还没有配置生图模型。请打开设置页 → 添加模型 → 类型选 image(走 openclacky 官方网关时推荐 or-gemini-3-pro-image 或 or-gpt-image-2)。配好后再让我生图。

Do NOT try to fall back to terminal + a hand-written curl https://api.openai.com/... — that bypasses the user's configured backend and won't be billed correctly.

You do NOT configure models — the user does, in the settings page. Never edit the user's config.yml to add or change a model, and never invent a model name from memory (e.g. or-gpt-5.4-image-2 does not exist). The real, current model is whatever /api/media/types reports under image.model. If you think a different model is needed, tell the user which one to set in the settings page — don't touch the config file yourself.

Step 2 — Generate the image

The model does NOT honor exact pixel sizes

There is no size / width / height field — the only shape control is aspect_ratio (landscape / square / portrait), and even that is just a rough hint (ask for 576x96 and you may get 1408x768). When the user needs an exact pixel size, a grid, an icon at NxN, or a spritesheet, generate first at whatever size the model gives, then resize / crop / tile to the exact pixels with ImageMagick (magick). Verify with magick identify before reporting done.

Important: generation speed & concurrency
  • Image generation can be slow — up to 2 minutes per image depending on the model. Before calling the API, warn the user that it may take a minute or two. The curl request blocks until the image is ready; do NOT run it in the background.
  • One at a time only. Never generate multiple images concurrently (e.g. by running several curl commands simultaneously or in a script loop). Each call consumes significant server-side resources, and parallel requests will almost certainly cause timeouts. If the user wants several images, generate them sequentially, one after another.
bash
curl -s -X POST http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/media/image \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A clean, modern hero illustration for a tech startup landing page. Soft gradient background, abstract geometric shapes in blue and purple, minimal style, 4K quality.",
    "aspect_ratio": "landscape",
    "output_dir": "'"$(pwd)"'/assets/generated",
    "session_id": "<%= session_id %>"
  }'
  • The terminal blocks multi-line commands — write the request into a .sh file and run it, don't paste a multi-line curl.
  • If a call fails with 400 / INVALID_ARGUMENT, drop the aspect_ratio field and retry once before reporting the error.
  • If a call fails with unknown image model (400), the configured model name isn't recognized by its backend — tell the user to fix the model name in the settings page; do NOT guess another name and retry.
Content-safety refusal (content_filter)

If a call fails with no image and mentions content_filter / safety / blocked (or HTTP 422), the prompt was blocked. Don't resend as-is — rephrase the prompt (soften the sensitive part, keep the intent) and retry, up to 3 times, checking each returned image. Still blocked? Stop and ask the user to adjust.

Request fields
FieldRequiredValuesNotes
promptyesstringBe detailed and concrete. See prompt tips below.
aspect_rationolandscape / square / portraitDefaults to landscape.
output_dirnoabsolute pathThe exact directory the file is written to — nothing is appended. Use the directory the user asked for; otherwise $(pwd)/assets/generated as shown in the example.
session_idyesstringCurrent Clacky session ID. Always pass the rendered value shown in the request example.
imagenofile path / base64 / data URLA single input image to edit. Triggers image-edit mode (see below).
imagesnoarray of the aboveMultiple input images for a multi-image edit. Takes precedence over image.
Input / reference image format

Images passed as image / images must be PNG, JPEG, or WebP. Other formats (SVG, GIF, BMP, TIFF, …) are rejected upstream and fail the call — convert them to one of the supported formats first.

Editing an existing image

To edit instead of generate from scratch, pass the existing image as image (a local file path is easiest — the skill reads and encodes it for you) plus a prompt describing the change. The configured image model receives the image alongside the prompt and returns an edited result.

bash
curl -s -X POST http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/media/image \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "change the background to a starry night sky, keep the cat unchanged",
    "image": "/abs/path/to/input.png",
    "session_id": "<%= session_id %>"
  }'
  • The result is a new edited image saved next to the inputs in output_dir — the original file is never modified in place.
  • For combining several inputs (e.g. "put the product from image 1 onto the background from image 2"), pass them as images: ["/path/a.png", "/path/b.png"] and describe the composition in the prompt.
  • Same speed/concurrency rules apply: editing is as slow as generation, one at a time.
Response shape (success)
json
{
  "success": true,
  "image": "/abs/path/to/working_dir/assets/generated/img_20260525_011820_a1b2c3d4.png",
  "model": "<the configured image model>",
  "provider": "openclacky",
  "prompt": "A clean, modern hero illustration ...",
  "aspect_ratio": "landscape",
  "size": "1536x1024",
  "usage": {
    "prompt_tokens": 50,
    "completion_tokens": 4500,
    "cache_read_tokens": 0,
    "cache_write_tokens": 0,
    "total_tokens": 4550
  }
}

The image field is an absolute path on disk. To embed it in markdown, slides, or HTML, convert it to a path relative to the document you're writing.

usage may be absent when the configured backend doesn't return token counts. Treat it as optional.

Response shape (failure)
json
{
  "success": false,
  "image": null,
  "error": "Upstream 401: Invalid API key",
  "error_type": "api_error",
  "model": "...",
  "provider": "..."
}

Common error_type values: not_configured, auth_required, network_error, api_error, empty_response. Tell the user the error plainly; if it's auth_required or api_error 401/403, point them at settings to fix the api_key.

Step 3 — Show the image

Read does NOT show the image to the user — it only feeds it into your own context. To make the user actually see it, write a markdown tag in your reply:

markdown
![](file:///abs/path/from/response.png)

Take the image field from the response and prefix file:// (three slashes, since the path is absolute).

If you're also embedding it in a document (README, PPT, etc.), convert the returned path to one relative to that document.

Prompt writing tips

A good image prompt has 4 layers, in this order:

  1. Subject — what is in the image, concretely. ("a golden retriever puppy", "a stylized icon of a rocket")
  2. Style / medium — photo / illustration / 3D render / watercolor / flat vector / line art
  3. Composition / lighting — close-up / wide shot / overhead / soft natural light / dramatic backlight
  4. Mood / palette — minimal / playful / corporate / pastel / high-contrast monochrome

For PPT / slide decks specifically:

  • Hero / cover slides: aspect_ratio: landscape, prompt should emphasise "clean", "minimal", "negative space" so text overlays well
  • Section dividers: aspect_ratio: landscape, abstract or pattern-style works better than literal subjects
  • Inline figures: aspect_ratio: square or portrait, more literal subject is fine

When the user gives a vague request like "给我配张图", ask one clarifying question (subject? style?) before calling the API — costs real money per image.

When NOT to use this skill

  • The user wants a diagram / chart with specific data — use a charting library (matplotlib, mermaid, etc.) instead; image gen is for illustrations, not data viz
  • The user asks for screenshots of real software — use the browser tool

Generating video (Veo)

The same /api/media/ namespace serves video generation. The user must configure a type=video model in settings (recommended: or-veo-3-1).

Endpoint
POST http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/media/video

Check GET /api/media/types first — if video.configured = false, tell the user to add a type=video model in settings before generating.

Video is slow and expensive
  • A single clip can take 1–3 minutes (sometimes longer). Warn the user before calling, and run the curl in the foreground — it blocks until the MP4 is ready. Do NOT background it.
  • One at a time. Never run multiple video generations concurrently.
  • Each clip costs real money (billed per output-second). Confirm the prompt with the user before generating.
Request
bash
curl -s -X POST http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/media/video \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A cinematic drone shot flying over a misty mountain range at sunrise, golden light, 4K.",
    "aspect_ratio": "landscape",
    "duration_seconds": 8,
    "output_dir": "'"$(pwd)"'/assets/generated",
    "session_id": "<%= session_id %>"
  }'
FieldRequiredValuesNotes
promptyesstringSame prompt-craft tips as images apply.
aspect_rationolandscape / portraitDefaults to landscape (16:9).
duration_secondsno4–8Defaults to 8.
imageno{ "b64_json": "...", "mime_type": "image/png" }Optional first frame for image-to-video.
output_dirnoabsolute pathThe exact directory the file is written to — nothing is appended. Use the directory the user asked for; otherwise $(pwd)/assets/generated as shown in the example.
session_idyesstringCurrent Clacky session ID. Always pass the rendered value shown in the request example.
Response (success)
json
{
  "success": true,
  "video": "/abs/path/to/working_dir/assets/generated/vid_20260615_011820_a1b2c3d4.mp4",
  "model": "or-veo-3-1",
  "provider": "openclacky",
  "prompt": "A cinematic drone shot ...",
  "aspect_ratio": "landscape",
  "duration_seconds": 8,
  "cost_usd": 2.688
}

The video field is an absolute path on disk. Show it to the user with a markdown link or an HTML5 <video> tag pointing at the file:// path; embed it in documents with a path relative to the document.

Response (failure)

Same shape and error_type values as image generation, but with "video": null. not_configured means no type=video model is set up.

Continuous / long video (last-frame chaining)

A single Veo call maxes out at 8 seconds, and separate calls are visually unrelated (the character, lighting and framing jump between clips). To make several clips flow as one continuous shot, chain them: take the last frame of clip N and feed it as the image (first frame) of clip N+1. Veo's image-to-video then continues from exactly where the previous clip ended, so the seam is smooth.

Use the helper script (it only does the ffmpeg mechanics — you drive the generation with the same /api/media/video curl as above). The script's absolute path is given in the Supporting Files block; assign it once:

bash
SEQ="SKILL_DIR/scripts/video_seq.sh"   # SKILL_DIR is provided in Supporting Files
# subcommands: lastframe | tob64 | payload | concat | probe

Workflow for an N-segment continuous video:

  1. Plan the shots. Split the story into 4–8s beats. Write one prompt per beat; each prompt should describe the continuation, e.g. "The same girl keeps walking forward, the camera pushes in…". Keep subject, style and lighting wording consistent across prompts.
  2. Segment 1 — normal text-to-video call. Save the returned mp4 path.
  3. Extract its last frame (as JPEG — keep the .jpg extension):
    bash
    "$SEQ" lastframe seg1.mp4 /tmp/seg1_last.jpg
  4. Segment 2 — build the request body with payload, then post it with curl --data @file. Do NOT inline the base64 into -d "{…}" — a frame's base64 is ~150KB+ and overflows the shell's argument limit ("Argument list too long"). The payload subcommand reads the frame, base64-encodes it, and writes a ready-to-send JSON file:
    bash
    "$SEQ" payload /tmp/seg2.json /tmp/seg1_last.jpg 8 landscape "$OUT_DIR" \
      "Continuing the same scene, the camera keeps pushing forward…" "<%= session_id %>"
    curl -s -X POST .../api/media/video -H "Content-Type: application/json" \
      --data @/tmp/seg2.json
    (payload <out.json> <frame> <duration_seconds> <aspect_ratio> <output_dir> <prompt> [session_id], where OUT_DIR is the same directory you'd pass as output_dir above)
  5. Repeat steps 3–4 for each subsequent segment, always chaining off the previous segment's last frame.
  6. Stitch all clips in order into one file:
    bash
    "$SEQ" concat final.mp4 seg1.mp4 seg2.mp4 seg3.mp4

Rules & caveats:

  • Strictly sequential. Generate one segment, wait for it, extract its frame, then start the next. Never run two video generations at once.
  • Keep prompts consistent. The image carries visual continuity, but the prompt must not contradict it (don't switch the subject or scene mid-chain unless you intend a cut).
  • Aspect ratio must match across all segments, or concat falls back to a slower re-encode (and may letterbox). Use the same aspect_ratio everywhere.
  • Cost adds up linearly — N segments ≈ N × single-clip price. Confirm the number of segments and total length with the user before starting.
  • For >30s or a true single-take >8s with no seam at all, this client-side chaining is the practical option today; Veo's native server-side extend (148s) is not wired into this endpoint yet.
Show full SKILL.md (1,379 more words)Show less
Seedance — multimodal video

When the configured type=video model is a ByteDance Doubao Seedance model, the same POST /api/media/video endpoint drives it. No separate endpoint — the server routes by Base URL automatically. Seedance adds richer inputs on top of the common fields (all optional, Seedance-only), split below into a common set that works on any Seedance gateway and an Ark-only set that takes effect only on the native Volcengine Ark transport (Base URL under *.volces.com). On any other OpenAI-compatible Seedance gateway, stick to the common fields.

Cost gate — ask before EVERY generation. Resolution is the main driver of Seedance's price (4k costs far more than 720p). So once you've confirmed via GET /api/media/types that the type=video Base URL is under *.volces.com, you MUST ask the user which resolution they want before EACH AND EVERY billable call — this covers not just a brand-new clip but also editing, multimodal reference, and extending/continuing an existing video (they all cost the same as a fresh render). Offer 480p / 720p / 1080p / 4k and state the default is 720p. Only after they answer (or explicitly say "use the default") do you proceed, passing their choice as resolution. Ask again every single time — a resolution the user picked for one clip is NEVER carried over to the next generation. Do not assume, do not reuse a prior answer, do not batch. One generation = one fresh resolution question. When editing or continuing/extending an existing video, default to that source video's resolution — never silently upgrade it (e.g. don't turn a 720p source into a 4k render). If the user gave no answer and you didn't ask, the server pins 720p. These Seedance-only fields have NO effect on Veo or Qwen/DashScope backends — never send them there. (And within Seedance, the Ark-only table additionally requires a *.volces.com Base URL.)

Common fields — work on any Seedance gateway (native Ark or an OpenAI-compatible host):

FieldValuesNotes
aspect_ratiolandscape/portrait/square, or a raw Ark ratio like 16:9, 9:16, 4:3, 3:4, 21:9, adaptiveRaw ratios pass through unchanged.
duration_secondsinteger, or -1-1 lets the model pick the length (Seedance 2.0 / 1.5 Pro).
first_framemedia ref (see below)First frame → image-to-video.
reference_imagesarray of media refs (0–9)Reference images.

Ark-only fields — only take effect on the native Volcengine Ark transport (video.base_url under *.volces.com). On any other OpenAI-compatible Seedance gateway, resolution / generate_audio / watermark / seed are silently ignored, and last_frame / reference_videos / reference_audios are rejected outright — so don't send any of them there:

FieldValuesNotes
resolution480p / 720p / 1080p / 4kDefaults to 720p when omitted (cost control). Ask the user before every generation — never reuse a prior answer. See the cost gate above. Model-dependent; unsupported values are rejected upstream.
generate_audiotrue / falseSeedance 2.0 / 1.5 Pro can synthesize a synced audio track.
watermarktrue / false
seedintegerReproducibility.
last_framemedia refTogether with first_frame → first+last-frame video.
reference_videosarray of media refs (0–3)Reference videos.
reference_audiosarray of media refs (0–3)Reference audio (background music / voice).

Which fields for which task — Seedance covers six capabilities; pick the fields by intent, and never mix the two families below:

TaskWhat you wantFields to send
Text-to-videoa clip from a prompt onlyprompt (no media)
Image-to-video (first frame)animate a still image forwardfirst_frame
Image-to-video (first + last frame)interpolate between two stillsfirst_frame + last_frame
Multimodal generationnew clip guided by reference images/videos/audioreference_images / reference_videos / reference_audios
Edit an existing videoreplace/add/remove/repaint something inside a given videoreference_videos: [<the video to edit>] (+ optional reference_images / reference_audios) + a prompt describing the edit
Extend / continue a videoprepend/append or stitch clips into onereference_videos: [<clip1>, <clip2>, ...] (up to 3) + a prompt describing the join

🚫 Hard rule — the two families are mutually exclusive. first_frame/last_frame cannot be combined with any reference_* field; Ark rejects the request. If the user wants to edit or extend an existing video, that is a reference_videos task — do NOT fall back to extracting a frame and using first_frame (that produces a brand-new clip and silently loses the "edit the original" intent). The server also enforces this and returns a clear invalid_argument error if you mix them.

A media ref may be:

  • a public http(s):// URL, or a data: URL, or
  • a local file path (the server reads and base64-encodes it), or
  • a { "b64_json": "...", "mime_type": "image/png" } hash.

Note: audio cannot be sent alone — pair it with at least one image or video. Prefer passing large videos/audios as public URLs; base64-encoding a big local file can exceed upstream size limits.

Example — first + last frame (image-to-video, no reference_*):

bash
curl -s -X POST http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/media/video \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "First-person POV, a hand raises a cup of fruit tea toward the camera, bright and refreshing lighting",
    "aspect_ratio": "9:16",
    "duration_seconds": 8,
    "resolution": "720p",
    "first_frame": "'"$(pwd)"'/assets/frame_first.jpg",
    "last_frame": "'"$(pwd)"'/assets/frame_last.jpg",
    "output_dir": "'"$(pwd)"'/assets/generated",
    "session_id": "<%= session_id %>"
  }'

Example — edit an existing video (replace/add/remove something inside it; uses reference_videos, NOT first_frame):

bash
curl -s -X POST http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/media/video \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Add a small wooden fishing boat with a warm lantern drifting slowly across the lake in the foreground, keep everything else unchanged",
    "resolution": "720p",
    "reference_videos": ["'"$(pwd)"'/assets/original.mp4"],
    "output_dir": "'"$(pwd)"'/assets/generated",
    "session_id": "<%= session_id %>"
  }'

Seedance is asynchronous — POST only submits, it does NOT return the video. Unlike Veo (which blocks and returns the mp4 in one call), the Seedance POST returns immediately with a task id:

json
{ "success": true, "status": "submitted", "task_id": "cgt-2024...-xxxx", "provider": "volcengine" }

status: "submitted" means the render is now running on Volcengine's servers and is already being billed — it does NOT mean it is done. You MUST now poll for completion: sleep ~15 seconds, then query the status endpoint, and repeat until it is succeeded (or failed):

bash
curl -s "http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/media/video/status?task_id=cgt-2024...-xxxx&output_dir=$(pwd)/assets/generated&session_id=<%= session_id %>"

Status responses:

json
{ "success": true,  "status": "running" }                         // keep polling
{ "success": true,  "status": "succeeded", "video": "/abs/path.mp4" }  // done — this is the file
{ "success": false, "status": "failed", "error": "..." }          // give up, report to user

Only once you receive status: "succeeded" and the absolute video path may you present the result to the user. Do NOT end your turn while the task is still submitted/running — the user is waiting for the finished video.

A minimal poll loop:

bash
TASK_ID=$(curl -s -X POST http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/media/video \
  -H "Content-Type: application/json" \
  -d '{"prompt":"...","resolution":"720p","output_dir":"'"$(pwd)"'/assets/generated","session_id":"<%= session_id %>"}' \
  | sed -n 's/.*"task_id"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')

while true; do
  sleep 15
  RESP=$(curl -s "http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/media/video/status?task_id=${TASK_ID}&output_dir=$(pwd)/assets/generated&session_id=<%= session_id %>")
  STATUS=$(echo "$RESP" | sed -n 's/.*"status"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')
  echo "poll: $STATUS"
  [ "$STATUS" = "succeeded" ] && echo "$RESP" && break
  [ "$STATUS" = "failed" ] && echo "$RESP" && break
done

Hard rules — a broken version of this once doubled a user's bill:

  • ❌ Never POST the same generation twice. Once you have a task_id, the only valid next action is polling /api/media/video/status. A slow render is not a failed one.
  • ⚠️ A timeout or error is NOT proof the task failed. The task keeps running and billing on Volcengine's side. Always query the status endpoint to find out the real state before doing anything else — never resubmit.
  • ❌ Never kill the poll to "cancel" the job. Killing your curl/session does not stop the Volcengine task; it keeps running and billing. A running task also cannot be deleted upstream.
  • ❌ Never bypass /api/media/* to call Volcengine's native API directly. All submission and status checks must go through this server (it meters cost). There is no reason to touch the raw Ark API.
  • ⏱️ If polling exceeds ~15 minutes and status is still running, stop polling and tell the user the task is still rendering in the background, give them the task_id, and let them check again later — do NOT resubmit.

Generating ambient audio

Ambient audio includes rain, ocean waves, wind, and café background sounds. Generate it programmatically, verify the audio, and provide it for playback or download.

Generating speech (Gemini TTS)

The same /api/media/ namespace serves text-to-speech. The user must configure a type=audio model in settings (recommended: or-tts-gemini-2-5-flash, the cheap+fast default).

Endpoint
POST http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/media/audio/speech

Check GET /api/media/types first — if audio.configured = false, tell the user to add a type=audio model in settings before generating.

Request
bash
curl -s -X POST http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/media/audio/speech \
  -H "Content-Type: application/json" \
  -d '{
    "input": "Hello and welcome to openclacky. Today we will explore...",
    "voice": "Kore",
    "output_dir": "'"$(pwd)"'/assets/generated",
    "session_id": "<%= session_id %>"
  }'
FieldRequiredValuesNotes
inputyesstringThe text to speak. Plain prose works best; you can prefix with style cues like "Say cheerfully:" or "In a calm tone:".
voicenostring voice nameDefaults to Kore. Common Gemini voices: Kore, Puck, Charon, Fenrir, Aoede.
output_dirnoabsolute pathThe exact directory the file is written to — nothing is appended. Use the directory the user asked for; otherwise $(pwd)/assets/generated as shown in the example.
session_idyesstringCurrent Clacky session ID. Always pass the rendered value shown in the request example.

Generation typically takes 2–10 seconds depending on length. The request blocks until the WAV is ready.

Response (success)
json
{
  "success": true,
  "audio": "/abs/path/to/working_dir/assets/generated/tts_20260615_233522_4ff02705.wav",
  "model": "or-tts-gemini-2-5-flash",
  "provider": "openclacky",
  "input": "Hello and welcome to openclacky...",
  "voice": "Kore",
  "mime_type": "audio/wav",
  "usage": { "prompt_tokens": 13, "completion_tokens": 122, "total_tokens": 135 },
  "cost_usd": 0.000259
}

The audio field is an absolute path on disk. Output is mono 16-bit PCM at 24 kHz wrapped in a standard WAV container — playable by any browser, OS player, or <audio> tag without conversion.

To let the user hear it, write a markdown link in your reply:

markdown
[🔊 听一下](file:///abs/path/from/response.wav)

For embedding in HTML documents, use:

html
<audio controls src="./xxx.wav"></audio>
Response (failure)

Same shape and error_type values as image generation, but with "audio": null. not_configured means no type=audio model is set up.

Cost & length tips
  • Gemini TTS bills by tokens (input text + generated audio). A typical one-paragraph narration costs well under $0.001.
  • For long-form audio (>1 minute), split the script into paragraphs and generate each separately, then concatenate locally — avoids upstream truncation and gives you finer control over pacing.
  • Voice consistency: Gemini TTS does not currently support voice cloning; use the same voice name across calls in one project to keep the narrator consistent.

© clacky-ai, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 1 other file (scripts) in lib/clacky/default_skills/media-gen of clacky-ai/openclacky.

  • SKILL.md
  • scripts/video_seq.sh

Open the folder on GitHubat commit 7e41f3a

Compare with similar skills

Media Gen next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Media Gen compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Media Gen this skillclacky-ai/openclacky1.2k—~7.5kAutomated safety check: PassMIT
Clean Audiohassancs91/claude-youtube-editor328—~1.8kAutomated safety check: PassMIT
Atlas Cloudcalesthio/OpenMontage66k—~1.2kAutomated safety check: PassAGPL-3.0
AI Mediaericrisco/rsc-harness190—~3.3kAutomated safety check: PassMIT
Ergo Remotion Videoitwanger/toBeBetterJavaer18k—~1.1kAutomated safety check: PassNone
Wedding Video Guided Wizardaaronyi97/wedding-video-guided-wizard310—~1kAutomated safety check: PassMIT

Similar skills

  • Clean Audio

    hassancs91/claude-youtube-editor

    Voice/audio cleanup step of the AI Video Editor pipeline — diagnose a video's background noise, pick the right denoise method, and produce a cleaned master (voice isolated, levels preserved, video…

    328 GitHub stars~1.8k tokensUpdated 1 mo ago
    Media & CreativeAuto-check passed
  • Atlas Cloud

    calesthio/OpenMontage

    Generate or edit images and videos through the Atlas Cloud gateway.

    66k GitHub stars~1.2k tokensUpdated 7 days ago
    Media & CreativeAuto-check passed
  • AI Media

    ericrisco/rsc-harness

    A skill your agent uses when a creative goal must become a finished media file: pick and order generative-media models per modality — AI voiceover, image-to-video clips, score — then glue them with…

    190 GitHub stars~3.3k tokensUpdated today
    Media & CreativeAuto-check passed
  • Ergo Remotion Video

    itwanger/toBeBetterJavaer

    把口播稿做成二哥风格的 Remotion 视频,包括整理视频用稿、火山 TTS 配音、音画对齐、逐章动画预览和导出带配音的 MP4。用户说“做视频”“口播稿转视频”“Remotion”“继续做下一章”“出片”“渲染”“改读音”“配音读错了”,或给出 docs/src/ai/video/ 下的稿子要做成视频时使用。共享工具、配置和素材在…

    18k GitHub stars~1.1k tokensUpdated yesterday
    Media & CreativeAuto-check passed
  • Wedding Video Guided Wizard

    aaronyi97/wedding-video-guided-wizard

    Guide a creator through a real couple's custom wedding video, from a shareable story intake card and Kimi writing pack through narration, external GPT image prompts, image-to-video packs, music and…

    310 GitHub stars~1k tokensUpdated 1 mo ago
    Media & CreativeAuto-check passed
  • Gc Still Image Motion Director

    LiamGvchi/gc-still-image-motion-director

    Analyze still images and design restrained, image-specific motion for image-to-video generation.

    152 GitHub stars~1.4k tokensUpdated 2 mo ago
    Media & CreativeAuto-check passed

More from clacky-ai/openclacky

All 20 skills in this repo
  • Skill Add

    clacky-ai/openclacky

    Install skills from a zip URL or local zip file path. An agent skill from clacky-ai/openclacky.

    1.2k GitHub stars~560 tokensUpdated today
    Auto-check passed
  • Browser Setup

    clacky-ai/openclacky

    Configure the browser tool for Clacky. An agent skill from clacky-ai/openclacky.

    1.2k GitHub stars~3.1k tokensUpdated today
    Auto-check: notes
  • Cron Task Creator

    clacky-ai/openclacky

    Create, manage, and run scheduled automated tasks (cron jobs) in Clacky.

    1.2k GitHub stars~2k tokensUpdated today
    Auto-check passed
  • Deploy

    clacky-ai/openclacky

    Deploy Rails applications to Railway. An agent skill from clacky-ai/openclacky.

    1.2k GitHub stars~1.9k tokensUpdated today
    Auto-check passed
  • MCP Manager

    clacky-ai/openclacky

    Manage MCP (Model Context Protocol) servers for openclacky: add, list, probe, remove, reconfigure.

    1.2k GitHub stars~3k tokensUpdated today
    Auto-check passed
  • New

    clacky-ai/openclacky

    Create a new project to start development quickly. An agent skill from clacky-ai/openclacky.

    1.2k GitHub stars~1.2k tokensUpdated today
    Auto-check passed

Questions about Media Gen

What does Media Gen do?

Generate or edit images, videos, or audio in the current task. Media Gen is an agent skill from clacky-ai/openclacky. Generate or edit images, videos, or audio in the current task.

When should I use Media Gen?

Media Gen fits situations like: the user asks to create/generate/produce; edit/modify a picture / image / illustration / cover / poster / icon / artwork; A video / clip / animation; speech / voiceover / narration / TTS / ambient audio / soundscapes — e.g.

How do I install Media Gen in Claude Code?

Run `npx skills add clacky-ai/openclacky --skill media-gen -a claude-code`. Or copy the skill folder (lib/clacky/default_skills/media-gen in clacky-ai/openclacky) into .claude/skills/media-gen in your project. Claude Code loads it when a task matches its description.

How do I install Media Gen in Codex?

Run `npx skills add clacky-ai/openclacky --skill media-gen -a codex`. Or copy the skill folder (lib/clacky/default_skills/media-gen in clacky-ai/openclacky) into .agents/skills/media-gen in your project. Codex loads it when a task matches its description.

Can I use Media Gen in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add clacky-ai/openclacky --skill media-gen -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/media-gen, .gemini/skills/media-gen, .github/skills/media-gen and .opencode/skills/media-gen in your project.

What does Media Gen need to run?

Going by SKILL.md and its folder, Media Gen needs a shell for the scripts in its folder and the command-line tools its instructions call (curl and magick). Our summary lists: A Bash shell.

Does Media Gen access the network?

SKILL.md names 1 domain. In commands or code: api.openai.com; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.

Is Media Gen safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. The check reads SKILL.md only: the scripts in the folder are not scanned, so read them before running anything.

What licence does Media Gen use?

Media Gen is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Media Gen use?

About 7.5k tokens (SKILL.md is roughly 30k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Media Gen?

Skills that share tags, products or a category with Media Gen: Clean Audio (hassancs91/claude-youtube-editor, 328 stars), Atlas Cloud (calesthio/OpenMontage, 66k stars), AI Media (ericrisco/rsc-harness, 190 stars) and Ergo Remotion Video (itwanger/toBeBetterJavaer, 18k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Media Gen?

clacky-ai (a GitHub organization) maintains it in clacky-ai/openclacky, which has 1,202 GitHub stars. The repository holds 20 skills in this directory. The repository was last updated on October 11, 2026.

Source: clacky-ai/openclacky on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.