{
  "markdown": "# mediagen — an image and video generation skill for coding agents\n\n[![npm](https://img.shields.io/npm/v/mediagen)](https://www.npmjs.com/package/mediagen)\n[![CI](https://github.com/Cripacx/mediagen/actions/workflows/ci.yml/badge.svg)](https://github.com/Cripacx/mediagen/actions/workflows/ci.yml)\n[![node](https://img.shields.io/node/v/mediagen)](https://nodejs.org)\n\nGive your agent image and video generation across **Google Gemini**, **OpenAI**\nand **Kie AI** — one skill, one install, no API to learn.\n\nSay roughly what you want and let it decide the rest:\n\n```\nYou:   Make a hero image for the landing page, wide, something moody and industrial.\n\nAgent: npx -y mediagen image \"A disused loading dock at dusk, wet concrete…\"\n         --aspect-ratio 21:9 --json\n       → ./output/image-20260823T094107Z.png\n```\n\nIt wrote the prompt out in full, knew 21:9 rules OpenAI out, and read the path\nback from `--json`.\n\nOr be exact, and it stops deciding:\n\n```\nYou:   Same thing with gemini-3-pro-image, 21:9, 4K, marked as AI-generated,\n       saved as hero.png.\n\nAgent: npx -y mediagen image \"A disused loading dock at dusk, wet concrete…\"\n         --model gemini-3-pro-image --aspect-ratio 21:9 --size 4K\n         --output-name hero.png --json\n       → ./output/hero.jpg\n\n       [looks at the image]\n\n       npx -y mediagen mark ./output/hero.jpg --visible-label\n         --label-position top-right --json\n       → ./output/hero.labelled.jpg\n```\n\nIt marked in a second pass, after seeing where the subject ended up — and put\nthe label on the flat roofline rather than over the loading bay.\n\nAnything the CLI takes can be asked for in words — provider, model, aspect\nratio, size, output name and directory, quality preset, video duration, an\ninput image to edit, and whether to mark the result. Name any of them and the\nagent uses it as given; leave it out and it chooses, or falls back to what you\nconfigured.\n\n## Install\n\n```bash\nnpx -y skills add Cripacx/mediagen --skill mediagen\n```\n\nThat is the whole installation. **Nothing else to set up** — the skill runs the\nCLI through `npx`, which fetches it on first use and caches it afterwards.\n\nThen give it a key:\n\n```bash\nnpx -y mediagen init\n```\n\nAn interactive wizard: pick providers, enter each key without it being echoed,\nverify each against the live API, choose a model per provider, and set a\ndefault. One key is enough to start.\n\nNow just ask your agent for an image.\n\n## What your agent can do with it\n\n- **Generate images and video** from a description, or edit media you already\n  have\n- **Choose the right provider** for the task — the skill knows Gemini handles\n  21:9 and video, that OpenAI cannot do 16:9 at all, and that Kie aggregates\n  around thirty third-party models\n- **Take your instructions literally when you give them.** Name a model, a\n  ratio, a size or a filename and it is used as stated. `mediagen models` is\n  there when you want to see what is available before choosing\n- **Write the prompt properly.** The skill carries prompt-writing guidance, so\n  \"a hero image, moody and industrial\" becomes a full description of subject,\n  composition, light, camera and materials before anything is sent\n- **Mark AI-generated output** when it matters — the skill suggests it for\n  anything photorealistic or destined for publication\n- **Recover from failures on its own**, because every error carries a\n  machine-readable code and a next action\n\nAnd what it will not do: **ask you to paste an API key into the chat.** On a\nconfiguration error the skill tells you to run `mediagen init` in your own\nterminal.\n\n## Prerequisites\n\n- At least one API key:\n  - Google Gemini ([get one here](https://aistudio.google.com/apikey)) — images\n    **and** video, widest range of shapes\n  - OpenAI ([get one here](https://platform.openai.com/api-keys)) — images\n  - Kie AI ([get one here](https://kie.ai/api-key)) — ~30 third-party models\n- Node.js 20.11 or later\n\n## Configuration\n\n`mediagen init` covers first-time setup. To change something later:\n\n```bash\nnpx -y mediagen config edit\n```\n\nA menu of every setting with its current value and where that value came from —\nprovider, model, key, output directory, quality preset, and what `mediagen\nmark` does by default. Each change is written as you make it.\n\nFor CI and scripts, where there is no terminal, `config set` takes the same\nsettings as arguments:\n\n```bash\necho \"$GEMINI_API_KEY\" | npx -y mediagen config set gemini --stdin\nnpx -y mediagen config set gemini-model gemini-3-pro-image\n```\n\n### Which provider gets used\n\nSet the order you prefer, most preferred first:\n\n```bash\nnpx -y mediagen config set provider-priority gemini,kie,openai\n```\n\nIt is a preference, not a whitelist. A request with no `--provider` goes to the\nfirst provider in the order that has a key **and** can do the job — so a\nmissing OpenAI key never stops something Gemini can do, and asking for video\nskips straight past the providers that do not make any. Naming `--provider`\noverrides all of it.\n\n`mediagen models` shows the resulting order, which providers are usable, and\nwhat a request would get:\n\n```\n1. Google Gemini (gemini)  [preferred, key from config file]\n  Would use: gemini-3.1-flash-image  (provider default)\n2. Kie AI (kie)  [key from config file]\n3. OpenAI (openai)  [preferred, no key]\n  No key configured, so requests to it fail. Fix: mediagen config set openai\n\nA request with no --provider uses gemini/gemini-3.1-flash-image.\n```\n\nWith `--json` it adds `wouldUse`, `usableProviders` and `providerPriority`.\nThat is what the skill has an agent read before generating, so it never picks\na model from a provider you have no key for.\n\nTo check what is configured and whether the keys still work:\n\n```bash\nnpx -y mediagen doctor\n```\n\n`doctor` reports, per provider, whether a key is configured, which layer it came\nfrom, and whether the provider accepts it — keeping _not configured_,\n_rejected_, _unreachable_ and _no cheap way to check_ distinct, because they\ncall for four different fixes.\n\n> [!WARNING]\n> There is deliberately no flag that takes an API key as an argument. Arguments\n> land in shell history and in the process list, where they outlive the command\n> that used them.\n\nSettings resolve from the environment first, then `.env` in the working\ndirectory, then the config file:\n\n| Variable                                          | Purpose                        |\n| ------------------------------------------------- | ------------------------------ |\n| `GEMINI_API_KEY`, `OPENAI_API_KEY`, `KIE_API_KEY` | credentials; at least one      |\n| `MEDIAGEN_PROVIDER_PRIORITY`                      | providers in preference order  |\n| `GEMINI_MODEL`, `OPENAI_MODEL`, `KIE_MODEL`       | default model per provider     |\n| `MEDIAGEN_OUTPUT_DIR`                             | where media is saved           |\n| `MEDIAGEN_QUALITY`                                | `fast`, `balanced`, `quality`  |\n| `MEDIAGEN_MARK`                                   | mark output by default         |\n| `MEDIAGEN_VISIBLE_LABEL`                          | add a visible label by default |\n\n> [!TIP]\n> A stale environment variable shadowing the key you just configured is the most\n> expensive failure this kind of tool has. `mediagen config list` marks every\n> shadowed value, so you can see it rather than guess.\n\n## Providers\n\n| Provider          | Images                         | Video | Editing | Key verification                 |\n| ----------------- | ------------------------------ | ----- | ------- | -------------------------------- |\n| **Google Gemini** | Nano Banana family, up to 4K   | yes   | yes     | live probe                       |\n| **OpenAI**        | gpt-image family, DALL·E       | —     | yes     | live probe                       |\n| **Kie AI**        | ~30 models: Flux, Imagen, Grok | —     | most    | no cheap probe; reported as such |\n\n> [!NOTE]\n> OpenAI takes pixel dimensions rather than aspect ratios and genuinely cannot\n> produce 16:9 — its widest image is 1536×1024, which is 3:2. Asking for 16:9 is\n> refused by name rather than quietly served as something else. The skill knows\n> this and routes wide shapes to Gemini.\n\nA model absent from the listings is still sent to the provider, so a newly\nreleased model works before mediagen knows about it. Kie's catalogue is\ngenerated from Kie's own documentation rather than maintained by hand.\n\n## Content marking\n\nThe EU AI Act splits disclosure into two duties, so `mediagen mark` has two\nindependent switches:\n\n| Flag              | Duty                      | What it does                                       |\n| ----------------- | ------------------------- | -------------------------------------------------- |\n| machine-readable  | make it findable by tools | writes IPTC/XMP `DigitalSourceType`, on by default |\n| `--visible-label` | disclose it to people     | composites the EU's official AI-content label      |\n\n**Generating never marks.** Marking is always a second command, run on the\nfile afterwards:\n\n```bash\nnpx -y mediagen image \"a wide banner\" --aspect-ratio 21:9 --size 2K --json\nnpx -y mediagen mark ./output/image-….jpg --visible-label --label-position top-left\n```\n\nThat is not ceremony. A visible label has to go where the subject is not, and\nonly the finished image can say where that is. The machine-readable marker is\nnot free either: adding metadata to a JPEG or WebP means decoding and\nre-encoding it, so marking costs a second lossy pass — worth paying\ndeliberately, not as a side effect of asking for an image. mediagen re-encodes\nat high quality to keep that cost small, but it cannot make it zero.\n\nTo have `mediagen mark` draw the visible label without being asked each time:\n\n```bash\nnpx -y mediagen config edit      # \"AI marking by default\"\n```\n\nA configured default is still overridable per run with `--no-mark` or\n`--no-visible-label`.\n\nThe visible label is the European Commission's own icon, published with the\nCode of Practice on Transparency of AI-generated Content and free to use\nwithout attribution. Two of its three variants are used: **AI GENERATED** by\ndefault, **AI MODIFIED** with `--modified`, for media a person made and a model\naltered. The light or dark version is picked from what is actually under the\ncorner it lands in, because a label nobody can read is not a disclosure.\n\nIt sits bottom-right by default. `--label-position` moves it to another corner,\nor `auto` puts it wherever the image has the least detail.\n\n> [!IMPORTANT]\n> A visible label is never written over its source. `mediagen mark photo.png\n--visible-label` produces `photo.labelled.png` and leaves the pixels of\n> `photo.png` exactly as they were, while writing the machine-readable marker\n> into it — so whichever of the two you publish carries the disclosure. A label\n> placed badly can be redone from an untouched original and from nothing else.\n> `--in-place` overwrites if you really mean to.\n\n## Using it without an agent\n\nThe skill is a wrapper around a CLI, and the CLI stands on its own.\n\n```bash\nnpx -y mediagen image \"a wide banner\" --aspect-ratio 21:9 --size 2K\nnpx -y mediagen image \"make the sky stormy\" --input ./photo.jpg\nnpx -y mediagen mark ./output/image-….jpg --visible-label\nnpx -y mediagen video \"a marble rolling down a wooden track\" --duration 6\nnpx -y mediagen models\n```\n\nInstall it globally if you use it often enough to want the shorter command:\n\n```bash\nnpm install -g mediagen\n```\n\n### Options\n\n| Option                   |                                     |\n| ------------------------ | ----------------------------------- |\n| `--provider <name>`      | `gemini`, `openai`, `kie`           |\n| `--model <id>`           | see `mediagen models`               |\n| `--input <path>`         | source media to edit or transform   |\n| `--aspect-ratio <ratio>` | `1:1`, `16:9`, `9:16`, …            |\n| `--size <size>`          | `1K`, `2K`, `4K`                    |\n| `--duration <seconds>`   | video only                          |\n| `--output-name <name>`   | the extension may select the format |\n| `--output-dir <dir>`     | where to save                       |\n| `--quality <preset>`     | `fast`, `balanced`, `quality`       |\n| `--json`                 | exactly one JSON object on stdout   |\n| `--verbose` `--quiet`    | diagnostics on stderr               |\n\n> [!TIP]\n> Without the skill, prompt writing is on you. mediagen sends the prompt exactly\n> as written — it does not expand or rewrite it. Decide subject, composition,\n> light, camera or medium, materials and atmosphere, and say what you want\n> rather than what you do not.\n\n### Scripting\n\nWith `--json`, stdout carries **exactly one JSON object and nothing else**.\nWithout it the saved path is the **last line**, and a failure writes nothing to\nstdout at all — so reading the last line can never hand you an error message\nwhere you expected a path.\n\n```json\n{\n  \"success\": true,\n  \"filePath\": \"./output/image-20260823T094107Z.png\",\n  \"kind\": \"image\",\n  \"provider\": \"gemini\",\n  \"model\": \"gemini-3.1-flash-image\",\n  \"mimeType\": \"image/png\"\n}\n```\n\n| Exit code | Meaning                          |\n| --------- | -------------------------------- |\n| `0`       | success                          |\n| `2`       | invalid input or usage           |\n| `3`       | configuration or credentials     |\n| `4`       | generation, network, or file I/O |\n\nA failure carries an `errorCode` — one of `VALIDATION_ERROR`, `CONFIG_ERROR`,\n`API_ERROR`, `NETWORK_ERROR`, `FILE_ERROR`, `CONTENT_BLOCKED` or `TIMEOUT` —\nand a `hint` naming a concrete next action.\n\n## Using it as an MCP server\n\nFor hosts that speak MCP rather than running skills. Same package, started with\n`mediagen mcp`, exposing `generate_media`, `list_models` and\n`check_configuration`.\n\n<details>\n<summary><strong>Claude Code</strong></summary>\n\n```bash\nclaude mcp add mediagen --env GEMINI_API_KEY=your-api-key-here -- npx -y mediagen mcp\n```\n\nThe `--` separates Claude's own flags from the command that starts the server.\nAdd `--scope project` or `--scope user` to change where the entry is written.\n\n</details>\n\n<details>\n<summary><strong>Claude Desktop</strong></summary>\n\nSettings → Developer → Edit Config, or edit directly:\n\n- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`\n- **Windows**: `%APPDATA%\\Claude\\claude_desktop_config.json`\n\n```json\n{\n  \"mcpServers\": {\n    \"mediagen\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"mediagen\", \"mcp\"],\n      \"env\": {\n        \"GEMINI_API_KEY\": \"your-api-key-here\"\n      }\n    }\n  }\n}\n```\n\nRestart Claude Desktop afterwards.\n\n</details>\n\n<details>\n<summary><strong>VS Code</strong></summary>\n\n```bash\ncode --add-mcp \"{\\\"name\\\":\\\"mediagen\\\",\\\"command\\\":\\\"npx\\\",\\\"args\\\":[\\\"-y\\\",\\\"mediagen\\\",\\\"mcp\\\"]}\"\n```\n\nOr create `.vscode/mcp.json` in your workspace — note that VS Code uses\n`servers`, not `mcpServers`:\n\n```json\n{\n  \"servers\": {\n    \"mediagen\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"mediagen\", \"mcp\"]\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><strong>Any other MCP client</strong></summary>\n\nCursor, Windsurf, Zed and most others take the same shape as Claude Desktop, in\ntheir own config file:\n\n| Field     | Value                       |\n| --------- | --------------------------- |\n| `command` | `npx`                       |\n| `args`    | `[\"-y\", \"mediagen\", \"mcp\"]` |\n| transport | stdio                       |\n\n</details>\n\n`env` can be omitted from any of these once `mediagen init` has run — the\nserver reads the same configuration the CLI does.\n\n## How it works\n\nOne pipeline, three frontends. The skill drives the CLI; the MCP server is a\nsecond adapter over the same core. Neither contains behaviour of its own, so a\ncapability cannot exist in one and be missing from the other.\n\n```\n      agent skill  ·  CLI  ·  MCP server\n                     ↓\n request → model resolution → capability check → provider client\n                     ↓\n                save to disk → result\n\n              mediagen mark → AI content marking\n```\n\nEach provider is one self-contained directory declaring what it supports.\nAdding one touches a single line outside its own folder. Provider manifests\ncarry no vendor SDK imports, so `doctor` and `config` never pay to load one.\n\n```\nsrc/\n├── types/          leaf types everything shares\n├── core/           pipeline, errors, capability checks, file handling\n├── config/         the three configuration layers, key verification\n├── providers/      one directory per provider, plus the registry\n│   ├── gemini/\n│   ├── openai/\n│   ├── kie/\n│   └── shared/     polling for asynchronous providers\n├── cli/            the command tree; output.ts owns stdout\n├── mcp/            the MCP server\n└── marking/        AI content marking\nskills/mediagen/    the agent skill\nscripts/            catalogue generation, version syncing\n```\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, how to add a\nprovider, and how releases are cut.\n",
  "bytes": 16945,
  "sha": "2d30db7d08a3055176635934dcece3e0d4d3df17265c33ace23e66a187e83a69",
  "repo_slug": "cripacx/mediagen",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_cripacx_mediagen_dee652fd/readme"
}