Media.io Generate
Submit image and video jobs through the current mediaio CLI contract. Treat CLI help, model/workflow/effect discovery, and model get/workflow get output as the source of truth.
Step 0 — Bootstrap
Before any generation command:
- Run
command -v mediaio and mediaio version. If the command is missing, tell the user that the shared Media.io CLI must be installed; do not silently install a second runtime from this skill.
If mediaio version prints an Update: line ending with (update available), treat that as a required handoff point: quote that line and ask whether to run mediaio upgrade --output json before continuing.
The hint is throttled to once every 24 hours, so its absence means "no new hint today", not "confirmed current". Do not present the absence of a hint as proof that the install is up to date. mediaio upgrade is the only unthrottled check, but it also performs the upgrade, so do not run it just to probe.
Use a blocking confirmation prompt in the same turn, such as: mediaio reports an update: <Update: line>. Upgrade now?
Do not continue with discovery, generation, upload, or wait until the user answers whether to upgrade.
If the user says yes, run mediaio upgrade --output json and judge only the standard JSON envelope: schema_version, command, data, and error.
- A non-zero exit code, or a top-level
error, means the upgrade failed. Surface error.message and stop.
data.ok=true means the upgrade command completed; continue unless data.cli.scheduled=true.
data.cli.scheduled=true (Windows only) means the binary swap happens after the current process exits, so the new CLI is not active in this session yet. Tell the user to restart the session before generating.
- If
data.ok=true and any plugin result has warning, mention it briefly only if useful for diagnostics. Do not treat warnings or skipped_reason as failures.
If the user says no, continue only with the currently installed CLI version and do not suppress the hint.
- Network approval gate (hard requirement). Before launching the first networked
mediaio process in the current task, submit that Shell/Bash tool call through the host's narrowest native network-only approval mechanism, scoped to the required destination when supported. Do not first run mediaio account status, auth login, discovery, upload, generation, or wait commands in the default sandbox as a connectivity probe. Approval metadata belongs to the host tool call, not to mediaio CLI arguments.
- Wait until the approval is accepted or automatically approved before launching the process. If network-only approval is unavailable, use a general out-of-sandbox approval only after reviewing its wider scope and presenting that approval to the user. If the command may write local state (including
auth login persisting credentials), also request filesystem-write authorization; do not infer whether the target is inside the sandbox. If the host cannot request the required approval, report the host limitation and stop instead of attempting a known-to-fail sandboxed request. A global Codex permission-profile edit is not a prerequisite.
- Run
mediaio account status using the approved execution path. If authentication is genuinely missing, expired or rejected by the server, run mediaio auth login and wait for the browser flow to finish. DNS, TLS, timeout, connection and sandbox-denial errors are network failures, not authentication failures.
- On a network or permission failure, load
references/troubleshooting.md. Retry read-only commands only after a clear pre-connection sandbox/DNS failure; never automatically retry a write with an ambiguous result.
- Run
mediaio config get when an endpoint or environment mismatch is suspected.
UX Rules
- Be concise. Do not paste raw registry output or full response payloads unless the user asks for diagnostics.
- When
mediaio version surfaces an Update: line ending with (update available), ask the user whether to run mediaio upgrade --output json before any generation workflow continues. The skill should not silently proceed past an update warning. Because the hint is throttled to once a day, never phrase its absence as a verified "already up to date".
- Do not expose access tokens, credentials, prompts from unrelated tasks, or request debug payloads.
- Don't batch-ask. Pick a sane default model from
references/model-catalog.md and ask one thing at a time only if genuinely missing.
- Never invent a job type or parameter. Take the job type from the static catalog and the parameters from
model get.
- Submit first, read the returned
task_id=<id> line, then call mediaio generate wait <task_id>. The current generate create command does not accept --wait.
- Generation spends credits, but do not raise the subject on your own. Submit quietly, and surface the cost or ask for an approval only when the user is cost-sensitive. See the credit handling rules below.
- Send the user to the web app only through a link the CLI printed. Never compose, complete, or edit a media.io URL, and never name a payment step — see the product-page handoff rules below.
Credit handling
generate create charges the user's Media.io credits. --yes is required on every submission because the CLI otherwise refuses to spend credits from a non-interactive host. By default the CLI prints no cost at all; --show-credit adds the estimate and the balance.
Pick one of three modes
| Mode |
Command |
What the user sees |
| Quiet (default) |
generate create ... --yes |
The result only. No cost, no confirmation turn. |
| Report |
generate create ... --yes --show-credit |
The result plus what it cost. Still one turn. |
| Approve first |
generate estimate ... → ask → generate create ... --yes --show-credit |
The price before anything is spent. |
Start in Quiet. Escalate only on a trigger below, and never de-escalate on your own: once a conversation reaches Report or Approve first, stay there until the user says to stop.
Quiet is the default
The user asked for the job, so the request itself is the approval. Deliver the result and nothing about its price — an unrequested credit figure is noise that makes the tool feel expensive. Do not add a confirmation turn, do not run an estimate, and do not mention credits at all.
Escalate to Report
Any one of these, in this turn or earlier in the conversation:
- The user mentioned credits, cost, price, balance, or quota.
- The user asked what a job cost, after it already ran.
- The user has expressed care about spending — saving credits, avoiding waste, not running out.
Report the number the command printed together with the result. One line is enough.
Escalate to Approve first
Any one of these, which are about control rather than visibility:
- The user asked to see the price, estimate, or quote before generating.
- The user objected to an earlier charge, or asked you to check with them before spending.
- The balance is low relative to the cost, or the job is a batch that multiplies it.
Then run the full flow, which stops before spending anything:
Estimate. After the parameters are final and any source media is uploaded, run the estimate with the exact job type and parameters you are about to submit:
mediaio generate estimate <job_type> [--param value]...
The estimate spends nothing. It reports credit, known, rule_type, the billed fields, and the account balance.
Ask. Tell the user the job type, the estimated cost, their remaining balance, and that the actual charge is resolved server-side and may be lower. Then ask for approval and end your turn. Do not chain the submission into the same turn.
Wait for a real answer. Only a fresh, explicit user message approving this specific job counts. None of the following is approval:
- the host running in an auto-approve / YOLO mode
- a shell-command permission prompt the host approved on your behalf
- your own reasoning that the cost is small
If the host cannot surface an interactive question to the user, do not submit. Report that the job is ready and is waiting for the user's credit approval.
Submit after the approval. Use --yes --show-credit. Optionally add --expect-credit <N> with the number the user approved; the CLI then re-checks the cost and aborts if the parameters drifted. Use it when the cost is large or the parameters were assembled over several steps.
If generate create aborts with an --expect-credit mismatch, re-run the estimate, show the new number, and ask again. Do not "fix" a mismatch by changing the number yourself.
On a retry after a failure, treat every resubmission as a new charge and ask again.
When the balance runs short
generate estimate, a --show-credit submission, and account status already print a get credits: / get more: line with a ready-made link whenever the balance cannot cover the job. Reuse that line verbatim. If you do not have one — for example a submission was rejected for insufficient credits before any cost was printed — ask the CLI for it:
mediaio link get credits
Then say, in one short line, what the balance is and hand over the printed url unchanged, so the user can pick up or add credits and come back. Do not describe the destination in your own words, do not name a payment step, and do not offer to retry until the user says they are ready.
Never type a media.io URL from memory and never edit one you were given: the destination and its tracking parameters are owned by the binary and can change without a skill update. See the product-page handoff rules below.
Insufficient permission or credits — membership-aware fallback
Trigger: generate estimate, a --show-credit submission, or generate create is rejected because the model requires a membership tier the account does not have, or the balance cannot cover the job.
- Check the account's membership tier:
mediaio account status prints a level: line (free / standard / premium). free means the account is not a paying member.
- Build your suggestion around that tier — both branches require the user's explicit go-ahead before you act, and both mention the same two options, just in a different order and with different detail:
- Non-member (
free) — lead with the downgrade. Name the specific fallback job_type for this job from the fallback chain in references/model-catalog.md (section 4), so the user knows exactly what they'd get. Mention getting more credits second, with the get credits: link.
- Member (
standard/premium) — lead with getting more credits (the get credits: link). Mention that an alternative/cheaper model is also an option second, but do not name a specific job_type — members do not need to be steered toward the downgraded tier by name.
- Wait for an explicit yes before doing anything. If the user picks the fallback model, re-run
generate estimate for the new job_type (its cost differs) and confirm again per the normal credit rules before submitting. If the user says they'll top up credits instead, stop and wait — do not resubmit on your own once the balance changes; let them tell you they're ready.
- Never switch models or resubmit without a fresh explicit confirmation, regardless of tier.
Other credit rules
- Never use
--skip-estimate. It is for interactive human terminals only and disables the tamper check.
- Never widen spending permissions on your own initiative.
mediaio generate auto-confirm on makes every later session spend without asking; only run it when the user asks for that in their own words, and say plainly that auto-confirm off reverts it. Never run it to work around a blocked job or a confirmation required error. mediaio generate auto-confirm status shows what is in effect.
- When the user asks you to stop checking on cost, drop to Report: keep
--show-credit and keep saying what each job cost, but stop asking first.
Product-page handoff
The CLI generates; the Media.io web app is where the user browses, organises, and manages what they already have. There are exactly two links, and both come from the CLI:
| The user wants to |
Command |
| Pick up or add credits, because the balance cannot cover the job |
mediaio link get credits |
See more of their history than generate list shows, manage past tasks, manage uploaded files or generated assets, or anything else the CLI does not implement |
mediaio link get home |
mediaio link list prints both destinations as purpose, title, url columns.
Rules:
- Never write a media.io URL yourself, and never rewrite, shorten, or strip parameters from one the CLI printed. The path and its tracking parameters live in the binary precisely so they can change without touching this skill.
- Answer with the CLI first when the CLI can answer:
mediaio generate list covers "what did I run recently", mediaio upload list covers "what have I uploaded". Offer the product page for the full history, previews, and management on top of that.
- Hand over one link with one line of context. Do not paste both links at once.
Result URL guardrail (hard rule)
A signed Media.io result URL carries a high-entropy storage credential. Rewriting one character breaks it, and the storage service answers InvalidAccessKeyId or SignatureDoesNotMatch rather than pointing at the typo. Therefore:
Never retype, re-key, summarise, reformat, or hand-edit a result URL. Do not strip or add query parameters such as x-oss-process, and do not "clean up" the URL for readability.
Prefer mediaio generate download. It resolves the task and fetches the file itself, so the download never depends on you reproducing a signed URL. It echoes the source URL on a # url[N] <url> comment line for reference; copy that line verbatim if the user asks for the link.
If a raw URL is genuinely required, capture it with the shell instead of copying it. The default brief output prints each result URL flush-left on its own line, so it can be captured verbatim:
url=$(mediaio generate query <job_type> <task_id> | grep '^http' | head -1)
If a download fails with a storage credential error, do not attempt to correct the URL. Re-run mediaio generate download <task_id> (or generate query) to obtain a fresh signature.
Output modes
Do not pass --output. Every generate subcommand defaults to brief, which is the only mode you should read:
| Command |
Default brief output |
generate create |
uni_fun_code=<job_type> and task_id=<id> lines |
generate wait / generate query (success) |
task_id=, uni_fun_code=, algorithm_name=, module=, status=, status_code=, files= lines, then # ... metadata comments and one bare result URL per line |
generate wait / generate query (failure) |
status=, status_code=, reason_code=, reason_label=, reason= lines |
generate list |
one tab-separated row per task (task_id, status, uni_fun_code, algorithm_name, module, begin, end), no URLs |
generate estimate |
job type:, estimate:, free:, balance:, note: lines, plus a get credits: line when the balance is short |
link get / link list |
purpose:, title:, url: lines / one tab-separated purpose, title, url row per destination |
generate download |
one local file path per non-comment line, preceded by a # uni_fun_code <code> line and per-file # file[N] ... metadata and # url[N] <url> lines |
uni_fun_code is the only field that identifies which model produced a task. The raw algorithm field is combo_alg for every workflow task, so it is omitted from brief output unless it holds a real value (tts, agent2mv, ...). Likewise generate list --algorithm filters by algorithm channel, not by model.
Discovery guardrail — static catalog first
references/model-catalog.md is a generated snapshot of the production registry. It is the default source for model selection. Do not run mediaio model list for routine routing.
Default path (no model list)
- Read
references/model-catalog.md.
- Pick the
job_type from its section 3 routing table — match top-down and stop at the first hit. If the user gave no source image, use the text-to-image table; if they attached one, use the image-to-image table.
- Some image-to-image rows are conditioned on membership tier. When you reach one, use the
level: value already printed by the mediaio account status you ran in the startup sequence — do not run an extra command for it, and treat a missing or unrecognised level as "not a member". Pure text-to-image has a single ToMoviee tier, so membership never changes that pick.
- Run
mediaio model get <job_type> for the parameter schema. This is a required pre-submission step, not a discovery step: the catalog never promises parameters, and you must not infer them from it.
- Continue with the normal upload / estimate / submit / wait flow.
When you may fall back to model list
Only these cases. Nothing else qualifies.
| Trigger |
Action |
| The model the user named is not in catalog sections 2 or 5 |
mediaio model list --grep <keyword> --output json |
A submission returned unknown job type |
Full model list, reselect, and tell the user the catalog may be stale |
| The user explicitly asks to see all/latest models, or whether something new exists |
Full model list, grouped by type/module |
| You are about to degrade and need to confirm the fallback is still live |
mediaio model list --grep on the fallback job_type |
The catalog's generated_at is more than 30 days old, or its catalog_schema_version is not 1 |
Full model list, and report that the catalog needs re-syncing. This check is local — do not issue a request to test freshness |
references/model-catalog.md is missing or its metadata table is corrupt |
Fall back to pure runtime discovery |
These are not reasons to call model list: routine intent routing, picking the default model, "let me just double-check", uncertainty about parameters (that is model get), or a job_type that looks misspelled.
Identifier rules (hard requirements)
- Copy
job_type byte for byte. Never trim it, change its case, or "fix" a name that looks wrong. Six production job types contain a literal space, for example image2video_seedance _2.5. Quote them in the shell: mediaio model get "image2video_seedance _2.5".
- Map display name →
job_type only, never the reverse. Display names are frequently unrelated to the identifier: image2image_banana_2 is Nano Banana Pro, while Nano Banana 2 is image2image_nano_banana_2. Look the name up in catalog section 5; do not assemble an identifier from what the user said.
- Display names are not unique — 37 groups collide. When a name matches several
job_type values, list the candidates and let the user choose.
- ToMoviee is the first-party model family; its Chinese name is 天幕. No model's display name is literally 天幕, so a user asking for 天幕 must be resolved to the ToMoviee entries in catalog section 6.5. Treat 天幕 and ToMoviee as the same request.
- Echo both when you report your choice:
Display Name (job_type).
- The catalog's permission tier column is a manual annotation. Never promise the user a model is free based on it; the cost comes from
generate estimate.
Workflows and effects
Workflows and effects are separate discovery views not covered by the static catalog, but they are submitted through the same command: mediaio generate create <job_type> .... Use mediaio workflow list / mediaio effect list for them. The current CLI has no effect get; never guess effect parameters from the list summary.
mediaio model get <job_type> marks parameters as [workflow-default] when the workflow supplies a value if the flag is omitted.
Workflow — generic generation
Select. For models, read references/model-catalog.md and take the job_type from its routing table — see the discovery guardrail above. Run a list command only for a workflow/effect, or when one of the fallback triggers applies:
mediaio workflow list
mediaio effect list
mediaio model list --grep <keyword> --output json # only on a listed trigger
Inspect. Use the exact identifier, copied verbatim (quote it if it contains a space):
mediaio model get <job_type>
mediaio workflow get <workflow_name>
For an effect, stop if its required parameters have not already been verified from current BIN/service evidence; effect list alone is not a parameter schema.
Prepare local media and check file access. The current generator does not auto-upload local paths. Before reading or uploading each user-provided path:
- Confirm the job actually needs source media, then confirm the user supplied it. Job types named like
image2image_*, image2video_*, img2vid_*, *_i2i, *_i2v, or reference2video_*, and any job whose model get/workflow get output lists an image/video/reference parameter, need at least one uploaded source file — even when the live schema does not mark that parameter required. If the user has not attached or referenced a local file or an existing file_id for such a job type, stop before generate create and ask the user to provide the source image/video first. Do not submit the job and then rely on the server's error to tell you a source was missing; see references/troubleshooting.md for the failure signature.
- Resolve relative paths against the current working directory without following an untrusted path blindly, and determine whether the resolved file is inside the active workspace.
- For a path inside the workspace, continue with the normal host file-read rules.
- For a path outside the workspace, pause and request the host's native file-read authorization for the exact file (or the smallest explicit set of files). State the paths and that they will be uploaded to Media.io. Do not launch
mediaio upload create until that authorization is accepted.
- If the host cannot provide file-read authorization, stop and ask the user to grant access or move/copy the file into the workspace. Never bypass this by broadening access silently.
After the required file authorization and network approval are available, upload each local file first, save the returned file_id, then pass that ID using the exact parameter name shown by model get or workflow get:
mediaio upload create ./reference.png
Pick the credit mode. Apply the credit handling rules above: stay Quiet unless the conversation has already triggered Report (add --show-credit to the submission below) or Approve first (estimate and stop for an answer before submitting).
Submit. Pass only parameters exposed by the live schema, plus --yes:
mediaio generate create <job_type> [--param value]... --yes
Do not mention the cost when you deliver the result unless --show-credit was warranted.
Wait. Read the task_id=<id> line printed by the create command, then run:
mediaio generate wait <task_id> --timeout 20m --interval 3s
When the deliverable is a local file, let the CLI do the download in the same step and skip URL handling entirely:
mediaio generate wait <task_id> --timeout 20m --download "$(mktemp -d)"
Deliver. Retrieve every result file with the CLI, never by re-entering, re-fetching, or hand-copying a URL. Do not run curl/wget/a browser against a result URL yourself, even to "double check" it — that is exactly how a 430-510 character signed URL gets corrupted. If a fetch fails, re-run generate download/generate query for a fresh signature instead of retrying your own copy of the URL.
Create a writable temporary directory with mktemp -d.
Download the task's results into it:
mediaio generate download <task_id> --output-dir "$tmp_dir"
Every non-comment line is a local path; each file is preceded by a # file[N] ... metadata line and a # url[N] <url> line carrying the source URL. Use grep -v '^#' to keep only the paths. Omit --index so every result file is downloaded — a task can produce more than one. Use --index N only when the user explicitly wants a single specific result, and --variant preview only when they explicitly want the compressed preview instead of the full-resolution file. --variant original is the default and is what you should normally deliver.
For each downloaded path (not just the first), require a non-empty file, then inspect it with file --brief --mime-type "$download_path". Continue with the image path only for image/*. If the CLI-provided filename already carries an accurate extension, keep it; otherwise derive one from common MIME types (image/png → png, image/jpeg → jpg, image/webp → webp, image/gif → gif). Never label an unknown image as PNG.
Deliver every verified file back to the host as its own local-path Markdown image, in the same order generate download printed them, using the standard syntax . A task with N result files means N images in the reply — never stop after the first one. When a local path contains spaces, parentheses, or non-ASCII characters, wrap the target in angle brackets. Prefer the local downloaded file over the remote HTTPS URL.
Report completion only after providing the local Markdown image snippet, or after establishing that local-path Markdown cannot be used in the current host. In the latter case, explicitly say inline local preview is unavailable, and reuse the # url[N] line printed by generate download (or the shell capture shown in the result URL guardrail) rather than transcribing the URL.
Do not remove the temporary directory before the final response is sent, because the host may resolve the local Markdown path when rendering the reply.
curl is a fallback only when generate download is unavailable in the installed build. In that case still capture the URL into a shell variable and pass "$url" unmodified:
curl --fail --location --retry 2 \
--connect-timeout 15 --max-time 120 \
--output "$download_path" "$url"
For video, audio, 3D, or other non-image outputs, download the file the same way and give the user its local path; provide the result URL only when the host cannot accept a local file.
Verified image generation
For text-only GPT Image 2, current discovery exposes text2image_gpt_image_2 with --prompt, --n, --quality, --model, --size, and --output_format.
mediaio model get text2image_gpt_image_2
mediaio generate create text2image_gpt_image_2 \
--prompt "a warm, photorealistic portrait of a golden retriever at sunset" \
--quality high \
--size 1024x1024 \
--output_format png \
--yes
Do not replace this with the legacy short name gpt_image_2; it is not the current registry key. Do not append --wait to the create command. When the user is cost-sensitive, add --show-credit so the cost is printed, and price the job with mediaio generate estimate first if they want a say before spending.
For image-to-image GPT Image 2, upload each source first and use the live repeated flag --images <file_id> with image2image_gpt_image_2.
Current capability boundary
Only the command families printed by the current mediaio --help output are executable, and only the job_type values present in references/model-catalog.md (or returned by live discovery) exist. The migrated reference set also describes surfaces that are not part of the current BIN:
- workflow-specific create helpers
- one-shot create-and-wait flags
- automatic upload of local paths passed directly to generation parameters
- 3D, audio, Virality Predictor, Soul ID, product-photoshoot, game-generation, or video-explainer routes — the production registry has no
fun_module for these at all
Errors
flag provided but not defined: -wait → remove --wait, submit, then call mediaio generate wait <task_id>.
credit confirmation required: rerun with --yes ... → --yes was missing. Add it. If the user is cost-sensitive, add --show-credit too, and get their approval before resubmitting. Never satisfy this error with --skip-estimate or by turning on auto-confirm.
- a submission or estimate rejected because the balance cannot cover the job, or because the model requires a membership tier the account does not have → do not retry and do not switch to a cheaper model on your own. Follow "Insufficient permission or credits — membership-aware fallback" above and wait for the user.
credit estimate mismatch: --expect-credit X but the current parameters estimate to Y → the parameters changed after the approval. Show Y to the user and ask again; never silently resubmit with Y.
--skip-estimate is only allowed on an interactive terminal → drop the flag so the cost is printed.
--json is not supported; use --output json instead or flag provided but not defined: -json → drop --json; you should not be passing an output flag at all.
flag provided but not defined: -output or -download → the installed build predates the brief-output contract. Fall back to reading the raw data: line, and still capture any URL with a shell variable instead of transcribing it.
unknown job type → most often the identifier was altered. Re-read it from references/model-catalog.md and copy it byte for byte; check section 6.1 in case it contains a space. Only if it is genuinely absent from the catalog, rerun the relevant live list and use its exact first-column identifier, and tell the user the catalog looks stale.
missing required flag(s) or invalid value → inspect the live schema and pass only exposed values.
InvalidAccessKeyId, SignatureDoesNotMatch, or an HTTP 403 from the storage host while downloading → the URL was altered or has expired. Do not try to repair it. Re-run mediaio generate download <task_id>.
is not downloadable yet: status=... → the task has not reached a successful terminal state; run generate wait first and read reason_code/reason_label.
already exists; pass --overwrite to replace it → choose a fresh --output-dir (for example a new mktemp -d) or pass --overwrite deliberately.
- task is accepted but
generate wait ends in a generic terminal failure → before retrying, check whether the job type needs a source image/video (name contains image2image/image2video/img2vid/reference2video, or model get/workflow get lists an image/video parameter). If no source file was uploaded and passed for such a job, ask the user for one and resubmit; do not blindly retry the identical command. See references/troubleshooting.md for the specific error signature.
- endpoint
404 during create → verify the BIN build routes creation through the configured combo_alg endpoint; do not switch models because this is not a prompt/model-selection error.
- missing credentials, an HTTP 401, or an explicit token-refresh rejection → run
mediaio auth login.
Reference docs
Load references on demand:
references/model-catalog.md before every model selection — generated from the production registry; carries the defaults, routing rules, fallback chain, the full model index, and the known identifier traps
references/prompt-engineering.md for prompt-writing guidance
references/media-inputs.md when the user provides local or uploaded media
references/workflows.md for a job type returned by live workflow discovery
references/troubleshooting.md after a current command fails
1---2name: mediaio-generate3description: Generate images and videos through the currently installed Media.io CLI. Use for text-to-image, image-to-image, text-to-video, image-to-video, reference-to-video and published workflows. Select the model from the bundled static catalog (`references/model-catalog.md`), which is generated from the production registry; only fall back to `mediaio model list` on the triggers listed in the discovery guardrail. Copy every `job_type` byte for byte — some contain a literal space, and display names often do not match the identifier. Effects may be used only when their parameters have been independently verified because the current CLI exposes `effect list` but not `effect get`. Always confirm the parameter schema with `model get` before submission. Submitting spends the user's credits, but the CLI stays quiet about the amount unless asked; surface the cost with `--show-credit`, and get an explicit approval first, only when the user is cost-sensitive or has raised credits, price or balance. When the balance runs short, 4---56# Media.io Generate78Submit image and video jobs through the current `mediaio` CLI contract. Treat CLI help, model/workflow/effect discovery, and `model get`/`workflow get` output as the source of truth.910## Step 0 — Bootstrap1112Before any generation command:13141. Run `command -v mediaio` and `mediaio version`. If the command is missing, tell the user that the shared Media.io CLI must be installed; do not silently install a second runtime from this skill.15 - If `mediaio version` prints an `Update:` line ending with `(update available)`, treat that as a required handoff point: quote that line and ask whether to run `mediaio upgrade --output json` before continuing.16 - The hint is throttled to once every 24 hours, so its absence means "no new hint today", not "confirmed current". Do not present the absence of a hint as proof that the install is up to date. `mediaio upgrade` is the only unthrottled check, but it also performs the upgrade, so do not run it just to probe.17 - Use a blocking confirmation prompt in the same turn, such as: `mediaio reports an update: <Update: line>. Upgrade now?`1819 - Do not continue with discovery, generation, upload, or wait until the user answers whether to upgrade.20 - If the user says yes, run `mediaio upgrade --output json` and judge only the standard JSON envelope: `schema_version`, `command`, `data`, and `error`.21 - A non-zero exit code, or a top-level `error`, means the upgrade failed. Surface `error.message` and stop.22 - `data.ok=true` means the upgrade command completed; continue unless `data.cli.scheduled=true`.23 - `data.cli.scheduled=true` (Windows only) means the binary swap happens after the current process exits, so the new CLI is not active in this session yet. Tell the user to restart the session before generating.24 - If `data.ok=true` and any plugin result has `warning`, mention it briefly only if useful for diagnostics. Do not treat warnings or `skipped_reason` as failures.25 - If the user says no, continue only with the currently installed CLI version and do not suppress the hint.262. **Network approval gate (hard requirement).** Before launching the first networked `mediaio` process in the current task, submit that Shell/Bash tool call through the host's narrowest native network-only approval mechanism, scoped to the required destination when supported. Do not first run `mediaio account status`, `auth login`, discovery, upload, generation, or wait commands in the default sandbox as a connectivity probe. Approval metadata belongs to the host tool call, not to `mediaio` CLI arguments.273. Wait until the approval is accepted or automatically approved before launching the process. If network-only approval is unavailable, use a general out-of-sandbox approval only after reviewing its wider scope and presenting that approval to the user. If the command may write local state (including `auth login` persisting credentials), also request filesystem-write authorization; do not infer whether the target is inside the sandbox. If the host cannot request the required approval, report the host limitation and stop instead of attempting a known-to-fail sandboxed request. A global Codex permission-profile edit is not a prerequisite.284. Run `mediaio account status` using the approved execution path. If authentication is genuinely missing, expired or rejected by the server, run `mediaio auth login` and wait for the browser flow to finish. DNS, TLS, timeout, connection and sandbox-denial errors are network failures, not authentication failures.295. On a network or permission failure, load `references/troubleshooting.md`. Retry read-only commands only after a clear pre-connection sandbox/DNS failure; never automatically retry a write with an ambiguous result.306. Run `mediaio config get` when an endpoint or environment mismatch is suspected.3132## UX Rules33341. Be concise. Do not paste raw registry output or full response payloads unless the user asks for diagnostics.352. When `mediaio version` surfaces an `Update:` line ending with `(update available)`, ask the user whether to run `mediaio upgrade --output json` before any generation workflow continues. The skill should not silently proceed past an update warning. Because the hint is throttled to once a day, never phrase its absence as a verified "already up to date".363. Do not expose access tokens, credentials, prompts from unrelated tasks, or request debug payloads.374. Don't batch-ask. Pick a sane default model from `references/model-catalog.md` and ask one thing at a time only if genuinely missing.385. Never invent a job type or parameter. Take the job type from the static catalog and the parameters from `model get`.396. Submit first, read the returned `task_id=<id>` line, then call `mediaio generate wait <task_id>`. The current `generate create` command does not accept `--wait`.407. Generation spends credits, but do not raise the subject on your own. Submit quietly, and surface the cost or ask for an approval only when the user is cost-sensitive. See the credit handling rules below.418. Send the user to the web app only through a link the CLI printed. Never compose, complete, or edit a media.io URL, and never name a payment step — see the product-page handoff rules below.4243## Credit handling4445`generate create` charges the user's Media.io credits. `--yes` is required on every submission because the CLI otherwise refuses to spend credits from a non-interactive host. By default the CLI prints no cost at all; `--show-credit` adds the estimate and the balance.4647### Pick one of three modes4849| Mode | Command | What the user sees |50| --- | --- | --- |51| **Quiet** (default) | `generate create ... --yes` | The result only. No cost, no confirmation turn. |52| **Report** | `generate create ... --yes --show-credit` | The result plus what it cost. Still one turn. |53| **Approve first** | `generate estimate ...` → ask → `generate create ... --yes --show-credit` | The price before anything is spent. |5455Start in **Quiet**. Escalate only on a trigger below, and never de-escalate on your own: once a conversation reaches Report or Approve first, stay there until the user says to stop.5657### Quiet is the default5859The user asked for the job, so the request itself is the approval. Deliver the result and nothing about its price — an unrequested credit figure is noise that makes the tool feel expensive. Do not add a confirmation turn, do not run an estimate, and do not mention credits at all.6061### Escalate to Report6263Any one of these, in this turn or earlier in the conversation:6465- The user mentioned credits, cost, price, balance, or quota.66- The user asked what a job cost, after it already ran.67- The user has expressed care about spending — saving credits, avoiding waste, not running out.6869Report the number the command printed together with the result. One line is enough.7071### Escalate to Approve first7273Any one of these, which are about control rather than visibility:7475- The user asked to see the price, estimate, or quote **before** generating.76- The user objected to an earlier charge, or asked you to check with them before spending.77- The balance is low relative to the cost, or the job is a batch that multiplies it.7879Then run the full flow, which stops before spending anything:80811. **Estimate.** After the parameters are final and any source media is uploaded, run the estimate with the exact job type and parameters you are about to submit:8283 ```bash84 mediaio generate estimate <job_type> [--param value]...85 ```8687 The estimate spends nothing. It reports `credit`, `known`, `rule_type`, the billed `fields`, and the account `balance`.88892. **Ask.** Tell the user the job type, the estimated cost, their remaining balance, and that the actual charge is resolved server-side and may be lower. Then ask for approval and **end your turn**. Do not chain the submission into the same turn.90913. **Wait for a real answer.** Only a fresh, explicit user message approving this specific job counts. None of the following is approval:9293 - the host running in an auto-approve / YOLO mode94 - a shell-command permission prompt the host approved on your behalf95 - your own reasoning that the cost is small9697 If the host cannot surface an interactive question to the user, do not submit. Report that the job is ready and is waiting for the user's credit approval.98994. **Submit after the approval.** Use `--yes --show-credit`. Optionally add `--expect-credit <N>` with the number the user approved; the CLI then re-checks the cost and aborts if the parameters drifted. Use it when the cost is large or the parameters were assembled over several steps.1001015. If `generate create` aborts with an `--expect-credit` mismatch, re-run the estimate, show the new number, and ask again. Do not "fix" a mismatch by changing the number yourself.1021036. On a retry after a failure, treat every resubmission as a new charge and ask again.104105### When the balance runs short106107`generate estimate`, a `--show-credit` submission, and `account status` already print a `get credits:` / `get more:` line with a ready-made link whenever the balance cannot cover the job. **Reuse that line verbatim.** If you do not have one — for example a submission was rejected for insufficient credits before any cost was printed — ask the CLI for it:108109```bash110mediaio link get credits111```112113Then say, in one short line, what the balance is and hand over the printed `url` unchanged, so the user can pick up or add credits and come back. Do not describe the destination in your own words, do not name a payment step, and do not offer to retry until the user says they are ready.114115Never type a media.io URL from memory and never edit one you were given: the destination and its tracking parameters are owned by the binary and can change without a skill update. See the product-page handoff rules below.116117### Insufficient permission or credits — membership-aware fallback118119Trigger: `generate estimate`, a `--show-credit` submission, or `generate create` is rejected because the model requires a membership tier the account does not have, or the balance cannot cover the job.1201211. Check the account's membership tier: `mediaio account status` prints a `level:` line (`free` / `standard` / `premium`). `free` means the account is not a paying member.1222. Build your suggestion around that tier — both branches require the user's explicit go-ahead before you act, and both mention the same two options, just in a different order and with different detail:123 - **Non-member (`free`)** — lead with the downgrade. Name the specific fallback `job_type` for this job from the fallback chain in [references/model-catalog.md](references/model-catalog.md) (section 4), so the user knows exactly what they'd get. Mention getting more credits second, with the `get credits:` link.124 - **Member (`standard`/`premium`)** — lead with getting more credits (the `get credits:` link). Mention that an alternative/cheaper model is also an option second, but do not name a specific `job_type` — members do not need to be steered toward the downgraded tier by name.1253. Wait for an explicit yes before doing anything. If the user picks the fallback model, re-run `generate estimate` for the new `job_type` (its cost differs) and confirm again per the normal credit rules before submitting. If the user says they'll top up credits instead, stop and wait — do not resubmit on your own once the balance changes; let them tell you they're ready.1264. Never switch models or resubmit without a fresh explicit confirmation, regardless of tier.127128### Other credit rules129130- **Never use `--skip-estimate`.** It is for interactive human terminals only and disables the tamper check.131- Never widen spending permissions on your own initiative. `mediaio generate auto-confirm on` makes every later session spend without asking; only run it when the user asks for that in their own words, and say plainly that `auto-confirm off` reverts it. Never run it to work around a blocked job or a `confirmation required` error. `mediaio generate auto-confirm status` shows what is in effect.132- When the user asks you to stop checking on cost, drop to Report: keep `--show-credit` and keep saying what each job cost, but stop asking first.133134## Product-page handoff135136The CLI generates; the Media.io web app is where the user browses, organises, and manages what they already have. There are exactly two links, and both come from the CLI:137138| The user wants to | Command |139| --- | --- |140| Pick up or add credits, because the balance cannot cover the job | `mediaio link get credits` |141| See more of their history than `generate list` shows, manage past tasks, manage uploaded files or generated assets, or anything else the CLI does not implement | `mediaio link get home` |142143`mediaio link list` prints both destinations as `purpose`, `title`, `url` columns.144145Rules:1461471. **Never write a media.io URL yourself**, and never rewrite, shorten, or strip parameters from one the CLI printed. The path and its tracking parameters live in the binary precisely so they can change without touching this skill.1482. Answer with the CLI first when the CLI can answer: `mediaio generate list` covers "what did I run recently", `mediaio upload list` covers "what have I uploaded". Offer the product page for the full history, previews, and management on top of that.1493. Hand over one link with one line of context. Do not paste both links at once.150151## Result URL guardrail (hard rule)152153A signed Media.io result URL carries a high-entropy storage credential. Rewriting one character breaks it, and the storage service answers `InvalidAccessKeyId` or `SignatureDoesNotMatch` rather than pointing at the typo. Therefore:1541551. **Never retype, re-key, summarise, reformat, or hand-edit a result URL.** Do not strip or add query parameters such as `x-oss-process`, and do not "clean up" the URL for readability.1562. **Prefer `mediaio generate download`.** It resolves the task and fetches the file itself, so the download never depends on you reproducing a signed URL. It echoes the source URL on a `# url[N] <url>` comment line for reference; copy that line verbatim if the user asks for the link.1573. If a raw URL is genuinely required, capture it with the shell instead of copying it. The default brief output prints each result URL flush-left on its own line, so it can be captured verbatim:158159 ```bash160 url=$(mediaio generate query <job_type> <task_id> | grep '^http' | head -1)161 ```1621634. If a download fails with a storage credential error, do not attempt to correct the URL. Re-run `mediaio generate download <task_id>` (or `generate query`) to obtain a fresh signature.164165## Output modes166167**Do not pass `--output`.** Every `generate` subcommand defaults to `brief`, which is the only mode you should read:168169| Command | Default brief output |170| --- | --- |171| `generate create` | `uni_fun_code=<job_type>` and `task_id=<id>` lines |172| `generate wait` / `generate query` (success) | `task_id=`, `uni_fun_code=`, `algorithm_name=`, `module=`, `status=`, `status_code=`, `files=` lines, then `# ...` metadata comments and one bare result URL per line |173| `generate wait` / `generate query` (failure) | `status=`, `status_code=`, `reason_code=`, `reason_label=`, `reason=` lines |174| `generate list` | one tab-separated row per task (`task_id`, `status`, `uni_fun_code`, `algorithm_name`, `module`, `begin`, `end`), no URLs |175| `generate estimate` | `job type:`, `estimate:`, `free:`, `balance:`, `note:` lines, plus a `get credits:` line when the balance is short |176| `link get` / `link list` | `purpose:`, `title:`, `url:` lines / one tab-separated `purpose`, `title`, `url` row per destination |177| `generate download` | one local file path per non-comment line, preceded by a `# uni_fun_code <code>` line and per-file `# file[N] ...` metadata and `# url[N] <url>` lines |178179`uni_fun_code` is the only field that identifies which model produced a task. The raw `algorithm` field is `combo_alg` for every workflow task, so it is omitted from brief output unless it holds a real value (`tts`, `agent2mv`, ...). Likewise `generate list --algorithm` filters by algorithm channel, not by model.180181## Discovery guardrail — static catalog first182183`references/model-catalog.md` is a generated snapshot of the production registry. **It is the default source for model selection. Do not run `mediaio model list` for routine routing.**184185### Default path (no `model list`)1861871. Read `references/model-catalog.md`.1882. Pick the `job_type` from its section 3 routing table — match top-down and **stop at the first hit**. If the user gave no source image, use the text-to-image table; if they attached one, use the image-to-image table.1893. Some image-to-image rows are conditioned on membership tier. When you reach one, use the `level:` value already printed by the `mediaio account status` you ran in the startup sequence — do not run an extra command for it, and treat a missing or unrecognised `level` as "not a member". Pure text-to-image has a single ToMoviee tier, so membership never changes that pick.1904. Run `mediaio model get <job_type>` for the parameter schema. This is a required pre-submission step, not a discovery step: the catalog never promises parameters, and you must not infer them from it.1915. Continue with the normal upload / estimate / submit / wait flow.192193### When you may fall back to `model list`194195Only these cases. Nothing else qualifies.196197| Trigger | Action |198| --- | --- |199| The model the user named is not in catalog sections 2 or 5 | `mediaio model list --grep <keyword> --output json` |200| A submission returned `unknown job type` | Full `model list`, reselect, and tell the user the catalog may be stale |201| The user explicitly asks to see all/latest models, or whether something new exists | Full `model list`, grouped by type/module |202| You are about to degrade and need to confirm the fallback is still live | `mediaio model list --grep` on the fallback `job_type` |203| The catalog's `generated_at` is more than 30 days old, or its `catalog_schema_version` is not 1 | Full `model list`, and report that the catalog needs re-syncing. **This check is local — do not issue a request to test freshness** |204| `references/model-catalog.md` is missing or its metadata table is corrupt | Fall back to pure runtime discovery |205206These are **not** reasons to call `model list`: routine intent routing, picking the default model, "let me just double-check", uncertainty about parameters (that is `model get`), or a `job_type` that looks misspelled.207208### Identifier rules (hard requirements)2092101. **Copy `job_type` byte for byte.** Never trim it, change its case, or "fix" a name that looks wrong. Six production job types contain a literal space, for example `image2video_seedance _2.5`. Quote them in the shell: `mediaio model get "image2video_seedance _2.5"`.2112. **Map display name → `job_type` only, never the reverse.** Display names are frequently unrelated to the identifier: `image2image_banana_2` is *Nano Banana Pro*, while *Nano Banana 2* is `image2image_nano_banana_2`. Look the name up in catalog section 5; do not assemble an identifier from what the user said.2123. **Display names are not unique** — 37 groups collide. When a name matches several `job_type` values, list the candidates and let the user choose.2134. **ToMoviee is the first-party model family; its Chinese name is 天幕.** No model's display name is literally 天幕, so a user asking for 天幕 must be resolved to the ToMoviee entries in catalog section 6.5. Treat 天幕 and ToMoviee as the same request.2145. **Echo both when you report your choice**: `Display Name (job_type)`.2156. The catalog's permission tier column is a manual annotation. Never promise the user a model is free based on it; the cost comes from `generate estimate`.216217### Workflows and effects218219Workflows and effects are separate discovery views not covered by the static catalog, but they are submitted through the same command: `mediaio generate create <job_type> ...`. Use `mediaio workflow list` / `mediaio effect list` for them. The current CLI has no `effect get`; never guess effect parameters from the list summary.220221`mediaio model get <job_type>` marks parameters as `[workflow-default]` when the workflow supplies a value if the flag is omitted.222223## Workflow — generic generation2242251. **Select.** For models, read `references/model-catalog.md` and take the `job_type` from its routing table — see the discovery guardrail above. Run a list command only for a workflow/effect, or when one of the fallback triggers applies:226227 ```bash228 mediaio workflow list229 mediaio effect list230 mediaio model list --grep <keyword> --output json # only on a listed trigger231 ```2322332. **Inspect.** Use the exact identifier, copied verbatim (quote it if it contains a space):234235 ```bash236 mediaio model get <job_type>237 mediaio workflow get <workflow_name>238 ```239240 For an effect, stop if its required parameters have not already been verified from current BIN/service evidence; `effect list` alone is not a parameter schema.2412423. **Prepare local media and check file access.** The current generator does not auto-upload local paths. Before reading or uploading each user-provided path:243244 - **Confirm the job actually needs source media, then confirm the user supplied it.** Job types named like `image2image_*`, `image2video_*`, `img2vid_*`, `*_i2i`, `*_i2v`, or `reference2video_*`, and any job whose `model get`/`workflow get` output lists an image/video/reference parameter, need at least one uploaded source file — even when the live schema does not mark that parameter `required`. If the user has not attached or referenced a local file or an existing `file_id` for such a job type, stop before `generate create` and ask the user to provide the source image/video first. Do not submit the job and then rely on the server's error to tell you a source was missing; see `references/troubleshooting.md` for the failure signature.245 - Resolve relative paths against the current working directory without following an untrusted path blindly, and determine whether the resolved file is inside the active workspace.246 - For a path inside the workspace, continue with the normal host file-read rules.247 - For a path outside the workspace, pause and request the host's native file-read authorization for the exact file (or the smallest explicit set of files). State the paths and that they will be uploaded to Media.io. Do not launch `mediaio upload create` until that authorization is accepted.248 - If the host cannot provide file-read authorization, stop and ask the user to grant access or move/copy the file into the workspace. Never bypass this by broadening access silently.249250 After the required file authorization and network approval are available, upload each local file first, save the returned `file_id`, then pass that ID using the exact parameter name shown by `model get` or `workflow get`:251252 ```bash253 mediaio upload create ./reference.png254 ```2552564. **Pick the credit mode.** Apply the credit handling rules above: stay Quiet unless the conversation has already triggered Report (add `--show-credit` to the submission below) or Approve first (estimate and stop for an answer before submitting).2572585. **Submit.** Pass only parameters exposed by the live schema, plus `--yes`:259260 ```bash261 mediaio generate create <job_type> [--param value]... --yes262 ```263264 Do not mention the cost when you deliver the result unless `--show-credit` was warranted.2652666. **Wait.** Read the `task_id=<id>` line printed by the create command, then run:267268 ```bash269 mediaio generate wait <task_id> --timeout 20m --interval 3s270 ```271272 When the deliverable is a local file, let the CLI do the download in the same step and skip URL handling entirely:273274 ```bash275 mediaio generate wait <task_id> --timeout 20m --download "$(mktemp -d)"276 ```2772787. **Deliver.** Retrieve every result file with the CLI, never by re-entering, re-fetching, or hand-copying a URL. Do not run `curl`/`wget`/a browser against a result URL yourself, even to "double check" it — that is exactly how a 430-510 character signed URL gets corrupted. If a fetch fails, re-run `generate download`/`generate query` for a fresh signature instead of retrying your own copy of the URL.279280 1. Create a writable temporary directory with `mktemp -d`.281 2. Download the task's results into it:282283 ```bash284 mediaio generate download <task_id> --output-dir "$tmp_dir"285 ```286287 Every non-comment line is a local path; each file is preceded by a `# file[N] ...` metadata line and a `# url[N] <url>` line carrying the source URL. Use `grep -v '^#'` to keep only the paths. Omit `--index` so every result file is downloaded — a task can produce more than one. Use `--index N` only when the user explicitly wants a single specific result, and `--variant preview` only when they explicitly want the compressed preview instead of the full-resolution file. `--variant original` is the default and is what you should normally deliver.288 3. For **each** downloaded path (not just the first), require a non-empty file, then inspect it with `file --brief --mime-type "$download_path"`. Continue with the image path only for `image/*`. If the CLI-provided filename already carries an accurate extension, keep it; otherwise derive one from common MIME types (`image/png` → `png`, `image/jpeg` → `jpg`, `image/webp` → `webp`, `image/gif` → `gif`). Never label an unknown image as PNG.289 4. Deliver **every** verified file back to the host as its own local-path Markdown image, in the same order `generate download` printed them, using the standard syntax ``. A task with N result files means N images in the reply — never stop after the first one. When a local path contains spaces, parentheses, or non-ASCII characters, wrap the target in angle brackets. Prefer the local downloaded file over the remote HTTPS URL.290 5. Report completion only after providing the local Markdown image snippet, or after establishing that local-path Markdown cannot be used in the current host. In the latter case, explicitly say inline local preview is unavailable, and reuse the `# url[N]` line printed by `generate download` (or the shell capture shown in the result URL guardrail) rather than transcribing the URL.291 6. Do not remove the temporary directory before the final response is sent, because the host may resolve the local Markdown path when rendering the reply.292 7. `curl` is a fallback only when `generate download` is unavailable in the installed build. In that case still capture the URL into a shell variable and pass `"$url"` unmodified:293294 ```bash295 curl --fail --location --retry 2 \296 --connect-timeout 15 --max-time 120 \297 --output "$download_path" "$url"298 ```299300 For video, audio, 3D, or other non-image outputs, download the file the same way and give the user its local path; provide the result URL only when the host cannot accept a local file.301302303## Verified image generation304305For text-only GPT Image 2, current discovery exposes `text2image_gpt_image_2` with `--prompt`, `--n`, `--quality`, `--model`, `--size`, and `--output_format`.306307```bash308mediaio model get text2image_gpt_image_2309mediaio generate create text2image_gpt_image_2 \310 --prompt "a warm, photorealistic portrait of a golden retriever at sunset" \311 --quality high \312 --size 1024x1024 \313 --output_format png \314 --yes315```316317Do not replace this with the legacy short name `gpt_image_2`; it is not the current registry key. Do not append `--wait` to the create command. When the user is cost-sensitive, add `--show-credit` so the cost is printed, and price the job with `mediaio generate estimate` first if they want a say before spending.318319For image-to-image GPT Image 2, upload each source first and use the live repeated flag `--images <file_id>` with `image2image_gpt_image_2`.320321## Current capability boundary322323Only the command families printed by the current `mediaio --help` output are executable, and only the `job_type` values present in `references/model-catalog.md` (or returned by live discovery) exist. The migrated reference set also describes surfaces that are not part of the current BIN:324325- workflow-specific create helpers326- one-shot create-and-wait flags327- automatic upload of local paths passed directly to generation parameters328- 3D, audio, Virality Predictor, Soul ID, product-photoshoot, game-generation, or video-explainer routes — the production registry has no `fun_module` for these at all329330## Errors331332- `flag provided but not defined: -wait` → remove `--wait`, submit, then call `mediaio generate wait <task_id>`.333- `credit confirmation required: rerun with --yes ...` → `--yes` was missing. Add it. If the user is cost-sensitive, add `--show-credit` too, and get their approval before resubmitting. Never satisfy this error with `--skip-estimate` or by turning on auto-confirm.334- a submission or estimate rejected because the balance cannot cover the job, or because the model requires a membership tier the account does not have → do not retry and do not switch to a cheaper model on your own. Follow "Insufficient permission or credits — membership-aware fallback" above and wait for the user.335- `credit estimate mismatch: --expect-credit X but the current parameters estimate to Y` → the parameters changed after the approval. Show Y to the user and ask again; never silently resubmit with Y.336- `--skip-estimate is only allowed on an interactive terminal` → drop the flag so the cost is printed.337- `--json is not supported; use --output json instead` or `flag provided but not defined: -json` → drop `--json`; you should not be passing an output flag at all.338- `flag provided but not defined: -output` or `-download` → the installed build predates the brief-output contract. Fall back to reading the raw `data:` line, and still capture any URL with a shell variable instead of transcribing it.339- `unknown job type` → most often the identifier was altered. Re-read it from `references/model-catalog.md` and copy it byte for byte; check section 6.1 in case it contains a space. Only if it is genuinely absent from the catalog, rerun the relevant live list and use its exact first-column identifier, and tell the user the catalog looks stale.340- `missing required flag(s)` or `invalid value` → inspect the live schema and pass only exposed values.341- `InvalidAccessKeyId`, `SignatureDoesNotMatch`, or an HTTP 403 from the storage host while downloading → the URL was altered or has expired. Do not try to repair it. Re-run `mediaio generate download <task_id>`.342- `is not downloadable yet: status=...` → the task has not reached a successful terminal state; run `generate wait` first and read `reason_code`/`reason_label`.343- `already exists; pass --overwrite to replace it` → choose a fresh `--output-dir` (for example a new `mktemp -d`) or pass `--overwrite` deliberately.344- task is accepted but `generate wait` ends in a generic terminal failure → before retrying, check whether the job type needs a source image/video (name contains `image2image`/`image2video`/`img2vid`/`reference2video`, or `model get`/`workflow get` lists an image/video parameter). If no source file was uploaded and passed for such a job, ask the user for one and resubmit; do not blindly retry the identical command. See `references/troubleshooting.md` for the specific error signature.345- endpoint `404` during create → verify the BIN build routes creation through the configured combo_alg endpoint; do not switch models because this is not a prompt/model-selection error.346- missing credentials, an HTTP 401, or an explicit token-refresh rejection → run `mediaio auth login`.347348## Reference docs349350Load references on demand:351352- `references/model-catalog.md` **before every model selection** — generated from the production registry; carries the defaults, routing rules, fallback chain, the full model index, and the known identifier traps353- `references/prompt-engineering.md` for prompt-writing guidance354- `references/media-inputs.md` when the user provides local or uploaded media355- `references/workflows.md` for a job type returned by live workflow discovery356- `references/troubleshooting.md` after a current command fails